1108f7bbaSPaul Durrant /* 2108f7bbaSPaul Durrant * Copyright (c) 2018 Citrix Systems Inc. 3108f7bbaSPaul Durrant * 4108f7bbaSPaul Durrant * This work is licensed under the terms of the GNU GPL, version 2 or later. 5108f7bbaSPaul Durrant * See the COPYING file in the top-level directory. 6108f7bbaSPaul Durrant */ 7108f7bbaSPaul Durrant 8108f7bbaSPaul Durrant #include "qemu/osdep.h" 982a29e30SPaul Durrant #include "qemu/main-loop.h" 100b8fa32fSMarkus Armbruster #include "qemu/module.h" 1182a29e30SPaul Durrant #include "qemu/uuid.h" 12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 13108f7bbaSPaul Durrant #include "hw/sysbus.h" 14094a2239SPaul Durrant #include "hw/xen/xen.h" 15a783f8adSPaul Durrant #include "hw/xen/xen-backend.h" 16108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h" 17094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h" 18094a2239SPaul Durrant #include "monitor/monitor.h" 19108f7bbaSPaul Durrant #include "qapi/error.h" 20a783f8adSPaul Durrant #include "qapi/qmp/qdict.h" 21094a2239SPaul Durrant #include "sysemu/sysemu.h" 22108f7bbaSPaul Durrant #include "trace.h" 23108f7bbaSPaul Durrant 24094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev) 25094a2239SPaul Durrant { 26094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 27094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 28094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 29094a2239SPaul Durrant const char *backend = xendev_class->backend; 30094a2239SPaul Durrant 31094a2239SPaul Durrant if (!backend) { 32094a2239SPaul Durrant backend = type; 33094a2239SPaul Durrant } 34094a2239SPaul Durrant 35094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s", 36094a2239SPaul Durrant xenbus->backend_id, backend, xendev->frontend_id, 37094a2239SPaul Durrant xendev->name); 38094a2239SPaul Durrant } 39094a2239SPaul Durrant 40094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev) 41094a2239SPaul Durrant { 42094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 43094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 44094a2239SPaul Durrant const char *device = xendev_class->device; 45094a2239SPaul Durrant 46094a2239SPaul Durrant if (!device) { 47094a2239SPaul Durrant device = type; 48094a2239SPaul Durrant } 49094a2239SPaul Durrant 50094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/device/%s/%s", 51094a2239SPaul Durrant xendev->frontend_id, device, xendev->name); 52094a2239SPaul Durrant } 53094a2239SPaul Durrant 54b6af8926SPaul Durrant static void xen_device_unplug(XenDevice *xendev, Error **errp) 55b6af8926SPaul Durrant { 56b6af8926SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 57b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 58b6af8926SPaul Durrant Error *local_err = NULL; 59b6af8926SPaul Durrant xs_transaction_t tid; 60b6af8926SPaul Durrant 61b6af8926SPaul Durrant trace_xen_device_unplug(type, xendev->name); 62b6af8926SPaul Durrant 63b6af8926SPaul Durrant /* Mimic the way the Xen toolstack does an unplug */ 64b6af8926SPaul Durrant again: 65b6af8926SPaul Durrant tid = xs_transaction_start(xenbus->xsh); 66b6af8926SPaul Durrant if (tid == XBT_NULL) { 67b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_start"); 68b6af8926SPaul Durrant return; 69b6af8926SPaul Durrant } 70b6af8926SPaul Durrant 71b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online", 72b6af8926SPaul Durrant &local_err, "%u", 0); 73b6af8926SPaul Durrant if (local_err) { 74b6af8926SPaul Durrant goto abort; 75b6af8926SPaul Durrant } 76b6af8926SPaul Durrant 77b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state", 78b6af8926SPaul Durrant &local_err, "%u", XenbusStateClosing); 79b6af8926SPaul Durrant if (local_err) { 80b6af8926SPaul Durrant goto abort; 81b6af8926SPaul Durrant } 82b6af8926SPaul Durrant 83b6af8926SPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, false)) { 84b6af8926SPaul Durrant if (errno == EAGAIN) { 85b6af8926SPaul Durrant goto again; 86b6af8926SPaul Durrant } 87b6af8926SPaul Durrant 88b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 89b6af8926SPaul Durrant } 90b6af8926SPaul Durrant 91b6af8926SPaul Durrant return; 92b6af8926SPaul Durrant 93b6af8926SPaul Durrant abort: 94b6af8926SPaul Durrant /* 95b6af8926SPaul Durrant * We only abort if there is already a failure so ignore any error 96b6af8926SPaul Durrant * from ending the transaction. 97b6af8926SPaul Durrant */ 98b6af8926SPaul Durrant xs_transaction_end(xenbus->xsh, tid, true); 99b6af8926SPaul Durrant error_propagate(errp, local_err); 100b6af8926SPaul Durrant } 101b6af8926SPaul Durrant 102094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) 103094a2239SPaul Durrant { 104094a2239SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 105094a2239SPaul Durrant 106094a2239SPaul Durrant monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", 107094a2239SPaul Durrant indent, "", xendev->name, xendev->frontend_id); 108094a2239SPaul Durrant } 109094a2239SPaul Durrant 110094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev) 111094a2239SPaul Durrant { 112094a2239SPaul Durrant return xen_device_get_backend_path(XEN_DEVICE(dev)); 113094a2239SPaul Durrant } 114094a2239SPaul Durrant 11582a29e30SPaul Durrant struct XenWatch { 11682a29e30SPaul Durrant char *node, *key; 11782a29e30SPaul Durrant char *token; 11882a29e30SPaul Durrant XenWatchHandler handler; 11982a29e30SPaul Durrant void *opaque; 12082a29e30SPaul Durrant Notifier notifier; 12182a29e30SPaul Durrant }; 12282a29e30SPaul Durrant 12382a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data) 12482a29e30SPaul Durrant { 12582a29e30SPaul Durrant XenWatch *watch = container_of(n, XenWatch, notifier); 12682a29e30SPaul Durrant const char *token = data; 12782a29e30SPaul Durrant 12882a29e30SPaul Durrant if (!strcmp(watch->token, token)) { 12982a29e30SPaul Durrant watch->handler(watch->opaque); 13082a29e30SPaul Durrant } 13182a29e30SPaul Durrant } 13282a29e30SPaul Durrant 13382a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key, 13482a29e30SPaul Durrant XenWatchHandler handler, void *opaque) 13582a29e30SPaul Durrant { 13682a29e30SPaul Durrant XenWatch *watch = g_new0(XenWatch, 1); 13782a29e30SPaul Durrant QemuUUID uuid; 13882a29e30SPaul Durrant 13982a29e30SPaul Durrant qemu_uuid_generate(&uuid); 14082a29e30SPaul Durrant 14182a29e30SPaul Durrant watch->token = qemu_uuid_unparse_strdup(&uuid); 14282a29e30SPaul Durrant watch->node = g_strdup(node); 14382a29e30SPaul Durrant watch->key = g_strdup(key); 14482a29e30SPaul Durrant watch->handler = handler; 14582a29e30SPaul Durrant watch->opaque = opaque; 14682a29e30SPaul Durrant watch->notifier.notify = watch_notify; 14782a29e30SPaul Durrant 14882a29e30SPaul Durrant return watch; 14982a29e30SPaul Durrant } 15082a29e30SPaul Durrant 15182a29e30SPaul Durrant static void free_watch(XenWatch *watch) 15282a29e30SPaul Durrant { 15382a29e30SPaul Durrant g_free(watch->token); 15482a29e30SPaul Durrant g_free(watch->key); 15582a29e30SPaul Durrant g_free(watch->node); 15682a29e30SPaul Durrant 15782a29e30SPaul Durrant g_free(watch); 15882a29e30SPaul Durrant } 15982a29e30SPaul Durrant 160374752a2SPaul Durrant struct XenWatchList { 161374752a2SPaul Durrant struct xs_handle *xsh; 162374752a2SPaul Durrant NotifierList notifiers; 163374752a2SPaul Durrant }; 164374752a2SPaul Durrant 165374752a2SPaul Durrant static void watch_list_event(void *opaque) 166374752a2SPaul Durrant { 167374752a2SPaul Durrant XenWatchList *watch_list = opaque; 168374752a2SPaul Durrant char **v; 169374752a2SPaul Durrant const char *token; 170374752a2SPaul Durrant 171374752a2SPaul Durrant v = xs_check_watch(watch_list->xsh); 172374752a2SPaul Durrant if (!v) { 173374752a2SPaul Durrant return; 174374752a2SPaul Durrant } 175374752a2SPaul Durrant 176374752a2SPaul Durrant token = v[XS_WATCH_TOKEN]; 177374752a2SPaul Durrant 178374752a2SPaul Durrant notifier_list_notify(&watch_list->notifiers, (void *)token); 179374752a2SPaul Durrant 180374752a2SPaul Durrant free(v); 181374752a2SPaul Durrant } 182374752a2SPaul Durrant 183374752a2SPaul Durrant static XenWatchList *watch_list_create(struct xs_handle *xsh) 184374752a2SPaul Durrant { 185374752a2SPaul Durrant XenWatchList *watch_list = g_new0(XenWatchList, 1); 186374752a2SPaul Durrant 187374752a2SPaul Durrant g_assert(xsh); 188374752a2SPaul Durrant 189374752a2SPaul Durrant watch_list->xsh = xsh; 190374752a2SPaul Durrant notifier_list_init(&watch_list->notifiers); 191374752a2SPaul Durrant qemu_set_fd_handler(xs_fileno(watch_list->xsh), watch_list_event, NULL, 192374752a2SPaul Durrant watch_list); 193374752a2SPaul Durrant 194374752a2SPaul Durrant return watch_list; 195374752a2SPaul Durrant } 196374752a2SPaul Durrant 197374752a2SPaul Durrant static void watch_list_destroy(XenWatchList *watch_list) 198374752a2SPaul Durrant { 199374752a2SPaul Durrant g_assert(notifier_list_empty(&watch_list->notifiers)); 200374752a2SPaul Durrant qemu_set_fd_handler(xs_fileno(watch_list->xsh), NULL, NULL, NULL); 201374752a2SPaul Durrant g_free(watch_list); 202374752a2SPaul Durrant } 203374752a2SPaul Durrant 204374752a2SPaul Durrant static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node, 20582a29e30SPaul Durrant const char *key, XenWatchHandler handler, 20682a29e30SPaul Durrant void *opaque, Error **errp) 20782a29e30SPaul Durrant { 20882a29e30SPaul Durrant XenWatch *watch = new_watch(node, key, handler, opaque); 20982a29e30SPaul Durrant Error *local_err = NULL; 21082a29e30SPaul Durrant 211374752a2SPaul Durrant notifier_list_add(&watch_list->notifiers, &watch->notifier); 21282a29e30SPaul Durrant 213374752a2SPaul Durrant xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err); 21482a29e30SPaul Durrant if (local_err) { 21582a29e30SPaul Durrant error_propagate(errp, local_err); 21682a29e30SPaul Durrant 21782a29e30SPaul Durrant notifier_remove(&watch->notifier); 21882a29e30SPaul Durrant free_watch(watch); 21982a29e30SPaul Durrant 22082a29e30SPaul Durrant return NULL; 22182a29e30SPaul Durrant } 22282a29e30SPaul Durrant 22382a29e30SPaul Durrant return watch; 22482a29e30SPaul Durrant } 22582a29e30SPaul Durrant 226374752a2SPaul Durrant static void watch_list_remove(XenWatchList *watch_list, XenWatch *watch, 22782a29e30SPaul Durrant Error **errp) 22882a29e30SPaul Durrant { 229374752a2SPaul Durrant xs_node_unwatch(watch_list->xsh, watch->node, watch->key, watch->token, 23082a29e30SPaul Durrant errp); 23182a29e30SPaul Durrant 23282a29e30SPaul Durrant notifier_remove(&watch->notifier); 23382a29e30SPaul Durrant free_watch(watch); 23482a29e30SPaul Durrant } 23582a29e30SPaul Durrant 236374752a2SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, 237374752a2SPaul Durrant const char *key, XenWatchHandler handler, 238*d198b711SPaul Durrant Error **errp) 239374752a2SPaul Durrant { 240374752a2SPaul Durrant trace_xen_bus_add_watch(node, key); 241374752a2SPaul Durrant 242*d198b711SPaul Durrant return watch_list_add(xenbus->watch_list, node, key, handler, xenbus, 243374752a2SPaul Durrant errp); 244374752a2SPaul Durrant } 245374752a2SPaul Durrant 246374752a2SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, 247374752a2SPaul Durrant Error **errp) 248374752a2SPaul Durrant { 249374752a2SPaul Durrant trace_xen_bus_remove_watch(watch->node, watch->key); 250374752a2SPaul Durrant 251374752a2SPaul Durrant watch_list_remove(xenbus->watch_list, watch, errp); 252374752a2SPaul Durrant } 253374752a2SPaul Durrant 254a783f8adSPaul Durrant static void xen_bus_backend_create(XenBus *xenbus, const char *type, 255a783f8adSPaul Durrant const char *name, char *path, 256a783f8adSPaul Durrant Error **errp) 257a783f8adSPaul Durrant { 258a783f8adSPaul Durrant xs_transaction_t tid; 259a783f8adSPaul Durrant char **key; 260a783f8adSPaul Durrant QDict *opts; 261a783f8adSPaul Durrant unsigned int i, n; 262a783f8adSPaul Durrant Error *local_err = NULL; 263a783f8adSPaul Durrant 264a783f8adSPaul Durrant trace_xen_bus_backend_create(type, path); 265a783f8adSPaul Durrant 266a783f8adSPaul Durrant again: 267a783f8adSPaul Durrant tid = xs_transaction_start(xenbus->xsh); 268a783f8adSPaul Durrant if (tid == XBT_NULL) { 269a783f8adSPaul Durrant error_setg(errp, "failed xs_transaction_start"); 270a783f8adSPaul Durrant return; 271a783f8adSPaul Durrant } 272a783f8adSPaul Durrant 273a783f8adSPaul Durrant key = xs_directory(xenbus->xsh, tid, path, &n); 274a783f8adSPaul Durrant if (!key) { 275a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, true)) { 276a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 277a783f8adSPaul Durrant } 278a783f8adSPaul Durrant return; 279a783f8adSPaul Durrant } 280a783f8adSPaul Durrant 281a783f8adSPaul Durrant opts = qdict_new(); 282a783f8adSPaul Durrant for (i = 0; i < n; i++) { 283a783f8adSPaul Durrant char *val; 284a783f8adSPaul Durrant 285a783f8adSPaul Durrant /* 286a783f8adSPaul Durrant * Assume anything found in the xenstore backend area, other than 287a783f8adSPaul Durrant * the keys created for a generic XenDevice, are parameters 288a783f8adSPaul Durrant * to be used to configure the backend. 289a783f8adSPaul Durrant */ 290a783f8adSPaul Durrant if (!strcmp(key[i], "state") || 291a783f8adSPaul Durrant !strcmp(key[i], "online") || 292a783f8adSPaul Durrant !strcmp(key[i], "frontend") || 293a783f8adSPaul Durrant !strcmp(key[i], "frontend-id") || 294a783f8adSPaul Durrant !strcmp(key[i], "hotplug-status")) 295a783f8adSPaul Durrant continue; 296a783f8adSPaul Durrant 297a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms", 298a783f8adSPaul Durrant &val) == 1) { 299a783f8adSPaul Durrant qdict_put_str(opts, key[i], val); 300a783f8adSPaul Durrant free(val); 301a783f8adSPaul Durrant } 302a783f8adSPaul Durrant } 303a783f8adSPaul Durrant 304a783f8adSPaul Durrant free(key); 305a783f8adSPaul Durrant 306a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, false)) { 307a783f8adSPaul Durrant qobject_unref(opts); 308a783f8adSPaul Durrant 309a783f8adSPaul Durrant if (errno == EAGAIN) { 310a783f8adSPaul Durrant goto again; 311a783f8adSPaul Durrant } 312a783f8adSPaul Durrant 313a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 314a783f8adSPaul Durrant return; 315a783f8adSPaul Durrant } 316a783f8adSPaul Durrant 317a783f8adSPaul Durrant xen_backend_device_create(xenbus, type, name, opts, &local_err); 318a783f8adSPaul Durrant qobject_unref(opts); 319a783f8adSPaul Durrant 320a783f8adSPaul Durrant if (local_err) { 321a783f8adSPaul Durrant error_propagate_prepend(errp, local_err, 322a783f8adSPaul Durrant "failed to create '%s' device '%s': ", 323a783f8adSPaul Durrant type, name); 324a783f8adSPaul Durrant } 325a783f8adSPaul Durrant } 326a783f8adSPaul Durrant 327a783f8adSPaul Durrant static void xen_bus_type_enumerate(XenBus *xenbus, const char *type) 328a783f8adSPaul Durrant { 329a783f8adSPaul Durrant char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid); 330a783f8adSPaul Durrant char **backend; 331a783f8adSPaul Durrant unsigned int i, n; 332a783f8adSPaul Durrant 333a783f8adSPaul Durrant trace_xen_bus_type_enumerate(type); 334a783f8adSPaul Durrant 335a783f8adSPaul Durrant backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n); 336a783f8adSPaul Durrant if (!backend) { 337a783f8adSPaul Durrant goto out; 338a783f8adSPaul Durrant } 339a783f8adSPaul Durrant 340a783f8adSPaul Durrant for (i = 0; i < n; i++) { 341a783f8adSPaul Durrant char *backend_path = g_strdup_printf("%s/%s", domain_path, 342a783f8adSPaul Durrant backend[i]); 343a783f8adSPaul Durrant enum xenbus_state backend_state; 344a783f8adSPaul Durrant 345a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state", 346a783f8adSPaul Durrant NULL, "%u", &backend_state) != 1) 347a783f8adSPaul Durrant backend_state = XenbusStateUnknown; 348a783f8adSPaul Durrant 349a783f8adSPaul Durrant if (backend_state == XenbusStateInitialising) { 350a783f8adSPaul Durrant Error *local_err = NULL; 351a783f8adSPaul Durrant 352a783f8adSPaul Durrant xen_bus_backend_create(xenbus, type, backend[i], backend_path, 353a783f8adSPaul Durrant &local_err); 354a783f8adSPaul Durrant if (local_err) { 355a783f8adSPaul Durrant error_report_err(local_err); 356a783f8adSPaul Durrant } 357a783f8adSPaul Durrant } 358a783f8adSPaul Durrant 359a783f8adSPaul Durrant g_free(backend_path); 360a783f8adSPaul Durrant } 361a783f8adSPaul Durrant 362a783f8adSPaul Durrant free(backend); 363a783f8adSPaul Durrant 364a783f8adSPaul Durrant out: 365a783f8adSPaul Durrant g_free(domain_path); 366a783f8adSPaul Durrant } 367a783f8adSPaul Durrant 368a783f8adSPaul Durrant static void xen_bus_enumerate(void *opaque) 369a783f8adSPaul Durrant { 370a783f8adSPaul Durrant XenBus *xenbus = opaque; 371a783f8adSPaul Durrant char **type; 372a783f8adSPaul Durrant unsigned int i, n; 373a783f8adSPaul Durrant 374a783f8adSPaul Durrant trace_xen_bus_enumerate(); 375a783f8adSPaul Durrant 376a783f8adSPaul Durrant type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); 377a783f8adSPaul Durrant if (!type) { 378a783f8adSPaul Durrant return; 379a783f8adSPaul Durrant } 380a783f8adSPaul Durrant 381a783f8adSPaul Durrant for (i = 0; i < n; i++) { 382a783f8adSPaul Durrant xen_bus_type_enumerate(xenbus, type[i]); 383a783f8adSPaul Durrant } 384a783f8adSPaul Durrant 385a783f8adSPaul Durrant free(type); 386a783f8adSPaul Durrant } 387a783f8adSPaul Durrant 388108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp) 389108f7bbaSPaul Durrant { 390094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 391094a2239SPaul Durrant 392108f7bbaSPaul Durrant trace_xen_bus_unrealize(); 393094a2239SPaul Durrant 394a783f8adSPaul Durrant if (xenbus->backend_watch) { 395a783f8adSPaul Durrant xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL); 396a783f8adSPaul Durrant xenbus->backend_watch = NULL; 397a783f8adSPaul Durrant } 398a783f8adSPaul Durrant 399374752a2SPaul Durrant if (xenbus->watch_list) { 400374752a2SPaul Durrant watch_list_destroy(xenbus->watch_list); 401374752a2SPaul Durrant xenbus->watch_list = NULL; 402094a2239SPaul Durrant } 403094a2239SPaul Durrant 404374752a2SPaul Durrant if (xenbus->xsh) { 405094a2239SPaul Durrant xs_close(xenbus->xsh); 406108f7bbaSPaul Durrant } 40782a29e30SPaul Durrant } 40882a29e30SPaul Durrant 409108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp) 410108f7bbaSPaul Durrant { 411094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 412094a2239SPaul Durrant unsigned int domid; 413a783f8adSPaul Durrant Error *local_err = NULL; 414094a2239SPaul Durrant 415108f7bbaSPaul Durrant trace_xen_bus_realize(); 416094a2239SPaul Durrant 417094a2239SPaul Durrant xenbus->xsh = xs_open(0); 418094a2239SPaul Durrant if (!xenbus->xsh) { 419094a2239SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 420094a2239SPaul Durrant goto fail; 421094a2239SPaul Durrant } 422094a2239SPaul Durrant 423094a2239SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */ 424094a2239SPaul Durrant "domid", NULL, "%u", &domid) == 1) { 425094a2239SPaul Durrant xenbus->backend_id = domid; 426094a2239SPaul Durrant } else { 427094a2239SPaul Durrant xenbus->backend_id = 0; /* Assume lack of node means dom0 */ 428094a2239SPaul Durrant } 429094a2239SPaul Durrant 430374752a2SPaul Durrant xenbus->watch_list = watch_list_create(xenbus->xsh); 431a783f8adSPaul Durrant 432a783f8adSPaul Durrant module_call_init(MODULE_INIT_XEN_BACKEND); 433a783f8adSPaul Durrant 434a783f8adSPaul Durrant xenbus->backend_watch = 435a783f8adSPaul Durrant xen_bus_add_watch(xenbus, "", /* domain root node */ 436*d198b711SPaul Durrant "backend", xen_bus_enumerate, &local_err); 437a783f8adSPaul Durrant if (local_err) { 438a783f8adSPaul Durrant /* This need not be treated as a hard error so don't propagate */ 439a783f8adSPaul Durrant error_reportf_err(local_err, 440a783f8adSPaul Durrant "failed to set up enumeration watch: "); 441a783f8adSPaul Durrant } 442a783f8adSPaul Durrant 443094a2239SPaul Durrant return; 444094a2239SPaul Durrant 445094a2239SPaul Durrant fail: 446094a2239SPaul Durrant xen_bus_unrealize(bus, &error_abort); 447108f7bbaSPaul Durrant } 448108f7bbaSPaul Durrant 449b6af8926SPaul Durrant static void xen_bus_unplug_request(HotplugHandler *hotplug, 450b6af8926SPaul Durrant DeviceState *dev, 451b6af8926SPaul Durrant Error **errp) 452b6af8926SPaul Durrant { 453b6af8926SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 454b6af8926SPaul Durrant 455b6af8926SPaul Durrant xen_device_unplug(xendev, errp); 456b6af8926SPaul Durrant } 457b6af8926SPaul Durrant 458108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data) 459108f7bbaSPaul Durrant { 460108f7bbaSPaul Durrant BusClass *bus_class = BUS_CLASS(class); 461b6af8926SPaul Durrant HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); 462108f7bbaSPaul Durrant 463094a2239SPaul Durrant bus_class->print_dev = xen_bus_print_dev; 464094a2239SPaul Durrant bus_class->get_dev_path = xen_bus_get_dev_path; 465108f7bbaSPaul Durrant bus_class->realize = xen_bus_realize; 466108f7bbaSPaul Durrant bus_class->unrealize = xen_bus_unrealize; 467b6af8926SPaul Durrant 468b6af8926SPaul Durrant hotplug_class->unplug_request = xen_bus_unplug_request; 469108f7bbaSPaul Durrant } 470108f7bbaSPaul Durrant 471108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = { 472108f7bbaSPaul Durrant .name = TYPE_XEN_BUS, 473108f7bbaSPaul Durrant .parent = TYPE_BUS, 474108f7bbaSPaul Durrant .instance_size = sizeof(XenBus), 475108f7bbaSPaul Durrant .class_size = sizeof(XenBusClass), 476108f7bbaSPaul Durrant .class_init = xen_bus_class_init, 477108f7bbaSPaul Durrant .interfaces = (InterfaceInfo[]) { 478108f7bbaSPaul Durrant { TYPE_HOTPLUG_HANDLER }, 479108f7bbaSPaul Durrant { } 480108f7bbaSPaul Durrant }, 481108f7bbaSPaul Durrant }; 482108f7bbaSPaul Durrant 483b6af8926SPaul Durrant void xen_device_backend_printf(XenDevice *xendev, const char *key, 484094a2239SPaul Durrant const char *fmt, ...) 485094a2239SPaul Durrant { 486094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 487094a2239SPaul Durrant Error *local_err = NULL; 488094a2239SPaul Durrant va_list ap; 489094a2239SPaul Durrant 490094a2239SPaul Durrant g_assert(xenbus->xsh); 491094a2239SPaul Durrant 492094a2239SPaul Durrant va_start(ap, fmt); 493094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 494094a2239SPaul Durrant &local_err, fmt, ap); 495094a2239SPaul Durrant va_end(ap); 496094a2239SPaul Durrant 497094a2239SPaul Durrant if (local_err) { 498094a2239SPaul Durrant error_report_err(local_err); 499094a2239SPaul Durrant } 500094a2239SPaul Durrant } 501094a2239SPaul Durrant 50282a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key, 50382a29e30SPaul Durrant const char *fmt, ...) 50482a29e30SPaul Durrant { 50582a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 50682a29e30SPaul Durrant va_list ap; 50782a29e30SPaul Durrant int rc; 50882a29e30SPaul Durrant 50982a29e30SPaul Durrant g_assert(xenbus->xsh); 51082a29e30SPaul Durrant 51182a29e30SPaul Durrant va_start(ap, fmt); 51282a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 51382a29e30SPaul Durrant NULL, fmt, ap); 51482a29e30SPaul Durrant va_end(ap); 51582a29e30SPaul Durrant 51682a29e30SPaul Durrant return rc; 51782a29e30SPaul Durrant } 51882a29e30SPaul Durrant 51982a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev, 520094a2239SPaul Durrant enum xenbus_state state) 521094a2239SPaul Durrant { 522094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 523094a2239SPaul Durrant 524094a2239SPaul Durrant if (xendev->backend_state == state) { 525094a2239SPaul Durrant return; 526094a2239SPaul Durrant } 527094a2239SPaul Durrant 528094a2239SPaul Durrant trace_xen_device_backend_state(type, xendev->name, 529094a2239SPaul Durrant xs_strstate(state)); 530094a2239SPaul Durrant 531094a2239SPaul Durrant xendev->backend_state = state; 532094a2239SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state); 533094a2239SPaul Durrant } 534094a2239SPaul Durrant 53582a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) 53682a29e30SPaul Durrant { 53782a29e30SPaul Durrant return xendev->backend_state; 53882a29e30SPaul Durrant } 53982a29e30SPaul Durrant 540b6af8926SPaul Durrant static void xen_device_backend_set_online(XenDevice *xendev, bool online) 541b6af8926SPaul Durrant { 542b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 543b6af8926SPaul Durrant 544b6af8926SPaul Durrant if (xendev->backend_online == online) { 545b6af8926SPaul Durrant return; 546b6af8926SPaul Durrant } 547b6af8926SPaul Durrant 548b6af8926SPaul Durrant trace_xen_device_backend_online(type, xendev->name, online); 549b6af8926SPaul Durrant 550b6af8926SPaul Durrant xendev->backend_online = online; 551b6af8926SPaul Durrant xen_device_backend_printf(xendev, "online", "%u", online); 552b6af8926SPaul Durrant } 553b6af8926SPaul Durrant 554cb323146SAnthony PERARD /* 555cb323146SAnthony PERARD * Tell from the state whether the frontend is likely alive, 556cb323146SAnthony PERARD * i.e. it will react to a change of state of the backend. 557cb323146SAnthony PERARD */ 558cb323146SAnthony PERARD static bool xen_device_state_is_active(enum xenbus_state state) 559cb323146SAnthony PERARD { 560cb323146SAnthony PERARD switch (state) { 561cb323146SAnthony PERARD case XenbusStateInitWait: 562cb323146SAnthony PERARD case XenbusStateInitialised: 563cb323146SAnthony PERARD case XenbusStateConnected: 564cb323146SAnthony PERARD case XenbusStateClosing: 565cb323146SAnthony PERARD return true; 566cb323146SAnthony PERARD default: 567cb323146SAnthony PERARD return false; 568cb323146SAnthony PERARD } 569cb323146SAnthony PERARD } 570cb323146SAnthony PERARD 571b6af8926SPaul Durrant static void xen_device_backend_changed(void *opaque) 572b6af8926SPaul Durrant { 573b6af8926SPaul Durrant XenDevice *xendev = opaque; 574b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 575b6af8926SPaul Durrant enum xenbus_state state; 576b6af8926SPaul Durrant unsigned int online; 577b6af8926SPaul Durrant 578b6af8926SPaul Durrant trace_xen_device_backend_changed(type, xendev->name); 579b6af8926SPaul Durrant 580b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) { 581b6af8926SPaul Durrant state = XenbusStateUnknown; 582b6af8926SPaul Durrant } 583b6af8926SPaul Durrant 584b6af8926SPaul Durrant xen_device_backend_set_state(xendev, state); 585b6af8926SPaul Durrant 586b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { 587b6af8926SPaul Durrant online = 0; 588b6af8926SPaul Durrant } 589b6af8926SPaul Durrant 590b6af8926SPaul Durrant xen_device_backend_set_online(xendev, !!online); 591b6af8926SPaul Durrant 592b6af8926SPaul Durrant /* 593b6af8926SPaul Durrant * If the toolstack (or unplug request callback) has set the backend 594cb323146SAnthony PERARD * state to Closing, but there is no active frontend then set the 595cb323146SAnthony PERARD * backend state to Closed. 596b6af8926SPaul Durrant */ 597b6af8926SPaul Durrant if (xendev->backend_state == XenbusStateClosing && 598df6180bbSPaul Durrant !xen_device_state_is_active(xendev->frontend_state)) { 599b6af8926SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateClosed); 600b6af8926SPaul Durrant } 601b6af8926SPaul Durrant 602b6af8926SPaul Durrant /* 60367bc8e00SPaul Durrant * If a backend is still 'online' then we should leave it alone but, 60467bc8e00SPaul Durrant * if a backend is not 'online', then the device should be destroyed 60567bc8e00SPaul Durrant * once the state is Closed. 606b6af8926SPaul Durrant */ 60767bc8e00SPaul Durrant if (!xendev->backend_online && 608b6af8926SPaul Durrant (xendev->backend_state == XenbusStateClosed || 609b6af8926SPaul Durrant xendev->backend_state == XenbusStateInitialising || 610b6af8926SPaul Durrant xendev->backend_state == XenbusStateInitWait || 611b6af8926SPaul Durrant xendev->backend_state == XenbusStateUnknown)) { 612a783f8adSPaul Durrant Error *local_err = NULL; 613a783f8adSPaul Durrant 614a783f8adSPaul Durrant if (!xen_backend_try_device_destroy(xendev, &local_err)) { 615b6af8926SPaul Durrant object_unparent(OBJECT(xendev)); 616b6af8926SPaul Durrant } 617a783f8adSPaul Durrant 618a783f8adSPaul Durrant if (local_err) { 619a783f8adSPaul Durrant error_report_err(local_err); 620a783f8adSPaul Durrant } 621a783f8adSPaul Durrant } 622b6af8926SPaul Durrant } 623b6af8926SPaul Durrant 624*d198b711SPaul Durrant static XenWatch *xen_device_add_watch(XenDevice *xendev, const char *node, 625*d198b711SPaul Durrant const char *key, 626*d198b711SPaul Durrant XenWatchHandler handler, 627*d198b711SPaul Durrant Error **errp) 628*d198b711SPaul Durrant { 629*d198b711SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 630*d198b711SPaul Durrant 631*d198b711SPaul Durrant trace_xen_device_add_watch(type, xendev->name, node, key); 632*d198b711SPaul Durrant 633*d198b711SPaul Durrant return watch_list_add(xendev->watch_list, node, key, handler, xendev, 634*d198b711SPaul Durrant errp); 635*d198b711SPaul Durrant } 636*d198b711SPaul Durrant 637*d198b711SPaul Durrant static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch, 638*d198b711SPaul Durrant Error **errp) 639*d198b711SPaul Durrant { 640*d198b711SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 641*d198b711SPaul Durrant 642*d198b711SPaul Durrant trace_xen_device_remove_watch(type, xendev->name, watch->node, 643*d198b711SPaul Durrant watch->key); 644*d198b711SPaul Durrant 645*d198b711SPaul Durrant watch_list_remove(xendev->watch_list, watch, errp); 646*d198b711SPaul Durrant } 647*d198b711SPaul Durrant 648*d198b711SPaul Durrant 649094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp) 650094a2239SPaul Durrant { 651094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 652094a2239SPaul Durrant struct xs_permissions perms[2]; 653094a2239SPaul Durrant Error *local_err = NULL; 654094a2239SPaul Durrant 655094a2239SPaul Durrant xendev->backend_path = xen_device_get_backend_path(xendev); 656094a2239SPaul Durrant 657094a2239SPaul Durrant perms[0].id = xenbus->backend_id; 658094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 659094a2239SPaul Durrant perms[1].id = xendev->frontend_id; 660094a2239SPaul Durrant perms[1].perms = XS_PERM_READ; 661094a2239SPaul Durrant 662094a2239SPaul Durrant g_assert(xenbus->xsh); 663094a2239SPaul Durrant 664094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, 665094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 666094a2239SPaul Durrant if (local_err) { 667094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 668094a2239SPaul Durrant "failed to create backend: "); 669b6af8926SPaul Durrant return; 670b6af8926SPaul Durrant } 671b6af8926SPaul Durrant 672b6af8926SPaul Durrant xendev->backend_state_watch = 673*d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->backend_path, 674b6af8926SPaul Durrant "state", xen_device_backend_changed, 675*d198b711SPaul Durrant &local_err); 676b6af8926SPaul Durrant if (local_err) { 677b6af8926SPaul Durrant error_propagate_prepend(errp, local_err, 678b6af8926SPaul Durrant "failed to watch backend state: "); 679b6af8926SPaul Durrant return; 680b6af8926SPaul Durrant } 681b6af8926SPaul Durrant 682b6af8926SPaul Durrant xendev->backend_online_watch = 683*d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->backend_path, 684b6af8926SPaul Durrant "online", xen_device_backend_changed, 685*d198b711SPaul Durrant &local_err); 686b6af8926SPaul Durrant if (local_err) { 687b6af8926SPaul Durrant error_propagate_prepend(errp, local_err, 688b6af8926SPaul Durrant "failed to watch backend online: "); 689b6af8926SPaul Durrant return; 690094a2239SPaul Durrant } 691094a2239SPaul Durrant } 692094a2239SPaul Durrant 693094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev) 694094a2239SPaul Durrant { 695094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 696094a2239SPaul Durrant Error *local_err = NULL; 697094a2239SPaul Durrant 698b6af8926SPaul Durrant if (xendev->backend_online_watch) { 699*d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->backend_online_watch, NULL); 700b6af8926SPaul Durrant xendev->backend_online_watch = NULL; 701b6af8926SPaul Durrant } 702b6af8926SPaul Durrant 703b6af8926SPaul Durrant if (xendev->backend_state_watch) { 704*d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->backend_state_watch, NULL); 705b6af8926SPaul Durrant xendev->backend_state_watch = NULL; 706b6af8926SPaul Durrant } 707b6af8926SPaul Durrant 708094a2239SPaul Durrant if (!xendev->backend_path) { 709094a2239SPaul Durrant return; 710094a2239SPaul Durrant } 711094a2239SPaul Durrant 712094a2239SPaul Durrant g_assert(xenbus->xsh); 713094a2239SPaul Durrant 714094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path, 715094a2239SPaul Durrant &local_err); 716094a2239SPaul Durrant g_free(xendev->backend_path); 717094a2239SPaul Durrant xendev->backend_path = NULL; 718094a2239SPaul Durrant 719094a2239SPaul Durrant if (local_err) { 720094a2239SPaul Durrant error_report_err(local_err); 721094a2239SPaul Durrant } 722094a2239SPaul Durrant } 723094a2239SPaul Durrant 724b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key, 725094a2239SPaul Durrant const char *fmt, ...) 726094a2239SPaul Durrant { 727094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 728094a2239SPaul Durrant Error *local_err = NULL; 729094a2239SPaul Durrant va_list ap; 730094a2239SPaul Durrant 731094a2239SPaul Durrant g_assert(xenbus->xsh); 732094a2239SPaul Durrant 733094a2239SPaul Durrant va_start(ap, fmt); 734094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 735094a2239SPaul Durrant &local_err, fmt, ap); 736094a2239SPaul Durrant va_end(ap); 737094a2239SPaul Durrant 738094a2239SPaul Durrant if (local_err) { 739094a2239SPaul Durrant error_report_err(local_err); 740094a2239SPaul Durrant } 741094a2239SPaul Durrant } 742094a2239SPaul Durrant 743b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key, 74482a29e30SPaul Durrant const char *fmt, ...) 74582a29e30SPaul Durrant { 74682a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 74782a29e30SPaul Durrant va_list ap; 74882a29e30SPaul Durrant int rc; 74982a29e30SPaul Durrant 75082a29e30SPaul Durrant g_assert(xenbus->xsh); 75182a29e30SPaul Durrant 75282a29e30SPaul Durrant va_start(ap, fmt); 75382a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 75482a29e30SPaul Durrant NULL, fmt, ap); 75582a29e30SPaul Durrant va_end(ap); 75682a29e30SPaul Durrant 75782a29e30SPaul Durrant return rc; 75882a29e30SPaul Durrant } 75982a29e30SPaul Durrant 760094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev, 761705be570SAnthony PERARD enum xenbus_state state, 762705be570SAnthony PERARD bool publish) 763094a2239SPaul Durrant { 764094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 765094a2239SPaul Durrant 766094a2239SPaul Durrant if (xendev->frontend_state == state) { 767094a2239SPaul Durrant return; 768094a2239SPaul Durrant } 769094a2239SPaul Durrant 770094a2239SPaul Durrant trace_xen_device_frontend_state(type, xendev->name, 771094a2239SPaul Durrant xs_strstate(state)); 772094a2239SPaul Durrant 773094a2239SPaul Durrant xendev->frontend_state = state; 774705be570SAnthony PERARD if (publish) { 775094a2239SPaul Durrant xen_device_frontend_printf(xendev, "state", "%u", state); 776094a2239SPaul Durrant } 777705be570SAnthony PERARD } 778094a2239SPaul Durrant 77982a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque) 78082a29e30SPaul Durrant { 78182a29e30SPaul Durrant XenDevice *xendev = opaque; 78282a29e30SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 78382a29e30SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 78482a29e30SPaul Durrant enum xenbus_state state; 78582a29e30SPaul Durrant 78682a29e30SPaul Durrant trace_xen_device_frontend_changed(type, xendev->name); 78782a29e30SPaul Durrant 78882a29e30SPaul Durrant if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) { 78982a29e30SPaul Durrant state = XenbusStateUnknown; 79082a29e30SPaul Durrant } 79182a29e30SPaul Durrant 792705be570SAnthony PERARD xen_device_frontend_set_state(xendev, state, false); 79382a29e30SPaul Durrant 79467bc8e00SPaul Durrant if (state == XenbusStateInitialising && 79567bc8e00SPaul Durrant xendev->backend_state == XenbusStateClosed && 79667bc8e00SPaul Durrant xendev->backend_online) { 79767bc8e00SPaul Durrant /* 79867bc8e00SPaul Durrant * The frontend is re-initializing so switch back to 79967bc8e00SPaul Durrant * InitWait. 80067bc8e00SPaul Durrant */ 80167bc8e00SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 80267bc8e00SPaul Durrant return; 80367bc8e00SPaul Durrant } 80467bc8e00SPaul Durrant 80582a29e30SPaul Durrant if (xendev_class->frontend_changed) { 80682a29e30SPaul Durrant Error *local_err = NULL; 80782a29e30SPaul Durrant 80882a29e30SPaul Durrant xendev_class->frontend_changed(xendev, state, &local_err); 80982a29e30SPaul Durrant 81082a29e30SPaul Durrant if (local_err) { 81182a29e30SPaul Durrant error_reportf_err(local_err, "frontend change error: "); 81282a29e30SPaul Durrant } 81382a29e30SPaul Durrant } 81482a29e30SPaul Durrant } 81582a29e30SPaul Durrant 816094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp) 817094a2239SPaul Durrant { 818094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 819094a2239SPaul Durrant struct xs_permissions perms[2]; 820094a2239SPaul Durrant Error *local_err = NULL; 821094a2239SPaul Durrant 822094a2239SPaul Durrant xendev->frontend_path = xen_device_get_frontend_path(xendev); 823094a2239SPaul Durrant 824094a2239SPaul Durrant perms[0].id = xendev->frontend_id; 825094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 826094a2239SPaul Durrant perms[1].id = xenbus->backend_id; 827094a2239SPaul Durrant perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; 828094a2239SPaul Durrant 829094a2239SPaul Durrant g_assert(xenbus->xsh); 830094a2239SPaul Durrant 831094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, 832094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 833094a2239SPaul Durrant if (local_err) { 834094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 835094a2239SPaul Durrant "failed to create frontend: "); 83682a29e30SPaul Durrant return; 83782a29e30SPaul Durrant } 83882a29e30SPaul Durrant 83982a29e30SPaul Durrant xendev->frontend_state_watch = 840*d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->frontend_path, "state", 841*d198b711SPaul Durrant xen_device_frontend_changed, &local_err); 84282a29e30SPaul Durrant if (local_err) { 84382a29e30SPaul Durrant error_propagate_prepend(errp, local_err, 84482a29e30SPaul Durrant "failed to watch frontend state: "); 845094a2239SPaul Durrant } 846094a2239SPaul Durrant } 847094a2239SPaul Durrant 848094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev) 849094a2239SPaul Durrant { 850094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 851094a2239SPaul Durrant Error *local_err = NULL; 852094a2239SPaul Durrant 85382a29e30SPaul Durrant if (xendev->frontend_state_watch) { 854*d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->frontend_state_watch, 855*d198b711SPaul Durrant NULL); 85682a29e30SPaul Durrant xendev->frontend_state_watch = NULL; 85782a29e30SPaul Durrant } 85882a29e30SPaul Durrant 859094a2239SPaul Durrant if (!xendev->frontend_path) { 860094a2239SPaul Durrant return; 861094a2239SPaul Durrant } 862094a2239SPaul Durrant 863094a2239SPaul Durrant g_assert(xenbus->xsh); 864094a2239SPaul Durrant 865094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path, 866094a2239SPaul Durrant &local_err); 867094a2239SPaul Durrant g_free(xendev->frontend_path); 868094a2239SPaul Durrant xendev->frontend_path = NULL; 869094a2239SPaul Durrant 870094a2239SPaul Durrant if (local_err) { 871094a2239SPaul Durrant error_report_err(local_err); 872094a2239SPaul Durrant } 873094a2239SPaul Durrant } 874094a2239SPaul Durrant 8754b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, 8764b34b5b1SPaul Durrant Error **errp) 8774b34b5b1SPaul Durrant { 8784b34b5b1SPaul Durrant if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) { 8794b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); 8804b34b5b1SPaul Durrant } 8814b34b5b1SPaul Durrant } 8824b34b5b1SPaul Durrant 8834b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, 8844b34b5b1SPaul Durrant unsigned int nr_refs, int prot, 8854b34b5b1SPaul Durrant Error **errp) 8864b34b5b1SPaul Durrant { 8874b34b5b1SPaul Durrant void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs, 8884b34b5b1SPaul Durrant xendev->frontend_id, refs, 8894b34b5b1SPaul Durrant prot); 8904b34b5b1SPaul Durrant 8914b34b5b1SPaul Durrant if (!map) { 8924b34b5b1SPaul Durrant error_setg_errno(errp, errno, 8934b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 8944b34b5b1SPaul Durrant } 8954b34b5b1SPaul Durrant 8964b34b5b1SPaul Durrant return map; 8974b34b5b1SPaul Durrant } 8984b34b5b1SPaul Durrant 8994b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, 9004b34b5b1SPaul Durrant unsigned int nr_refs, Error **errp) 9014b34b5b1SPaul Durrant { 9024b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_refs)) { 9034b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 9044b34b5b1SPaul Durrant } 9054b34b5b1SPaul Durrant } 9064b34b5b1SPaul Durrant 9074b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain, 9084b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 9094b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 9104b34b5b1SPaul Durrant { 9114b34b5b1SPaul Durrant uint32_t *refs = g_new(uint32_t, nr_segs); 9124b34b5b1SPaul Durrant int prot = to_domain ? PROT_WRITE : PROT_READ; 9134b34b5b1SPaul Durrant void *map; 9144b34b5b1SPaul Durrant unsigned int i; 9154b34b5b1SPaul Durrant 9164b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9174b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 9184b34b5b1SPaul Durrant 9194b34b5b1SPaul Durrant refs[i] = to_domain ? seg->dest.foreign.ref : 9204b34b5b1SPaul Durrant seg->source.foreign.ref; 9214b34b5b1SPaul Durrant } 9224b34b5b1SPaul Durrant 9234b34b5b1SPaul Durrant map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs, 9244b34b5b1SPaul Durrant xendev->frontend_id, refs, 9254b34b5b1SPaul Durrant prot); 9264b34b5b1SPaul Durrant if (!map) { 9274b34b5b1SPaul Durrant error_setg_errno(errp, errno, 9284b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 9294b34b5b1SPaul Durrant goto done; 9304b34b5b1SPaul Durrant } 9314b34b5b1SPaul Durrant 9324b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9334b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 9344b34b5b1SPaul Durrant void *page = map + (i * XC_PAGE_SIZE); 9354b34b5b1SPaul Durrant 9364b34b5b1SPaul Durrant if (to_domain) { 9374b34b5b1SPaul Durrant memcpy(page + seg->dest.foreign.offset, seg->source.virt, 9384b34b5b1SPaul Durrant seg->len); 9394b34b5b1SPaul Durrant } else { 9404b34b5b1SPaul Durrant memcpy(seg->dest.virt, page + seg->source.foreign.offset, 9414b34b5b1SPaul Durrant seg->len); 9424b34b5b1SPaul Durrant } 9434b34b5b1SPaul Durrant } 9444b34b5b1SPaul Durrant 9454b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_segs)) { 9464b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 9474b34b5b1SPaul Durrant } 9484b34b5b1SPaul Durrant 9494b34b5b1SPaul Durrant done: 9504b34b5b1SPaul Durrant g_free(refs); 9514b34b5b1SPaul Durrant } 9524b34b5b1SPaul Durrant 9534b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, 9544b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 9554b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 9564b34b5b1SPaul Durrant { 9574b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_segs; 9584b34b5b1SPaul Durrant unsigned int i; 9594b34b5b1SPaul Durrant 9604b34b5b1SPaul Durrant if (!xendev->feature_grant_copy) { 9614b34b5b1SPaul Durrant compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp); 9624b34b5b1SPaul Durrant return; 9634b34b5b1SPaul Durrant } 9644b34b5b1SPaul Durrant 9654b34b5b1SPaul Durrant xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); 9664b34b5b1SPaul Durrant 9674b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9684b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 9694b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 9704b34b5b1SPaul Durrant 9714b34b5b1SPaul Durrant if (to_domain) { 9724b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_dest_gref; 9734b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.domid = xendev->frontend_id; 9744b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; 9754b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; 9764b34b5b1SPaul Durrant xengnttab_seg->source.virt = seg->source.virt; 9774b34b5b1SPaul Durrant } else { 9784b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_source_gref; 9794b34b5b1SPaul Durrant xengnttab_seg->source.foreign.domid = xendev->frontend_id; 9804b34b5b1SPaul Durrant xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; 9814b34b5b1SPaul Durrant xengnttab_seg->source.foreign.offset = 9824b34b5b1SPaul Durrant seg->source.foreign.offset; 9834b34b5b1SPaul Durrant xengnttab_seg->dest.virt = seg->dest.virt; 9844b34b5b1SPaul Durrant } 9854b34b5b1SPaul Durrant 9864b34b5b1SPaul Durrant xengnttab_seg->len = seg->len; 9874b34b5b1SPaul Durrant } 9884b34b5b1SPaul Durrant 9894b34b5b1SPaul Durrant if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) { 9904b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); 9914b34b5b1SPaul Durrant goto done; 9924b34b5b1SPaul Durrant } 9934b34b5b1SPaul Durrant 9944b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9954b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 9964b34b5b1SPaul Durrant 9974b34b5b1SPaul Durrant if (xengnttab_seg->status != GNTST_okay) { 9984b34b5b1SPaul Durrant error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); 9994b34b5b1SPaul Durrant break; 10004b34b5b1SPaul Durrant } 10014b34b5b1SPaul Durrant } 10024b34b5b1SPaul Durrant 10034b34b5b1SPaul Durrant done: 10044b34b5b1SPaul Durrant g_free(xengnttab_segs); 10054b34b5b1SPaul Durrant } 10064b34b5b1SPaul Durrant 1007a3d669c8SPaul Durrant struct XenEventChannel { 1008c0b336eaSPaul Durrant QLIST_ENTRY(XenEventChannel) list; 100983361a8aSPaul Durrant AioContext *ctx; 1010c0b336eaSPaul Durrant xenevtchn_handle *xeh; 1011a3d669c8SPaul Durrant evtchn_port_t local_port; 1012a3d669c8SPaul Durrant XenEventHandler handler; 1013a3d669c8SPaul Durrant void *opaque; 1014a3d669c8SPaul Durrant }; 1015a3d669c8SPaul Durrant 1016345f42b4SPaul Durrant static bool xen_device_poll(void *opaque) 1017345f42b4SPaul Durrant { 1018345f42b4SPaul Durrant XenEventChannel *channel = opaque; 1019345f42b4SPaul Durrant 1020345f42b4SPaul Durrant return channel->handler(channel->opaque); 1021345f42b4SPaul Durrant } 1022345f42b4SPaul Durrant 1023c0b336eaSPaul Durrant static void xen_device_event(void *opaque) 1024a3d669c8SPaul Durrant { 1025c0b336eaSPaul Durrant XenEventChannel *channel = opaque; 1026c0b336eaSPaul Durrant unsigned long port = xenevtchn_pending(channel->xeh); 1027a3d669c8SPaul Durrant 1028a3d669c8SPaul Durrant if (port == channel->local_port) { 1029345f42b4SPaul Durrant xen_device_poll(channel); 1030c0b336eaSPaul Durrant 1031c0b336eaSPaul Durrant xenevtchn_unmask(channel->xeh, port); 1032a3d669c8SPaul Durrant } 1033a3d669c8SPaul Durrant } 1034a3d669c8SPaul Durrant 1035a3d669c8SPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, 103683361a8aSPaul Durrant AioContext *ctx, 1037a3d669c8SPaul Durrant unsigned int port, 1038a3d669c8SPaul Durrant XenEventHandler handler, 1039a3d669c8SPaul Durrant void *opaque, Error **errp) 1040a3d669c8SPaul Durrant { 1041a3d669c8SPaul Durrant XenEventChannel *channel = g_new0(XenEventChannel, 1); 1042a3d669c8SPaul Durrant xenevtchn_port_or_error_t local_port; 1043a3d669c8SPaul Durrant 1044c0b336eaSPaul Durrant channel->xeh = xenevtchn_open(NULL, 0); 1045c0b336eaSPaul Durrant if (!channel->xeh) { 1046c0b336eaSPaul Durrant error_setg_errno(errp, errno, "failed xenevtchn_open"); 1047c0b336eaSPaul Durrant goto fail; 1048c0b336eaSPaul Durrant } 1049c0b336eaSPaul Durrant 1050c0b336eaSPaul Durrant local_port = xenevtchn_bind_interdomain(channel->xeh, 1051a3d669c8SPaul Durrant xendev->frontend_id, 1052a3d669c8SPaul Durrant port); 1053a3d669c8SPaul Durrant if (local_port < 0) { 1054a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed"); 1055c0b336eaSPaul Durrant goto fail; 1056a3d669c8SPaul Durrant } 1057a3d669c8SPaul Durrant 1058a3d669c8SPaul Durrant channel->local_port = local_port; 1059a3d669c8SPaul Durrant channel->handler = handler; 1060a3d669c8SPaul Durrant channel->opaque = opaque; 1061a3d669c8SPaul Durrant 106283361a8aSPaul Durrant channel->ctx = ctx; 106383361a8aSPaul Durrant aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, 1064345f42b4SPaul Durrant xen_device_event, NULL, xen_device_poll, channel); 1065c0b336eaSPaul Durrant 1066c0b336eaSPaul Durrant QLIST_INSERT_HEAD(&xendev->event_channels, channel, list); 1067a3d669c8SPaul Durrant 1068a3d669c8SPaul Durrant return channel; 1069c0b336eaSPaul Durrant 1070c0b336eaSPaul Durrant fail: 1071c0b336eaSPaul Durrant if (channel->xeh) { 1072c0b336eaSPaul Durrant xenevtchn_close(channel->xeh); 1073c0b336eaSPaul Durrant } 1074c0b336eaSPaul Durrant 1075c0b336eaSPaul Durrant g_free(channel); 1076c0b336eaSPaul Durrant 1077c0b336eaSPaul Durrant return NULL; 1078a3d669c8SPaul Durrant } 1079a3d669c8SPaul Durrant 1080a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev, 1081a3d669c8SPaul Durrant XenEventChannel *channel, 1082a3d669c8SPaul Durrant Error **errp) 1083a3d669c8SPaul Durrant { 1084a3d669c8SPaul Durrant if (!channel) { 1085a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1086a3d669c8SPaul Durrant return; 1087a3d669c8SPaul Durrant } 1088a3d669c8SPaul Durrant 1089c0b336eaSPaul Durrant if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) { 1090a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_notify failed"); 1091a3d669c8SPaul Durrant } 1092a3d669c8SPaul Durrant } 1093a3d669c8SPaul Durrant 1094a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev, 1095a3d669c8SPaul Durrant XenEventChannel *channel, 1096a3d669c8SPaul Durrant Error **errp) 1097a3d669c8SPaul Durrant { 1098a3d669c8SPaul Durrant if (!channel) { 1099a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1100a3d669c8SPaul Durrant return; 1101a3d669c8SPaul Durrant } 1102a3d669c8SPaul Durrant 1103c0b336eaSPaul Durrant QLIST_REMOVE(channel, list); 1104a3d669c8SPaul Durrant 110583361a8aSPaul Durrant aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, 110683361a8aSPaul Durrant NULL, NULL, NULL, NULL); 1107c0b336eaSPaul Durrant 1108c0b336eaSPaul Durrant if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) { 1109a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_unbind failed"); 1110a3d669c8SPaul Durrant } 1111a3d669c8SPaul Durrant 1112c0b336eaSPaul Durrant xenevtchn_close(channel->xeh); 1113a3d669c8SPaul Durrant g_free(channel); 1114a3d669c8SPaul Durrant } 1115a3d669c8SPaul Durrant 1116108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp) 1117108f7bbaSPaul Durrant { 1118108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1119108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1120108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1121c0b336eaSPaul Durrant XenEventChannel *channel, *next; 1122108f7bbaSPaul Durrant 1123094a2239SPaul Durrant if (!xendev->name) { 1124094a2239SPaul Durrant return; 1125094a2239SPaul Durrant } 1126094a2239SPaul Durrant 1127094a2239SPaul Durrant trace_xen_device_unrealize(type, xendev->name); 1128094a2239SPaul Durrant 1129094a2239SPaul Durrant if (xendev->exit.notify) { 1130094a2239SPaul Durrant qemu_remove_exit_notifier(&xendev->exit); 1131094a2239SPaul Durrant xendev->exit.notify = NULL; 1132094a2239SPaul Durrant } 1133108f7bbaSPaul Durrant 1134108f7bbaSPaul Durrant if (xendev_class->unrealize) { 1135108f7bbaSPaul Durrant xendev_class->unrealize(xendev, errp); 1136108f7bbaSPaul Durrant } 1137094a2239SPaul Durrant 1138c0b336eaSPaul Durrant /* Make sure all event channels are cleaned up */ 1139c0b336eaSPaul Durrant QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) { 1140c0b336eaSPaul Durrant xen_device_unbind_event_channel(xendev, channel, NULL); 1141c0b336eaSPaul Durrant } 1142c0b336eaSPaul Durrant 1143094a2239SPaul Durrant xen_device_frontend_destroy(xendev); 1144094a2239SPaul Durrant xen_device_backend_destroy(xendev); 1145094a2239SPaul Durrant 11464b34b5b1SPaul Durrant if (xendev->xgth) { 11474b34b5b1SPaul Durrant xengnttab_close(xendev->xgth); 11484b34b5b1SPaul Durrant xendev->xgth = NULL; 11494b34b5b1SPaul Durrant } 11504b34b5b1SPaul Durrant 1151*d198b711SPaul Durrant if (xendev->watch_list) { 1152*d198b711SPaul Durrant watch_list_destroy(xendev->watch_list); 1153*d198b711SPaul Durrant xendev->watch_list = NULL; 1154*d198b711SPaul Durrant } 1155*d198b711SPaul Durrant 1156*d198b711SPaul Durrant if (xendev->xsh) { 1157*d198b711SPaul Durrant xs_close(xendev->xsh); 1158*d198b711SPaul Durrant xendev->xsh = NULL; 1159*d198b711SPaul Durrant } 1160*d198b711SPaul Durrant 1161094a2239SPaul Durrant g_free(xendev->name); 1162094a2239SPaul Durrant xendev->name = NULL; 1163094a2239SPaul Durrant } 1164094a2239SPaul Durrant 1165094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data) 1166094a2239SPaul Durrant { 1167094a2239SPaul Durrant XenDevice *xendev = container_of(n, XenDevice, exit); 1168094a2239SPaul Durrant 1169094a2239SPaul Durrant xen_device_unrealize(DEVICE(xendev), &error_abort); 1170108f7bbaSPaul Durrant } 1171108f7bbaSPaul Durrant 1172108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp) 1173108f7bbaSPaul Durrant { 1174108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1175108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1176094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 1177108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1178108f7bbaSPaul Durrant Error *local_err = NULL; 1179108f7bbaSPaul Durrant 1180094a2239SPaul Durrant if (xendev->frontend_id == DOMID_INVALID) { 1181094a2239SPaul Durrant xendev->frontend_id = xen_domid; 1182094a2239SPaul Durrant } 1183094a2239SPaul Durrant 1184094a2239SPaul Durrant if (xendev->frontend_id >= DOMID_FIRST_RESERVED) { 1185094a2239SPaul Durrant error_setg(errp, "invalid frontend-id"); 1186094a2239SPaul Durrant goto unrealize; 1187094a2239SPaul Durrant } 1188094a2239SPaul Durrant 1189094a2239SPaul Durrant if (!xendev_class->get_name) { 1190094a2239SPaul Durrant error_setg(errp, "get_name method not implemented"); 1191094a2239SPaul Durrant goto unrealize; 1192094a2239SPaul Durrant } 1193094a2239SPaul Durrant 1194094a2239SPaul Durrant xendev->name = xendev_class->get_name(xendev, &local_err); 1195094a2239SPaul Durrant if (local_err) { 1196094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 1197094a2239SPaul Durrant "failed to get device name: "); 1198094a2239SPaul Durrant goto unrealize; 1199094a2239SPaul Durrant } 1200094a2239SPaul Durrant 1201094a2239SPaul Durrant trace_xen_device_realize(type, xendev->name); 1202094a2239SPaul Durrant 1203*d198b711SPaul Durrant xendev->xsh = xs_open(0); 1204*d198b711SPaul Durrant if (!xendev->xsh) { 1205*d198b711SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 1206*d198b711SPaul Durrant goto unrealize; 1207*d198b711SPaul Durrant } 1208*d198b711SPaul Durrant 1209*d198b711SPaul Durrant xendev->watch_list = watch_list_create(xendev->xsh); 1210*d198b711SPaul Durrant 12114b34b5b1SPaul Durrant xendev->xgth = xengnttab_open(NULL, 0); 12124b34b5b1SPaul Durrant if (!xendev->xgth) { 12134b34b5b1SPaul Durrant error_setg_errno(errp, errno, "failed xengnttab_open"); 12144b34b5b1SPaul Durrant goto unrealize; 12154b34b5b1SPaul Durrant } 12164b34b5b1SPaul Durrant 12174b34b5b1SPaul Durrant xendev->feature_grant_copy = 12184b34b5b1SPaul Durrant (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); 12194b34b5b1SPaul Durrant 1220094a2239SPaul Durrant xen_device_backend_create(xendev, &local_err); 1221094a2239SPaul Durrant if (local_err) { 1222094a2239SPaul Durrant error_propagate(errp, local_err); 1223094a2239SPaul Durrant goto unrealize; 1224094a2239SPaul Durrant } 1225094a2239SPaul Durrant 1226094a2239SPaul Durrant xen_device_frontend_create(xendev, &local_err); 1227094a2239SPaul Durrant if (local_err) { 1228094a2239SPaul Durrant error_propagate(errp, local_err); 1229094a2239SPaul Durrant goto unrealize; 1230094a2239SPaul Durrant } 1231108f7bbaSPaul Durrant 1232108f7bbaSPaul Durrant if (xendev_class->realize) { 1233108f7bbaSPaul Durrant xendev_class->realize(xendev, &local_err); 1234108f7bbaSPaul Durrant if (local_err) { 1235108f7bbaSPaul Durrant error_propagate(errp, local_err); 1236108f7bbaSPaul Durrant goto unrealize; 1237108f7bbaSPaul Durrant } 1238108f7bbaSPaul Durrant } 1239108f7bbaSPaul Durrant 1240094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend", "%s", 1241094a2239SPaul Durrant xendev->frontend_path); 1242094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend-id", "%u", 1243094a2239SPaul Durrant xendev->frontend_id); 1244094a2239SPaul Durrant xen_device_backend_printf(xendev, "hotplug-status", "connected"); 1245094a2239SPaul Durrant 1246b6af8926SPaul Durrant xen_device_backend_set_online(xendev, true); 1247094a2239SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 1248094a2239SPaul Durrant 1249094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend", "%s", 1250094a2239SPaul Durrant xendev->backend_path); 1251094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend-id", "%u", 1252094a2239SPaul Durrant xenbus->backend_id); 1253094a2239SPaul Durrant 1254705be570SAnthony PERARD xen_device_frontend_set_state(xendev, XenbusStateInitialising, true); 1255094a2239SPaul Durrant 1256094a2239SPaul Durrant xendev->exit.notify = xen_device_exit; 1257094a2239SPaul Durrant qemu_add_exit_notifier(&xendev->exit); 1258108f7bbaSPaul Durrant return; 1259108f7bbaSPaul Durrant 1260108f7bbaSPaul Durrant unrealize: 1261108f7bbaSPaul Durrant xen_device_unrealize(dev, &error_abort); 1262108f7bbaSPaul Durrant } 1263108f7bbaSPaul Durrant 1264094a2239SPaul Durrant static Property xen_device_props[] = { 1265094a2239SPaul Durrant DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id, 1266094a2239SPaul Durrant DOMID_INVALID), 1267094a2239SPaul Durrant DEFINE_PROP_END_OF_LIST() 1268094a2239SPaul Durrant }; 1269094a2239SPaul Durrant 1270108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data) 1271108f7bbaSPaul Durrant { 1272108f7bbaSPaul Durrant DeviceClass *dev_class = DEVICE_CLASS(class); 1273108f7bbaSPaul Durrant 1274108f7bbaSPaul Durrant dev_class->realize = xen_device_realize; 1275108f7bbaSPaul Durrant dev_class->unrealize = xen_device_unrealize; 1276094a2239SPaul Durrant dev_class->props = xen_device_props; 1277108f7bbaSPaul Durrant dev_class->bus_type = TYPE_XEN_BUS; 1278108f7bbaSPaul Durrant } 1279108f7bbaSPaul Durrant 1280108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = { 1281108f7bbaSPaul Durrant .name = TYPE_XEN_DEVICE, 1282108f7bbaSPaul Durrant .parent = TYPE_DEVICE, 1283108f7bbaSPaul Durrant .instance_size = sizeof(XenDevice), 1284108f7bbaSPaul Durrant .abstract = true, 1285108f7bbaSPaul Durrant .class_size = sizeof(XenDeviceClass), 1286108f7bbaSPaul Durrant .class_init = xen_device_class_init, 1287108f7bbaSPaul Durrant }; 1288108f7bbaSPaul Durrant 1289108f7bbaSPaul Durrant typedef struct XenBridge { 1290108f7bbaSPaul Durrant SysBusDevice busdev; 1291108f7bbaSPaul Durrant } XenBridge; 1292108f7bbaSPaul Durrant 1293108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge" 1294108f7bbaSPaul Durrant 1295108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = { 1296108f7bbaSPaul Durrant .name = TYPE_XEN_BRIDGE, 1297108f7bbaSPaul Durrant .parent = TYPE_SYS_BUS_DEVICE, 1298108f7bbaSPaul Durrant .instance_size = sizeof(XenBridge), 1299108f7bbaSPaul Durrant }; 1300108f7bbaSPaul Durrant 1301108f7bbaSPaul Durrant static void xen_register_types(void) 1302108f7bbaSPaul Durrant { 1303108f7bbaSPaul Durrant type_register_static(&xen_bridge_type_info); 1304108f7bbaSPaul Durrant type_register_static(&xen_bus_type_info); 1305108f7bbaSPaul Durrant type_register_static(&xen_device_type_info); 1306108f7bbaSPaul Durrant } 1307108f7bbaSPaul Durrant 1308108f7bbaSPaul Durrant type_init(xen_register_types) 1309108f7bbaSPaul Durrant 1310108f7bbaSPaul Durrant void xen_bus_init(void) 1311108f7bbaSPaul Durrant { 1312108f7bbaSPaul Durrant DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE); 1313108f7bbaSPaul Durrant BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); 1314108f7bbaSPaul Durrant 1315108f7bbaSPaul Durrant qdev_init_nofail(dev); 1316108f7bbaSPaul Durrant qbus_set_bus_hotplug_handler(bus, &error_abort); 1317108f7bbaSPaul Durrant } 1318