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 { 561de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 57b6af8926SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 58b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 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", 721de7096dSVladimir Sementsov-Ogievskiy errp, "%u", 0); 731de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 74b6af8926SPaul Durrant goto abort; 75b6af8926SPaul Durrant } 76b6af8926SPaul Durrant 77b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state", 781de7096dSVladimir Sementsov-Ogievskiy errp, "%u", XenbusStateClosing); 791de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 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 } 100b6af8926SPaul Durrant 101094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) 102094a2239SPaul Durrant { 103094a2239SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 104094a2239SPaul Durrant 105094a2239SPaul Durrant monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", 106094a2239SPaul Durrant indent, "", xendev->name, xendev->frontend_id); 107094a2239SPaul Durrant } 108094a2239SPaul Durrant 109094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev) 110094a2239SPaul Durrant { 111094a2239SPaul Durrant return xen_device_get_backend_path(XEN_DEVICE(dev)); 112094a2239SPaul Durrant } 113094a2239SPaul Durrant 11482a29e30SPaul Durrant struct XenWatch { 11582a29e30SPaul Durrant char *node, *key; 11682a29e30SPaul Durrant char *token; 11782a29e30SPaul Durrant XenWatchHandler handler; 11882a29e30SPaul Durrant void *opaque; 11982a29e30SPaul Durrant Notifier notifier; 12082a29e30SPaul Durrant }; 12182a29e30SPaul Durrant 12282a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data) 12382a29e30SPaul Durrant { 12482a29e30SPaul Durrant XenWatch *watch = container_of(n, XenWatch, notifier); 12582a29e30SPaul Durrant const char *token = data; 12682a29e30SPaul Durrant 12782a29e30SPaul Durrant if (!strcmp(watch->token, token)) { 12882a29e30SPaul Durrant watch->handler(watch->opaque); 12982a29e30SPaul Durrant } 13082a29e30SPaul Durrant } 13182a29e30SPaul Durrant 13282a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key, 13382a29e30SPaul Durrant XenWatchHandler handler, void *opaque) 13482a29e30SPaul Durrant { 13582a29e30SPaul Durrant XenWatch *watch = g_new0(XenWatch, 1); 13682a29e30SPaul Durrant QemuUUID uuid; 13782a29e30SPaul Durrant 13882a29e30SPaul Durrant qemu_uuid_generate(&uuid); 13982a29e30SPaul Durrant 14082a29e30SPaul Durrant watch->token = qemu_uuid_unparse_strdup(&uuid); 14182a29e30SPaul Durrant watch->node = g_strdup(node); 14282a29e30SPaul Durrant watch->key = g_strdup(key); 14382a29e30SPaul Durrant watch->handler = handler; 14482a29e30SPaul Durrant watch->opaque = opaque; 14582a29e30SPaul Durrant watch->notifier.notify = watch_notify; 14682a29e30SPaul Durrant 14782a29e30SPaul Durrant return watch; 14882a29e30SPaul Durrant } 14982a29e30SPaul Durrant 15082a29e30SPaul Durrant static void free_watch(XenWatch *watch) 15182a29e30SPaul Durrant { 15282a29e30SPaul Durrant g_free(watch->token); 15382a29e30SPaul Durrant g_free(watch->key); 15482a29e30SPaul Durrant g_free(watch->node); 15582a29e30SPaul Durrant 15682a29e30SPaul Durrant g_free(watch); 15782a29e30SPaul Durrant } 15882a29e30SPaul Durrant 159374752a2SPaul Durrant struct XenWatchList { 160374752a2SPaul Durrant struct xs_handle *xsh; 161374752a2SPaul Durrant NotifierList notifiers; 162374752a2SPaul Durrant }; 163374752a2SPaul Durrant 164374752a2SPaul Durrant static void watch_list_event(void *opaque) 165374752a2SPaul Durrant { 166374752a2SPaul Durrant XenWatchList *watch_list = opaque; 167374752a2SPaul Durrant char **v; 168374752a2SPaul Durrant const char *token; 169374752a2SPaul Durrant 170374752a2SPaul Durrant v = xs_check_watch(watch_list->xsh); 171374752a2SPaul Durrant if (!v) { 172374752a2SPaul Durrant return; 173374752a2SPaul Durrant } 174374752a2SPaul Durrant 175374752a2SPaul Durrant token = v[XS_WATCH_TOKEN]; 176374752a2SPaul Durrant 177374752a2SPaul Durrant notifier_list_notify(&watch_list->notifiers, (void *)token); 178374752a2SPaul Durrant 179374752a2SPaul Durrant free(v); 180374752a2SPaul Durrant } 181374752a2SPaul Durrant 182374752a2SPaul Durrant static XenWatchList *watch_list_create(struct xs_handle *xsh) 183374752a2SPaul Durrant { 184374752a2SPaul Durrant XenWatchList *watch_list = g_new0(XenWatchList, 1); 185374752a2SPaul Durrant 186374752a2SPaul Durrant g_assert(xsh); 187374752a2SPaul Durrant 188374752a2SPaul Durrant watch_list->xsh = xsh; 189374752a2SPaul Durrant notifier_list_init(&watch_list->notifiers); 190374752a2SPaul Durrant qemu_set_fd_handler(xs_fileno(watch_list->xsh), watch_list_event, NULL, 191374752a2SPaul Durrant watch_list); 192374752a2SPaul Durrant 193374752a2SPaul Durrant return watch_list; 194374752a2SPaul Durrant } 195374752a2SPaul Durrant 196374752a2SPaul Durrant static void watch_list_destroy(XenWatchList *watch_list) 197374752a2SPaul Durrant { 198374752a2SPaul Durrant g_assert(notifier_list_empty(&watch_list->notifiers)); 199374752a2SPaul Durrant qemu_set_fd_handler(xs_fileno(watch_list->xsh), NULL, NULL, NULL); 200374752a2SPaul Durrant g_free(watch_list); 201374752a2SPaul Durrant } 202374752a2SPaul Durrant 203374752a2SPaul Durrant static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node, 20482a29e30SPaul Durrant const char *key, XenWatchHandler handler, 20582a29e30SPaul Durrant void *opaque, Error **errp) 20682a29e30SPaul Durrant { 2071de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 20882a29e30SPaul Durrant XenWatch *watch = new_watch(node, key, handler, opaque); 20982a29e30SPaul Durrant 210374752a2SPaul Durrant notifier_list_add(&watch_list->notifiers, &watch->notifier); 21182a29e30SPaul Durrant 2121de7096dSVladimir Sementsov-Ogievskiy xs_node_watch(watch_list->xsh, node, key, watch->token, errp); 2131de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 21482a29e30SPaul Durrant notifier_remove(&watch->notifier); 21582a29e30SPaul Durrant free_watch(watch); 21682a29e30SPaul Durrant 21782a29e30SPaul Durrant return NULL; 21882a29e30SPaul Durrant } 21982a29e30SPaul Durrant 22082a29e30SPaul Durrant return watch; 22182a29e30SPaul Durrant } 22282a29e30SPaul Durrant 223374752a2SPaul Durrant static void watch_list_remove(XenWatchList *watch_list, XenWatch *watch, 22482a29e30SPaul Durrant Error **errp) 22582a29e30SPaul Durrant { 226374752a2SPaul Durrant xs_node_unwatch(watch_list->xsh, watch->node, watch->key, watch->token, 22782a29e30SPaul Durrant errp); 22882a29e30SPaul Durrant 22982a29e30SPaul Durrant notifier_remove(&watch->notifier); 23082a29e30SPaul Durrant free_watch(watch); 23182a29e30SPaul Durrant } 23282a29e30SPaul Durrant 233374752a2SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, 234374752a2SPaul Durrant const char *key, XenWatchHandler handler, 235d198b711SPaul Durrant Error **errp) 236374752a2SPaul Durrant { 237374752a2SPaul Durrant trace_xen_bus_add_watch(node, key); 238374752a2SPaul Durrant 239d198b711SPaul Durrant return watch_list_add(xenbus->watch_list, node, key, handler, xenbus, 240374752a2SPaul Durrant errp); 241374752a2SPaul Durrant } 242374752a2SPaul Durrant 243374752a2SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, 244374752a2SPaul Durrant Error **errp) 245374752a2SPaul Durrant { 246374752a2SPaul Durrant trace_xen_bus_remove_watch(watch->node, watch->key); 247374752a2SPaul Durrant 248374752a2SPaul Durrant watch_list_remove(xenbus->watch_list, watch, errp); 249374752a2SPaul Durrant } 250374752a2SPaul Durrant 251a783f8adSPaul Durrant static void xen_bus_backend_create(XenBus *xenbus, const char *type, 252a783f8adSPaul Durrant const char *name, char *path, 253a783f8adSPaul Durrant Error **errp) 254a783f8adSPaul Durrant { 2551de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 256a783f8adSPaul Durrant xs_transaction_t tid; 257a783f8adSPaul Durrant char **key; 258a783f8adSPaul Durrant QDict *opts; 259a783f8adSPaul Durrant unsigned int i, n; 260a783f8adSPaul Durrant 261a783f8adSPaul Durrant trace_xen_bus_backend_create(type, path); 262a783f8adSPaul Durrant 263a783f8adSPaul Durrant again: 264a783f8adSPaul Durrant tid = xs_transaction_start(xenbus->xsh); 265a783f8adSPaul Durrant if (tid == XBT_NULL) { 266a783f8adSPaul Durrant error_setg(errp, "failed xs_transaction_start"); 267a783f8adSPaul Durrant return; 268a783f8adSPaul Durrant } 269a783f8adSPaul Durrant 270a783f8adSPaul Durrant key = xs_directory(xenbus->xsh, tid, path, &n); 271a783f8adSPaul Durrant if (!key) { 272a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, true)) { 273a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 274a783f8adSPaul Durrant } 275a783f8adSPaul Durrant return; 276a783f8adSPaul Durrant } 277a783f8adSPaul Durrant 278a783f8adSPaul Durrant opts = qdict_new(); 279a783f8adSPaul Durrant for (i = 0; i < n; i++) { 280a783f8adSPaul Durrant char *val; 281a783f8adSPaul Durrant 282a783f8adSPaul Durrant /* 283a783f8adSPaul Durrant * Assume anything found in the xenstore backend area, other than 284a783f8adSPaul Durrant * the keys created for a generic XenDevice, are parameters 285a783f8adSPaul Durrant * to be used to configure the backend. 286a783f8adSPaul Durrant */ 287a783f8adSPaul Durrant if (!strcmp(key[i], "state") || 288a783f8adSPaul Durrant !strcmp(key[i], "online") || 289a783f8adSPaul Durrant !strcmp(key[i], "frontend") || 290a783f8adSPaul Durrant !strcmp(key[i], "frontend-id") || 291a783f8adSPaul Durrant !strcmp(key[i], "hotplug-status")) 292a783f8adSPaul Durrant continue; 293a783f8adSPaul Durrant 294a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms", 295a783f8adSPaul Durrant &val) == 1) { 296a783f8adSPaul Durrant qdict_put_str(opts, key[i], val); 297a783f8adSPaul Durrant free(val); 298a783f8adSPaul Durrant } 299a783f8adSPaul Durrant } 300a783f8adSPaul Durrant 301a783f8adSPaul Durrant free(key); 302a783f8adSPaul Durrant 303a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, false)) { 304a783f8adSPaul Durrant qobject_unref(opts); 305a783f8adSPaul Durrant 306a783f8adSPaul Durrant if (errno == EAGAIN) { 307a783f8adSPaul Durrant goto again; 308a783f8adSPaul Durrant } 309a783f8adSPaul Durrant 310a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 311a783f8adSPaul Durrant return; 312a783f8adSPaul Durrant } 313a783f8adSPaul Durrant 3141de7096dSVladimir Sementsov-Ogievskiy xen_backend_device_create(xenbus, type, name, opts, errp); 315a783f8adSPaul Durrant qobject_unref(opts); 316a783f8adSPaul Durrant 3171de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 3181de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create '%s' device '%s': ", type, name); 319a783f8adSPaul Durrant } 320a783f8adSPaul Durrant } 321a783f8adSPaul Durrant 322a783f8adSPaul Durrant static void xen_bus_type_enumerate(XenBus *xenbus, const char *type) 323a783f8adSPaul Durrant { 324a783f8adSPaul Durrant char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid); 325a783f8adSPaul Durrant char **backend; 326a783f8adSPaul Durrant unsigned int i, n; 327a783f8adSPaul Durrant 328a783f8adSPaul Durrant trace_xen_bus_type_enumerate(type); 329a783f8adSPaul Durrant 330a783f8adSPaul Durrant backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n); 331a783f8adSPaul Durrant if (!backend) { 332a783f8adSPaul Durrant goto out; 333a783f8adSPaul Durrant } 334a783f8adSPaul Durrant 335a783f8adSPaul Durrant for (i = 0; i < n; i++) { 336a783f8adSPaul Durrant char *backend_path = g_strdup_printf("%s/%s", domain_path, 337a783f8adSPaul Durrant backend[i]); 3383809f758SPaul Durrant enum xenbus_state state; 3393809f758SPaul Durrant unsigned int online; 340a783f8adSPaul Durrant 341a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state", 3423809f758SPaul Durrant NULL, "%u", &state) != 1) 3433809f758SPaul Durrant state = XenbusStateUnknown; 344a783f8adSPaul Durrant 3453809f758SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "online", 3463809f758SPaul Durrant NULL, "%u", &online) != 1) 3473809f758SPaul Durrant online = 0; 3483809f758SPaul Durrant 3493809f758SPaul Durrant if (online && 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 3683809f758SPaul Durrant static void xen_bus_enumerate(XenBus *xenbus) 369a783f8adSPaul Durrant { 370a783f8adSPaul Durrant char **type; 371a783f8adSPaul Durrant unsigned int i, n; 372a783f8adSPaul Durrant 373a783f8adSPaul Durrant trace_xen_bus_enumerate(); 374a783f8adSPaul Durrant 375a783f8adSPaul Durrant type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); 376a783f8adSPaul Durrant if (!type) { 377a783f8adSPaul Durrant return; 378a783f8adSPaul Durrant } 379a783f8adSPaul Durrant 380a783f8adSPaul Durrant for (i = 0; i < n; i++) { 381a783f8adSPaul Durrant xen_bus_type_enumerate(xenbus, type[i]); 382a783f8adSPaul Durrant } 383a783f8adSPaul Durrant 384a783f8adSPaul Durrant free(type); 385a783f8adSPaul Durrant } 386a783f8adSPaul Durrant 3873809f758SPaul Durrant static void xen_bus_device_cleanup(XenDevice *xendev) 3883809f758SPaul Durrant { 3893809f758SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 3903809f758SPaul Durrant Error *local_err = NULL; 3913809f758SPaul Durrant 3923809f758SPaul Durrant trace_xen_bus_device_cleanup(type, xendev->name); 3933809f758SPaul Durrant 3943809f758SPaul Durrant g_assert(!xendev->backend_online); 3953809f758SPaul Durrant 3963809f758SPaul Durrant if (!xen_backend_try_device_destroy(xendev, &local_err)) { 3973809f758SPaul Durrant object_unparent(OBJECT(xendev)); 3983809f758SPaul Durrant } 3993809f758SPaul Durrant 4003809f758SPaul Durrant if (local_err) { 4013809f758SPaul Durrant error_report_err(local_err); 4023809f758SPaul Durrant } 4033809f758SPaul Durrant } 4043809f758SPaul Durrant 4053809f758SPaul Durrant static void xen_bus_cleanup(XenBus *xenbus) 4063809f758SPaul Durrant { 4073809f758SPaul Durrant XenDevice *xendev, *next; 4083809f758SPaul Durrant 4093809f758SPaul Durrant trace_xen_bus_cleanup(); 4103809f758SPaul Durrant 4113809f758SPaul Durrant QLIST_FOREACH_SAFE(xendev, &xenbus->inactive_devices, list, next) { 4123809f758SPaul Durrant g_assert(xendev->inactive); 4133809f758SPaul Durrant QLIST_REMOVE(xendev, list); 4143809f758SPaul Durrant xen_bus_device_cleanup(xendev); 4153809f758SPaul Durrant } 4163809f758SPaul Durrant } 4173809f758SPaul Durrant 4183809f758SPaul Durrant static void xen_bus_backend_changed(void *opaque) 4193809f758SPaul Durrant { 4203809f758SPaul Durrant XenBus *xenbus = opaque; 4213809f758SPaul Durrant 4223809f758SPaul Durrant xen_bus_enumerate(xenbus); 4233809f758SPaul Durrant xen_bus_cleanup(xenbus); 4243809f758SPaul Durrant } 4253809f758SPaul Durrant 426b69c3c21SMarkus Armbruster static void xen_bus_unrealize(BusState *bus) 427108f7bbaSPaul Durrant { 428094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 429094a2239SPaul Durrant 430108f7bbaSPaul Durrant trace_xen_bus_unrealize(); 431094a2239SPaul Durrant 432a783f8adSPaul Durrant if (xenbus->backend_watch) { 433c4583c8cSPaul Durrant unsigned int i; 434c4583c8cSPaul Durrant 435c4583c8cSPaul Durrant for (i = 0; i < xenbus->backend_types; i++) { 436c4583c8cSPaul Durrant if (xenbus->backend_watch[i]) { 437c4583c8cSPaul Durrant xen_bus_remove_watch(xenbus, xenbus->backend_watch[i], NULL); 438c4583c8cSPaul Durrant } 439c4583c8cSPaul Durrant } 440c4583c8cSPaul Durrant 441c4583c8cSPaul Durrant g_free(xenbus->backend_watch); 442a783f8adSPaul Durrant xenbus->backend_watch = NULL; 443a783f8adSPaul Durrant } 444a783f8adSPaul Durrant 445374752a2SPaul Durrant if (xenbus->watch_list) { 446374752a2SPaul Durrant watch_list_destroy(xenbus->watch_list); 447374752a2SPaul Durrant xenbus->watch_list = NULL; 448094a2239SPaul Durrant } 449094a2239SPaul Durrant 450374752a2SPaul Durrant if (xenbus->xsh) { 451094a2239SPaul Durrant xs_close(xenbus->xsh); 452108f7bbaSPaul Durrant } 45382a29e30SPaul Durrant } 45482a29e30SPaul Durrant 455108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp) 456108f7bbaSPaul Durrant { 457c4583c8cSPaul Durrant char *key = g_strdup_printf("%u", xen_domid); 458094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 459094a2239SPaul Durrant unsigned int domid; 460c4583c8cSPaul Durrant const char **type; 461c4583c8cSPaul Durrant unsigned int i; 462a783f8adSPaul Durrant Error *local_err = NULL; 463094a2239SPaul Durrant 464108f7bbaSPaul Durrant trace_xen_bus_realize(); 465094a2239SPaul Durrant 466094a2239SPaul Durrant xenbus->xsh = xs_open(0); 467094a2239SPaul Durrant if (!xenbus->xsh) { 468094a2239SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 469094a2239SPaul Durrant goto fail; 470094a2239SPaul Durrant } 471094a2239SPaul Durrant 472094a2239SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */ 473094a2239SPaul Durrant "domid", NULL, "%u", &domid) == 1) { 474094a2239SPaul Durrant xenbus->backend_id = domid; 475094a2239SPaul Durrant } else { 476094a2239SPaul Durrant xenbus->backend_id = 0; /* Assume lack of node means dom0 */ 477094a2239SPaul Durrant } 478094a2239SPaul Durrant 479374752a2SPaul Durrant xenbus->watch_list = watch_list_create(xenbus->xsh); 480a783f8adSPaul Durrant 481a783f8adSPaul Durrant module_call_init(MODULE_INIT_XEN_BACKEND); 482a783f8adSPaul Durrant 483c4583c8cSPaul Durrant type = xen_backend_get_types(&xenbus->backend_types); 484c4583c8cSPaul Durrant xenbus->backend_watch = g_new(XenWatch *, xenbus->backend_types); 485c4583c8cSPaul Durrant 486c4583c8cSPaul Durrant for (i = 0; i < xenbus->backend_types; i++) { 487c4583c8cSPaul Durrant char *node = g_strdup_printf("backend/%s", type[i]); 488c4583c8cSPaul Durrant 489c4583c8cSPaul Durrant xenbus->backend_watch[i] = 490c4583c8cSPaul Durrant xen_bus_add_watch(xenbus, node, key, xen_bus_backend_changed, 491c4583c8cSPaul Durrant &local_err); 492a783f8adSPaul Durrant if (local_err) { 493a783f8adSPaul Durrant /* This need not be treated as a hard error so don't propagate */ 494a783f8adSPaul Durrant error_reportf_err(local_err, 495c4583c8cSPaul Durrant "failed to set up '%s' enumeration watch: ", 496c4583c8cSPaul Durrant type[i]); 497a783f8adSPaul Durrant } 498a783f8adSPaul Durrant 499c4583c8cSPaul Durrant g_free(node); 500c4583c8cSPaul Durrant } 501c4583c8cSPaul Durrant 502c4583c8cSPaul Durrant g_free(type); 503c4583c8cSPaul Durrant g_free(key); 504094a2239SPaul Durrant return; 505094a2239SPaul Durrant 506094a2239SPaul Durrant fail: 507b69c3c21SMarkus Armbruster xen_bus_unrealize(bus); 508c4583c8cSPaul Durrant g_free(key); 509108f7bbaSPaul Durrant } 510108f7bbaSPaul Durrant 511b6af8926SPaul Durrant static void xen_bus_unplug_request(HotplugHandler *hotplug, 512b6af8926SPaul Durrant DeviceState *dev, 513b6af8926SPaul Durrant Error **errp) 514b6af8926SPaul Durrant { 515b6af8926SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 516b6af8926SPaul Durrant 517b6af8926SPaul Durrant xen_device_unplug(xendev, errp); 518b6af8926SPaul Durrant } 519b6af8926SPaul Durrant 520108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data) 521108f7bbaSPaul Durrant { 522108f7bbaSPaul Durrant BusClass *bus_class = BUS_CLASS(class); 523b6af8926SPaul Durrant HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); 524108f7bbaSPaul Durrant 525094a2239SPaul Durrant bus_class->print_dev = xen_bus_print_dev; 526094a2239SPaul Durrant bus_class->get_dev_path = xen_bus_get_dev_path; 527108f7bbaSPaul Durrant bus_class->realize = xen_bus_realize; 528108f7bbaSPaul Durrant bus_class->unrealize = xen_bus_unrealize; 529b6af8926SPaul Durrant 530b6af8926SPaul Durrant hotplug_class->unplug_request = xen_bus_unplug_request; 531108f7bbaSPaul Durrant } 532108f7bbaSPaul Durrant 533108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = { 534108f7bbaSPaul Durrant .name = TYPE_XEN_BUS, 535108f7bbaSPaul Durrant .parent = TYPE_BUS, 536108f7bbaSPaul Durrant .instance_size = sizeof(XenBus), 537108f7bbaSPaul Durrant .class_size = sizeof(XenBusClass), 538108f7bbaSPaul Durrant .class_init = xen_bus_class_init, 539108f7bbaSPaul Durrant .interfaces = (InterfaceInfo[]) { 540108f7bbaSPaul Durrant { TYPE_HOTPLUG_HANDLER }, 541108f7bbaSPaul Durrant { } 542108f7bbaSPaul Durrant }, 543108f7bbaSPaul Durrant }; 544108f7bbaSPaul Durrant 545b6af8926SPaul Durrant void xen_device_backend_printf(XenDevice *xendev, const char *key, 546094a2239SPaul Durrant const char *fmt, ...) 547094a2239SPaul Durrant { 548094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 549094a2239SPaul Durrant Error *local_err = NULL; 550094a2239SPaul Durrant va_list ap; 551094a2239SPaul Durrant 552094a2239SPaul Durrant g_assert(xenbus->xsh); 553094a2239SPaul Durrant 554094a2239SPaul Durrant va_start(ap, fmt); 555094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 556094a2239SPaul Durrant &local_err, fmt, ap); 557094a2239SPaul Durrant va_end(ap); 558094a2239SPaul Durrant 559094a2239SPaul Durrant if (local_err) { 560094a2239SPaul Durrant error_report_err(local_err); 561094a2239SPaul Durrant } 562094a2239SPaul Durrant } 563094a2239SPaul Durrant 564d62449daSDaniel P. Berrangé G_GNUC_SCANF(3, 4) 56582a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key, 56682a29e30SPaul Durrant const char *fmt, ...) 56782a29e30SPaul Durrant { 56882a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 56982a29e30SPaul Durrant va_list ap; 57082a29e30SPaul Durrant int rc; 57182a29e30SPaul Durrant 57282a29e30SPaul Durrant g_assert(xenbus->xsh); 57382a29e30SPaul Durrant 57482a29e30SPaul Durrant va_start(ap, fmt); 57582a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 57682a29e30SPaul Durrant NULL, fmt, ap); 57782a29e30SPaul Durrant va_end(ap); 57882a29e30SPaul Durrant 57982a29e30SPaul Durrant return rc; 58082a29e30SPaul Durrant } 58182a29e30SPaul Durrant 58282a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev, 583094a2239SPaul Durrant enum xenbus_state state) 584094a2239SPaul Durrant { 585094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 586094a2239SPaul Durrant 587094a2239SPaul Durrant if (xendev->backend_state == state) { 588094a2239SPaul Durrant return; 589094a2239SPaul Durrant } 590094a2239SPaul Durrant 591094a2239SPaul Durrant trace_xen_device_backend_state(type, xendev->name, 592094a2239SPaul Durrant xs_strstate(state)); 593094a2239SPaul Durrant 594094a2239SPaul Durrant xendev->backend_state = state; 595094a2239SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state); 596094a2239SPaul Durrant } 597094a2239SPaul Durrant 59882a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) 59982a29e30SPaul Durrant { 60082a29e30SPaul Durrant return xendev->backend_state; 60182a29e30SPaul Durrant } 60282a29e30SPaul Durrant 603b6af8926SPaul Durrant static void xen_device_backend_set_online(XenDevice *xendev, bool online) 604b6af8926SPaul Durrant { 605b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 606b6af8926SPaul Durrant 607b6af8926SPaul Durrant if (xendev->backend_online == online) { 608b6af8926SPaul Durrant return; 609b6af8926SPaul Durrant } 610b6af8926SPaul Durrant 611b6af8926SPaul Durrant trace_xen_device_backend_online(type, xendev->name, online); 612b6af8926SPaul Durrant 613b6af8926SPaul Durrant xendev->backend_online = online; 614b6af8926SPaul Durrant xen_device_backend_printf(xendev, "online", "%u", online); 615b6af8926SPaul Durrant } 616b6af8926SPaul Durrant 617cb323146SAnthony PERARD /* 618cb323146SAnthony PERARD * Tell from the state whether the frontend is likely alive, 619cb323146SAnthony PERARD * i.e. it will react to a change of state of the backend. 620cb323146SAnthony PERARD */ 6213809f758SPaul Durrant static bool xen_device_frontend_is_active(XenDevice *xendev) 622cb323146SAnthony PERARD { 6233809f758SPaul Durrant switch (xendev->frontend_state) { 624cb323146SAnthony PERARD case XenbusStateInitWait: 625cb323146SAnthony PERARD case XenbusStateInitialised: 626cb323146SAnthony PERARD case XenbusStateConnected: 627cb323146SAnthony PERARD case XenbusStateClosing: 628cb323146SAnthony PERARD return true; 629cb323146SAnthony PERARD default: 630cb323146SAnthony PERARD return false; 631cb323146SAnthony PERARD } 632cb323146SAnthony PERARD } 633cb323146SAnthony PERARD 634b6af8926SPaul Durrant static void xen_device_backend_changed(void *opaque) 635b6af8926SPaul Durrant { 636b6af8926SPaul Durrant XenDevice *xendev = opaque; 637b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 638b6af8926SPaul Durrant enum xenbus_state state; 639b6af8926SPaul Durrant unsigned int online; 640b6af8926SPaul Durrant 641b6af8926SPaul Durrant trace_xen_device_backend_changed(type, xendev->name); 642b6af8926SPaul Durrant 643b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) { 644b6af8926SPaul Durrant state = XenbusStateUnknown; 645b6af8926SPaul Durrant } 646b6af8926SPaul Durrant 647b6af8926SPaul Durrant xen_device_backend_set_state(xendev, state); 648b6af8926SPaul Durrant 649b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { 650b6af8926SPaul Durrant online = 0; 651b6af8926SPaul Durrant } 652b6af8926SPaul Durrant 653b6af8926SPaul Durrant xen_device_backend_set_online(xendev, !!online); 654b6af8926SPaul Durrant 655b6af8926SPaul Durrant /* 656b6af8926SPaul Durrant * If the toolstack (or unplug request callback) has set the backend 657cb323146SAnthony PERARD * state to Closing, but there is no active frontend then set the 658cb323146SAnthony PERARD * backend state to Closed. 659b6af8926SPaul Durrant */ 6603809f758SPaul Durrant if (state == XenbusStateClosing && 6613809f758SPaul Durrant !xen_device_frontend_is_active(xendev)) { 662b6af8926SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateClosed); 663b6af8926SPaul Durrant } 664b6af8926SPaul Durrant 665b6af8926SPaul Durrant /* 66667bc8e00SPaul Durrant * If a backend is still 'online' then we should leave it alone but, 6673809f758SPaul Durrant * if a backend is not 'online', then the device is a candidate 6683809f758SPaul Durrant * for destruction. Hence add it to the 'inactive' list to be cleaned 6693809f758SPaul Durrant * by xen_bus_cleanup(). 670b6af8926SPaul Durrant */ 6713809f758SPaul Durrant if (!online && 6723809f758SPaul Durrant (state == XenbusStateClosed || state == XenbusStateInitialising || 6733809f758SPaul Durrant state == XenbusStateInitWait || state == XenbusStateUnknown) && 6743809f758SPaul Durrant !xendev->inactive) { 6753809f758SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 676a783f8adSPaul Durrant 6773809f758SPaul Durrant xendev->inactive = true; 6783809f758SPaul Durrant QLIST_INSERT_HEAD(&xenbus->inactive_devices, xendev, list); 679a783f8adSPaul Durrant 6803809f758SPaul Durrant /* 6813809f758SPaul Durrant * Re-write the state to cause a XenBus backend_watch notification, 6823809f758SPaul Durrant * resulting in a call to xen_bus_cleanup(). 6833809f758SPaul Durrant */ 6843809f758SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state); 685a783f8adSPaul Durrant } 686b6af8926SPaul Durrant } 687b6af8926SPaul Durrant 688d198b711SPaul Durrant static XenWatch *xen_device_add_watch(XenDevice *xendev, const char *node, 689d198b711SPaul Durrant const char *key, 690d198b711SPaul Durrant XenWatchHandler handler, 691d198b711SPaul Durrant Error **errp) 692d198b711SPaul Durrant { 693d198b711SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 694d198b711SPaul Durrant 695d198b711SPaul Durrant trace_xen_device_add_watch(type, xendev->name, node, key); 696d198b711SPaul Durrant 697d198b711SPaul Durrant return watch_list_add(xendev->watch_list, node, key, handler, xendev, 698d198b711SPaul Durrant errp); 699d198b711SPaul Durrant } 700d198b711SPaul Durrant 701d198b711SPaul Durrant static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch, 702d198b711SPaul Durrant Error **errp) 703d198b711SPaul Durrant { 704d198b711SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 705d198b711SPaul Durrant 706d198b711SPaul Durrant trace_xen_device_remove_watch(type, xendev->name, watch->node, 707d198b711SPaul Durrant watch->key); 708d198b711SPaul Durrant 709d198b711SPaul Durrant watch_list_remove(xendev->watch_list, watch, errp); 710d198b711SPaul Durrant } 711d198b711SPaul Durrant 712d198b711SPaul Durrant 713094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp) 714094a2239SPaul Durrant { 7151de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 716094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 717094a2239SPaul Durrant struct xs_permissions perms[2]; 718094a2239SPaul Durrant 719094a2239SPaul Durrant xendev->backend_path = xen_device_get_backend_path(xendev); 720094a2239SPaul Durrant 721094a2239SPaul Durrant perms[0].id = xenbus->backend_id; 722094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 723094a2239SPaul Durrant perms[1].id = xendev->frontend_id; 724094a2239SPaul Durrant perms[1].perms = XS_PERM_READ; 725094a2239SPaul Durrant 726094a2239SPaul Durrant g_assert(xenbus->xsh); 727094a2239SPaul Durrant 728094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, 7291de7096dSVladimir Sementsov-Ogievskiy ARRAY_SIZE(perms), errp); 7301de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 7311de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create backend: "); 732b6af8926SPaul Durrant return; 733b6af8926SPaul Durrant } 734b6af8926SPaul Durrant 735b6af8926SPaul Durrant xendev->backend_state_watch = 736d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->backend_path, 737b6af8926SPaul Durrant "state", xen_device_backend_changed, 7381de7096dSVladimir Sementsov-Ogievskiy errp); 7391de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 7401de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch backend state: "); 741b6af8926SPaul Durrant return; 742b6af8926SPaul Durrant } 743b6af8926SPaul Durrant 744b6af8926SPaul Durrant xendev->backend_online_watch = 745d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->backend_path, 746b6af8926SPaul Durrant "online", xen_device_backend_changed, 7471de7096dSVladimir Sementsov-Ogievskiy errp); 7481de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 7491de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch backend online: "); 750b6af8926SPaul Durrant return; 751094a2239SPaul Durrant } 752094a2239SPaul Durrant } 753094a2239SPaul Durrant 754094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev) 755094a2239SPaul Durrant { 756094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 757094a2239SPaul Durrant Error *local_err = NULL; 758094a2239SPaul Durrant 759b6af8926SPaul Durrant if (xendev->backend_online_watch) { 760d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->backend_online_watch, NULL); 761b6af8926SPaul Durrant xendev->backend_online_watch = NULL; 762b6af8926SPaul Durrant } 763b6af8926SPaul Durrant 764b6af8926SPaul Durrant if (xendev->backend_state_watch) { 765d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->backend_state_watch, NULL); 766b6af8926SPaul Durrant xendev->backend_state_watch = NULL; 767b6af8926SPaul Durrant } 768b6af8926SPaul Durrant 769094a2239SPaul Durrant if (!xendev->backend_path) { 770094a2239SPaul Durrant return; 771094a2239SPaul Durrant } 772094a2239SPaul Durrant 773094a2239SPaul Durrant g_assert(xenbus->xsh); 774094a2239SPaul Durrant 775094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path, 776094a2239SPaul Durrant &local_err); 777094a2239SPaul Durrant g_free(xendev->backend_path); 778094a2239SPaul Durrant xendev->backend_path = NULL; 779094a2239SPaul Durrant 780094a2239SPaul Durrant if (local_err) { 781094a2239SPaul Durrant error_report_err(local_err); 782094a2239SPaul Durrant } 783094a2239SPaul Durrant } 784094a2239SPaul Durrant 785b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key, 786094a2239SPaul Durrant const char *fmt, ...) 787094a2239SPaul Durrant { 788094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 789094a2239SPaul Durrant Error *local_err = NULL; 790094a2239SPaul Durrant va_list ap; 791094a2239SPaul Durrant 792094a2239SPaul Durrant g_assert(xenbus->xsh); 793094a2239SPaul Durrant 794094a2239SPaul Durrant va_start(ap, fmt); 795094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 796094a2239SPaul Durrant &local_err, fmt, ap); 797094a2239SPaul Durrant va_end(ap); 798094a2239SPaul Durrant 799094a2239SPaul Durrant if (local_err) { 800094a2239SPaul Durrant error_report_err(local_err); 801094a2239SPaul Durrant } 802094a2239SPaul Durrant } 803094a2239SPaul Durrant 804b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key, 80582a29e30SPaul Durrant const char *fmt, ...) 80682a29e30SPaul Durrant { 80782a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 80882a29e30SPaul Durrant va_list ap; 80982a29e30SPaul Durrant int rc; 81082a29e30SPaul Durrant 81182a29e30SPaul Durrant g_assert(xenbus->xsh); 81282a29e30SPaul Durrant 81382a29e30SPaul Durrant va_start(ap, fmt); 81482a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 81582a29e30SPaul Durrant NULL, fmt, ap); 81682a29e30SPaul Durrant va_end(ap); 81782a29e30SPaul Durrant 81882a29e30SPaul Durrant return rc; 81982a29e30SPaul Durrant } 82082a29e30SPaul Durrant 821094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev, 822705be570SAnthony PERARD enum xenbus_state state, 823705be570SAnthony PERARD bool publish) 824094a2239SPaul Durrant { 825094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 826094a2239SPaul Durrant 827094a2239SPaul Durrant if (xendev->frontend_state == state) { 828094a2239SPaul Durrant return; 829094a2239SPaul Durrant } 830094a2239SPaul Durrant 831094a2239SPaul Durrant trace_xen_device_frontend_state(type, xendev->name, 832094a2239SPaul Durrant xs_strstate(state)); 833094a2239SPaul Durrant 834094a2239SPaul Durrant xendev->frontend_state = state; 835705be570SAnthony PERARD if (publish) { 836094a2239SPaul Durrant xen_device_frontend_printf(xendev, "state", "%u", state); 837094a2239SPaul Durrant } 838705be570SAnthony PERARD } 839094a2239SPaul Durrant 84082a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque) 84182a29e30SPaul Durrant { 84282a29e30SPaul Durrant XenDevice *xendev = opaque; 84382a29e30SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 84482a29e30SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 84582a29e30SPaul Durrant enum xenbus_state state; 84682a29e30SPaul Durrant 84782a29e30SPaul Durrant trace_xen_device_frontend_changed(type, xendev->name); 84882a29e30SPaul Durrant 84982a29e30SPaul Durrant if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) { 85082a29e30SPaul Durrant state = XenbusStateUnknown; 85182a29e30SPaul Durrant } 85282a29e30SPaul Durrant 853705be570SAnthony PERARD xen_device_frontend_set_state(xendev, state, false); 85482a29e30SPaul Durrant 85567bc8e00SPaul Durrant if (state == XenbusStateInitialising && 85667bc8e00SPaul Durrant xendev->backend_state == XenbusStateClosed && 85767bc8e00SPaul Durrant xendev->backend_online) { 85867bc8e00SPaul Durrant /* 85967bc8e00SPaul Durrant * The frontend is re-initializing so switch back to 86067bc8e00SPaul Durrant * InitWait. 86167bc8e00SPaul Durrant */ 86267bc8e00SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 86367bc8e00SPaul Durrant return; 86467bc8e00SPaul Durrant } 86567bc8e00SPaul Durrant 86682a29e30SPaul Durrant if (xendev_class->frontend_changed) { 86782a29e30SPaul Durrant Error *local_err = NULL; 86882a29e30SPaul Durrant 86982a29e30SPaul Durrant xendev_class->frontend_changed(xendev, state, &local_err); 87082a29e30SPaul Durrant 87182a29e30SPaul Durrant if (local_err) { 87282a29e30SPaul Durrant error_reportf_err(local_err, "frontend change error: "); 87382a29e30SPaul Durrant } 87482a29e30SPaul Durrant } 87582a29e30SPaul Durrant } 87682a29e30SPaul Durrant 8776bd6b955SMark Syms static bool xen_device_frontend_exists(XenDevice *xendev) 8786bd6b955SMark Syms { 8796bd6b955SMark Syms enum xenbus_state state; 8806bd6b955SMark Syms 8816bd6b955SMark Syms return (xen_device_frontend_scanf(xendev, "state", "%u", &state) == 1); 8826bd6b955SMark Syms } 8836bd6b955SMark Syms 884094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp) 885094a2239SPaul Durrant { 8861de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 887094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 888094a2239SPaul Durrant struct xs_permissions perms[2]; 889094a2239SPaul Durrant 890094a2239SPaul Durrant xendev->frontend_path = xen_device_get_frontend_path(xendev); 891094a2239SPaul Durrant 8926bd6b955SMark Syms /* 8936bd6b955SMark Syms * The frontend area may have already been created by a legacy 8946bd6b955SMark Syms * toolstack. 8956bd6b955SMark Syms */ 8966bd6b955SMark Syms if (!xen_device_frontend_exists(xendev)) { 897094a2239SPaul Durrant perms[0].id = xendev->frontend_id; 898094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 899094a2239SPaul Durrant perms[1].id = xenbus->backend_id; 900094a2239SPaul Durrant perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; 901094a2239SPaul Durrant 902094a2239SPaul Durrant g_assert(xenbus->xsh); 903094a2239SPaul Durrant 904094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, 9051de7096dSVladimir Sementsov-Ogievskiy ARRAY_SIZE(perms), errp); 9061de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 9071de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create frontend: "); 90882a29e30SPaul Durrant return; 90982a29e30SPaul Durrant } 9106bd6b955SMark Syms } 91182a29e30SPaul Durrant 91282a29e30SPaul Durrant xendev->frontend_state_watch = 913d198b711SPaul Durrant xen_device_add_watch(xendev, xendev->frontend_path, "state", 9141de7096dSVladimir Sementsov-Ogievskiy xen_device_frontend_changed, errp); 9151de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 9161de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch frontend state: "); 917094a2239SPaul Durrant } 918094a2239SPaul Durrant } 919094a2239SPaul Durrant 920094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev) 921094a2239SPaul Durrant { 922094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 923094a2239SPaul Durrant Error *local_err = NULL; 924094a2239SPaul Durrant 92582a29e30SPaul Durrant if (xendev->frontend_state_watch) { 926d198b711SPaul Durrant xen_device_remove_watch(xendev, xendev->frontend_state_watch, 927d198b711SPaul Durrant NULL); 92882a29e30SPaul Durrant xendev->frontend_state_watch = NULL; 92982a29e30SPaul Durrant } 93082a29e30SPaul Durrant 931094a2239SPaul Durrant if (!xendev->frontend_path) { 932094a2239SPaul Durrant return; 933094a2239SPaul Durrant } 934094a2239SPaul Durrant 935094a2239SPaul Durrant g_assert(xenbus->xsh); 936094a2239SPaul Durrant 937094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path, 938094a2239SPaul Durrant &local_err); 939094a2239SPaul Durrant g_free(xendev->frontend_path); 940094a2239SPaul Durrant xendev->frontend_path = NULL; 941094a2239SPaul Durrant 942094a2239SPaul Durrant if (local_err) { 943094a2239SPaul Durrant error_report_err(local_err); 944094a2239SPaul Durrant } 945094a2239SPaul Durrant } 946094a2239SPaul Durrant 9474b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, 9484b34b5b1SPaul Durrant Error **errp) 9494b34b5b1SPaul Durrant { 950*c412ba47SDavid Woodhouse if (qemu_xen_gnttab_set_max_grants(xendev->xgth, nr_refs)) { 9514b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); 9524b34b5b1SPaul Durrant } 9534b34b5b1SPaul Durrant } 9544b34b5b1SPaul Durrant 9554b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, 9564b34b5b1SPaul Durrant unsigned int nr_refs, int prot, 9574b34b5b1SPaul Durrant Error **errp) 9584b34b5b1SPaul Durrant { 959*c412ba47SDavid Woodhouse void *map = qemu_xen_gnttab_map_refs(xendev->xgth, nr_refs, 960*c412ba47SDavid Woodhouse xendev->frontend_id, refs, prot); 9614b34b5b1SPaul Durrant 9624b34b5b1SPaul Durrant if (!map) { 9634b34b5b1SPaul Durrant error_setg_errno(errp, errno, 9644b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 9654b34b5b1SPaul Durrant } 9664b34b5b1SPaul Durrant 9674b34b5b1SPaul Durrant return map; 9684b34b5b1SPaul Durrant } 9694b34b5b1SPaul Durrant 9704b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, 9714b34b5b1SPaul Durrant unsigned int nr_refs, Error **errp) 9724b34b5b1SPaul Durrant { 973*c412ba47SDavid Woodhouse if (qemu_xen_gnttab_unmap(xendev->xgth, map, nr_refs)) { 9744b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 9754b34b5b1SPaul Durrant } 9764b34b5b1SPaul Durrant } 9774b34b5b1SPaul Durrant 9784b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, 9794b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 9804b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 9814b34b5b1SPaul Durrant { 982*c412ba47SDavid Woodhouse qemu_xen_gnttab_grant_copy(xendev->xgth, to_domain, xendev->frontend_id, 983*c412ba47SDavid Woodhouse (XenGrantCopySegment *)segs, nr_segs, errp); 9844b34b5b1SPaul Durrant } 9854b34b5b1SPaul Durrant 986a3d669c8SPaul Durrant struct XenEventChannel { 987c0b336eaSPaul Durrant QLIST_ENTRY(XenEventChannel) list; 98883361a8aSPaul Durrant AioContext *ctx; 989c0b336eaSPaul Durrant xenevtchn_handle *xeh; 990a3d669c8SPaul Durrant evtchn_port_t local_port; 991a3d669c8SPaul Durrant XenEventHandler handler; 992a3d669c8SPaul Durrant void *opaque; 993a3d669c8SPaul Durrant }; 994a3d669c8SPaul Durrant 995345f42b4SPaul Durrant static bool xen_device_poll(void *opaque) 996345f42b4SPaul Durrant { 997345f42b4SPaul Durrant XenEventChannel *channel = opaque; 998345f42b4SPaul Durrant 999345f42b4SPaul Durrant return channel->handler(channel->opaque); 1000345f42b4SPaul Durrant } 1001345f42b4SPaul Durrant 1002c0b336eaSPaul Durrant static void xen_device_event(void *opaque) 1003a3d669c8SPaul Durrant { 1004c0b336eaSPaul Durrant XenEventChannel *channel = opaque; 1005b6cacfeaSDavid Woodhouse unsigned long port = qemu_xen_evtchn_pending(channel->xeh); 1006a3d669c8SPaul Durrant 1007a3d669c8SPaul Durrant if (port == channel->local_port) { 1008345f42b4SPaul Durrant xen_device_poll(channel); 1009c0b336eaSPaul Durrant 1010b6cacfeaSDavid Woodhouse qemu_xen_evtchn_unmask(channel->xeh, port); 1011a3d669c8SPaul Durrant } 1012a3d669c8SPaul Durrant } 1013a3d669c8SPaul Durrant 101432d0b7beSPaul Durrant void xen_device_set_event_channel_context(XenDevice *xendev, 101532d0b7beSPaul Durrant XenEventChannel *channel, 101683361a8aSPaul Durrant AioContext *ctx, 101732d0b7beSPaul Durrant Error **errp) 101832d0b7beSPaul Durrant { 101932d0b7beSPaul Durrant if (!channel) { 102032d0b7beSPaul Durrant error_setg(errp, "bad channel"); 102132d0b7beSPaul Durrant return; 102232d0b7beSPaul Durrant } 102332d0b7beSPaul Durrant 102432d0b7beSPaul Durrant if (channel->ctx) 1025b6cacfeaSDavid Woodhouse aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true, 1026826cc324SStefan Hajnoczi NULL, NULL, NULL, NULL, NULL); 102732d0b7beSPaul Durrant 102832d0b7beSPaul Durrant channel->ctx = ctx; 1029b6cacfeaSDavid Woodhouse aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true, 1030826cc324SStefan Hajnoczi xen_device_event, NULL, xen_device_poll, NULL, channel); 103132d0b7beSPaul Durrant } 103232d0b7beSPaul Durrant 103332d0b7beSPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, 1034a3d669c8SPaul Durrant unsigned int port, 1035a3d669c8SPaul Durrant XenEventHandler handler, 1036a3d669c8SPaul Durrant void *opaque, Error **errp) 1037a3d669c8SPaul Durrant { 1038a3d669c8SPaul Durrant XenEventChannel *channel = g_new0(XenEventChannel, 1); 1039a3d669c8SPaul Durrant xenevtchn_port_or_error_t local_port; 1040a3d669c8SPaul Durrant 1041b6cacfeaSDavid Woodhouse channel->xeh = qemu_xen_evtchn_open(); 1042c0b336eaSPaul Durrant if (!channel->xeh) { 1043c0b336eaSPaul Durrant error_setg_errno(errp, errno, "failed xenevtchn_open"); 1044c0b336eaSPaul Durrant goto fail; 1045c0b336eaSPaul Durrant } 1046c0b336eaSPaul Durrant 1047b6cacfeaSDavid Woodhouse local_port = qemu_xen_evtchn_bind_interdomain(channel->xeh, 1048a3d669c8SPaul Durrant xendev->frontend_id, 1049a3d669c8SPaul Durrant port); 1050a3d669c8SPaul Durrant if (local_port < 0) { 1051a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed"); 1052c0b336eaSPaul Durrant goto fail; 1053a3d669c8SPaul Durrant } 1054a3d669c8SPaul Durrant 1055a3d669c8SPaul Durrant channel->local_port = local_port; 1056a3d669c8SPaul Durrant channel->handler = handler; 1057a3d669c8SPaul Durrant channel->opaque = opaque; 1058a3d669c8SPaul Durrant 105932d0b7beSPaul Durrant /* Only reason for failure is a NULL channel */ 106032d0b7beSPaul Durrant xen_device_set_event_channel_context(xendev, channel, 106132d0b7beSPaul Durrant qemu_get_aio_context(), 106232d0b7beSPaul Durrant &error_abort); 1063c0b336eaSPaul Durrant 1064c0b336eaSPaul Durrant QLIST_INSERT_HEAD(&xendev->event_channels, channel, list); 1065a3d669c8SPaul Durrant 1066a3d669c8SPaul Durrant return channel; 1067c0b336eaSPaul Durrant 1068c0b336eaSPaul Durrant fail: 1069c0b336eaSPaul Durrant if (channel->xeh) { 1070b6cacfeaSDavid Woodhouse qemu_xen_evtchn_close(channel->xeh); 1071c0b336eaSPaul Durrant } 1072c0b336eaSPaul Durrant 1073c0b336eaSPaul Durrant g_free(channel); 1074c0b336eaSPaul Durrant 1075c0b336eaSPaul Durrant return NULL; 1076a3d669c8SPaul Durrant } 1077a3d669c8SPaul Durrant 1078a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev, 1079a3d669c8SPaul Durrant XenEventChannel *channel, 1080a3d669c8SPaul Durrant Error **errp) 1081a3d669c8SPaul Durrant { 1082a3d669c8SPaul Durrant if (!channel) { 1083a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1084a3d669c8SPaul Durrant return; 1085a3d669c8SPaul Durrant } 1086a3d669c8SPaul Durrant 1087b6cacfeaSDavid Woodhouse if (qemu_xen_evtchn_notify(channel->xeh, channel->local_port) < 0) { 1088a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_notify failed"); 1089a3d669c8SPaul Durrant } 1090a3d669c8SPaul Durrant } 1091a3d669c8SPaul Durrant 1092a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev, 1093a3d669c8SPaul Durrant XenEventChannel *channel, 1094a3d669c8SPaul Durrant Error **errp) 1095a3d669c8SPaul Durrant { 1096a3d669c8SPaul Durrant if (!channel) { 1097a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1098a3d669c8SPaul Durrant return; 1099a3d669c8SPaul Durrant } 1100a3d669c8SPaul Durrant 1101c0b336eaSPaul Durrant QLIST_REMOVE(channel, list); 1102a3d669c8SPaul Durrant 1103b6cacfeaSDavid Woodhouse aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh), true, 1104826cc324SStefan Hajnoczi NULL, NULL, NULL, NULL, NULL); 1105c0b336eaSPaul Durrant 1106b6cacfeaSDavid Woodhouse if (qemu_xen_evtchn_unbind(channel->xeh, channel->local_port) < 0) { 1107a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_unbind failed"); 1108a3d669c8SPaul Durrant } 1109a3d669c8SPaul Durrant 1110b6cacfeaSDavid Woodhouse qemu_xen_evtchn_close(channel->xeh); 1111a3d669c8SPaul Durrant g_free(channel); 1112a3d669c8SPaul Durrant } 1113a3d669c8SPaul Durrant 1114b69c3c21SMarkus Armbruster static void xen_device_unrealize(DeviceState *dev) 1115108f7bbaSPaul Durrant { 1116108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1117108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1118108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1119c0b336eaSPaul Durrant XenEventChannel *channel, *next; 1120108f7bbaSPaul Durrant 1121094a2239SPaul Durrant if (!xendev->name) { 1122094a2239SPaul Durrant return; 1123094a2239SPaul Durrant } 1124094a2239SPaul Durrant 1125094a2239SPaul Durrant trace_xen_device_unrealize(type, xendev->name); 1126094a2239SPaul Durrant 1127094a2239SPaul Durrant if (xendev->exit.notify) { 1128094a2239SPaul Durrant qemu_remove_exit_notifier(&xendev->exit); 1129094a2239SPaul Durrant xendev->exit.notify = NULL; 1130094a2239SPaul Durrant } 1131108f7bbaSPaul Durrant 1132108f7bbaSPaul Durrant if (xendev_class->unrealize) { 1133b69c3c21SMarkus Armbruster xendev_class->unrealize(xendev); 1134108f7bbaSPaul Durrant } 1135094a2239SPaul Durrant 1136c0b336eaSPaul Durrant /* Make sure all event channels are cleaned up */ 1137c0b336eaSPaul Durrant QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) { 1138c0b336eaSPaul Durrant xen_device_unbind_event_channel(xendev, channel, NULL); 1139c0b336eaSPaul Durrant } 1140c0b336eaSPaul Durrant 1141094a2239SPaul Durrant xen_device_frontend_destroy(xendev); 1142094a2239SPaul Durrant xen_device_backend_destroy(xendev); 1143094a2239SPaul Durrant 11444b34b5b1SPaul Durrant if (xendev->xgth) { 1145*c412ba47SDavid Woodhouse qemu_xen_gnttab_close(xendev->xgth); 11464b34b5b1SPaul Durrant xendev->xgth = NULL; 11474b34b5b1SPaul Durrant } 11484b34b5b1SPaul Durrant 1149d198b711SPaul Durrant if (xendev->watch_list) { 1150d198b711SPaul Durrant watch_list_destroy(xendev->watch_list); 1151d198b711SPaul Durrant xendev->watch_list = NULL; 1152d198b711SPaul Durrant } 1153d198b711SPaul Durrant 1154d198b711SPaul Durrant if (xendev->xsh) { 1155d198b711SPaul Durrant xs_close(xendev->xsh); 1156d198b711SPaul Durrant xendev->xsh = NULL; 1157d198b711SPaul Durrant } 1158d198b711SPaul Durrant 1159094a2239SPaul Durrant g_free(xendev->name); 1160094a2239SPaul Durrant xendev->name = NULL; 1161094a2239SPaul Durrant } 1162094a2239SPaul Durrant 1163094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data) 1164094a2239SPaul Durrant { 1165094a2239SPaul Durrant XenDevice *xendev = container_of(n, XenDevice, exit); 1166094a2239SPaul Durrant 1167b69c3c21SMarkus Armbruster xen_device_unrealize(DEVICE(xendev)); 1168108f7bbaSPaul Durrant } 1169108f7bbaSPaul Durrant 1170108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp) 1171108f7bbaSPaul Durrant { 11721de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD(); 1173108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1174108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1175094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 1176108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1177108f7bbaSPaul Durrant 1178094a2239SPaul Durrant if (xendev->frontend_id == DOMID_INVALID) { 1179094a2239SPaul Durrant xendev->frontend_id = xen_domid; 1180094a2239SPaul Durrant } 1181094a2239SPaul Durrant 1182094a2239SPaul Durrant if (xendev->frontend_id >= DOMID_FIRST_RESERVED) { 1183094a2239SPaul Durrant error_setg(errp, "invalid frontend-id"); 1184094a2239SPaul Durrant goto unrealize; 1185094a2239SPaul Durrant } 1186094a2239SPaul Durrant 1187094a2239SPaul Durrant if (!xendev_class->get_name) { 1188094a2239SPaul Durrant error_setg(errp, "get_name method not implemented"); 1189094a2239SPaul Durrant goto unrealize; 1190094a2239SPaul Durrant } 1191094a2239SPaul Durrant 11921de7096dSVladimir Sementsov-Ogievskiy xendev->name = xendev_class->get_name(xendev, errp); 11931de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 11941de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to get device name: "); 1195094a2239SPaul Durrant goto unrealize; 1196094a2239SPaul Durrant } 1197094a2239SPaul Durrant 1198094a2239SPaul Durrant trace_xen_device_realize(type, xendev->name); 1199094a2239SPaul Durrant 1200d198b711SPaul Durrant xendev->xsh = xs_open(0); 1201d198b711SPaul Durrant if (!xendev->xsh) { 1202d198b711SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 1203d198b711SPaul Durrant goto unrealize; 1204d198b711SPaul Durrant } 1205d198b711SPaul Durrant 1206d198b711SPaul Durrant xendev->watch_list = watch_list_create(xendev->xsh); 1207d198b711SPaul Durrant 1208*c412ba47SDavid Woodhouse xendev->xgth = qemu_xen_gnttab_open(); 12094b34b5b1SPaul Durrant if (!xendev->xgth) { 12104b34b5b1SPaul Durrant error_setg_errno(errp, errno, "failed xengnttab_open"); 12114b34b5b1SPaul Durrant goto unrealize; 12124b34b5b1SPaul Durrant } 12134b34b5b1SPaul Durrant 12141de7096dSVladimir Sementsov-Ogievskiy xen_device_backend_create(xendev, errp); 12151de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 1216094a2239SPaul Durrant goto unrealize; 1217094a2239SPaul Durrant } 1218094a2239SPaul Durrant 12191de7096dSVladimir Sementsov-Ogievskiy xen_device_frontend_create(xendev, errp); 12201de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 1221094a2239SPaul Durrant goto unrealize; 1222094a2239SPaul Durrant } 1223108f7bbaSPaul Durrant 1224108f7bbaSPaul Durrant if (xendev_class->realize) { 12251de7096dSVladimir Sementsov-Ogievskiy xendev_class->realize(xendev, errp); 12261de7096dSVladimir Sementsov-Ogievskiy if (*errp) { 1227108f7bbaSPaul Durrant goto unrealize; 1228108f7bbaSPaul Durrant } 1229108f7bbaSPaul Durrant } 1230108f7bbaSPaul Durrant 1231094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend", "%s", 1232094a2239SPaul Durrant xendev->frontend_path); 1233094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend-id", "%u", 1234094a2239SPaul Durrant xendev->frontend_id); 1235094a2239SPaul Durrant xen_device_backend_printf(xendev, "hotplug-status", "connected"); 1236094a2239SPaul Durrant 1237b6af8926SPaul Durrant xen_device_backend_set_online(xendev, true); 1238094a2239SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 1239094a2239SPaul Durrant 12406bd6b955SMark Syms if (!xen_device_frontend_exists(xendev)) { 1241094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend", "%s", 1242094a2239SPaul Durrant xendev->backend_path); 1243094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend-id", "%u", 1244094a2239SPaul Durrant xenbus->backend_id); 1245094a2239SPaul Durrant 1246705be570SAnthony PERARD xen_device_frontend_set_state(xendev, XenbusStateInitialising, true); 12476bd6b955SMark Syms } 1248094a2239SPaul Durrant 1249094a2239SPaul Durrant xendev->exit.notify = xen_device_exit; 1250094a2239SPaul Durrant qemu_add_exit_notifier(&xendev->exit); 1251108f7bbaSPaul Durrant return; 1252108f7bbaSPaul Durrant 1253108f7bbaSPaul Durrant unrealize: 1254b69c3c21SMarkus Armbruster xen_device_unrealize(dev); 1255108f7bbaSPaul Durrant } 1256108f7bbaSPaul Durrant 1257094a2239SPaul Durrant static Property xen_device_props[] = { 1258094a2239SPaul Durrant DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id, 1259094a2239SPaul Durrant DOMID_INVALID), 1260094a2239SPaul Durrant DEFINE_PROP_END_OF_LIST() 1261094a2239SPaul Durrant }; 1262094a2239SPaul Durrant 1263108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data) 1264108f7bbaSPaul Durrant { 1265108f7bbaSPaul Durrant DeviceClass *dev_class = DEVICE_CLASS(class); 1266108f7bbaSPaul Durrant 1267108f7bbaSPaul Durrant dev_class->realize = xen_device_realize; 1268108f7bbaSPaul Durrant dev_class->unrealize = xen_device_unrealize; 12694f67d30bSMarc-André Lureau device_class_set_props(dev_class, xen_device_props); 1270108f7bbaSPaul Durrant dev_class->bus_type = TYPE_XEN_BUS; 1271108f7bbaSPaul Durrant } 1272108f7bbaSPaul Durrant 1273108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = { 1274108f7bbaSPaul Durrant .name = TYPE_XEN_DEVICE, 1275108f7bbaSPaul Durrant .parent = TYPE_DEVICE, 1276108f7bbaSPaul Durrant .instance_size = sizeof(XenDevice), 1277108f7bbaSPaul Durrant .abstract = true, 1278108f7bbaSPaul Durrant .class_size = sizeof(XenDeviceClass), 1279108f7bbaSPaul Durrant .class_init = xen_device_class_init, 1280108f7bbaSPaul Durrant }; 1281108f7bbaSPaul Durrant 1282108f7bbaSPaul Durrant typedef struct XenBridge { 1283108f7bbaSPaul Durrant SysBusDevice busdev; 1284108f7bbaSPaul Durrant } XenBridge; 1285108f7bbaSPaul Durrant 1286108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge" 1287108f7bbaSPaul Durrant 1288108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = { 1289108f7bbaSPaul Durrant .name = TYPE_XEN_BRIDGE, 1290108f7bbaSPaul Durrant .parent = TYPE_SYS_BUS_DEVICE, 1291108f7bbaSPaul Durrant .instance_size = sizeof(XenBridge), 1292108f7bbaSPaul Durrant }; 1293108f7bbaSPaul Durrant 1294108f7bbaSPaul Durrant static void xen_register_types(void) 1295108f7bbaSPaul Durrant { 1296108f7bbaSPaul Durrant type_register_static(&xen_bridge_type_info); 1297108f7bbaSPaul Durrant type_register_static(&xen_bus_type_info); 1298108f7bbaSPaul Durrant type_register_static(&xen_device_type_info); 1299108f7bbaSPaul Durrant } 1300108f7bbaSPaul Durrant 1301108f7bbaSPaul Durrant type_init(xen_register_types) 1302108f7bbaSPaul Durrant 1303108f7bbaSPaul Durrant void xen_bus_init(void) 1304108f7bbaSPaul Durrant { 13053e80f690SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE); 13069388d170SPeter Maydell BusState *bus = qbus_new(TYPE_XEN_BUS, dev, NULL); 1307108f7bbaSPaul Durrant 13083c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 1309cd7c8660SMarkus Armbruster qbus_set_bus_hotplug_handler(bus); 1310108f7bbaSPaul Durrant } 1311