1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev 22843e1988Sjohnlev /* 23843e1988Sjohnlev * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24843e1988Sjohnlev * Use is subject to license terms. 25843e1988Sjohnlev */ 26843e1988Sjohnlev 27843e1988Sjohnlev /* 28843e1988Sjohnlev * Client-facing interface for the Xenbus driver. In other words, the 29843e1988Sjohnlev * interface between the Xenbus and the device-specific code, be it the 30843e1988Sjohnlev * frontend or the backend of that driver. 31843e1988Sjohnlev * 32843e1988Sjohnlev * Copyright (C) 2005 XenSource Ltd 33843e1988Sjohnlev * 34843e1988Sjohnlev * This file may be distributed separately from the Linux kernel, or 35843e1988Sjohnlev * incorporated into other software packages, subject to the following license: 36843e1988Sjohnlev * 37843e1988Sjohnlev * Permission is hereby granted, free of charge, to any person obtaining a copy 38843e1988Sjohnlev * of this source file (the "Software"), to deal in the Software without 39843e1988Sjohnlev * restriction, including without limitation the rights to use, copy, modify, 40843e1988Sjohnlev * merge, publish, distribute, sublicense, and/or sell copies of the Software, 41843e1988Sjohnlev * and to permit persons to whom the Software is furnished to do so, subject to 42843e1988Sjohnlev * the following conditions: 43843e1988Sjohnlev * 44843e1988Sjohnlev * The above copyright notice and this permission notice shall be included in 45843e1988Sjohnlev * all copies or substantial portions of the Software. 46843e1988Sjohnlev * 47843e1988Sjohnlev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 48843e1988Sjohnlev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 49843e1988Sjohnlev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 50843e1988Sjohnlev * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 51843e1988Sjohnlev * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 52843e1988Sjohnlev * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 53843e1988Sjohnlev * IN THE SOFTWARE. 54843e1988Sjohnlev */ 55843e1988Sjohnlev 56843e1988Sjohnlev #pragma ident "%Z%%M% %I% %E% SMI" 57843e1988Sjohnlev 58*551bc2a6Smrj #ifdef XPV_HVM_DRIVER 59*551bc2a6Smrj #include <sys/xpv_support.h> 60*551bc2a6Smrj #include <sys/hypervisor.h> 61*551bc2a6Smrj #else 62843e1988Sjohnlev #include <sys/hypervisor.h> 63843e1988Sjohnlev #include <sys/xen_mmu.h> 64843e1988Sjohnlev #include <sys/evtchn_impl.h> 65*551bc2a6Smrj #endif 66843e1988Sjohnlev #include <sys/gnttab.h> 67843e1988Sjohnlev #include <xen/sys/xenbus_impl.h> 68843e1988Sjohnlev #include <sys/cmn_err.h> 69843e1988Sjohnlev 70843e1988Sjohnlev 71843e1988Sjohnlev int 72843e1988Sjohnlev xenbus_watch_path(struct xenbus_device *dev, const char *path, 73843e1988Sjohnlev struct xenbus_watch *watch, 74843e1988Sjohnlev void (*callback)(struct xenbus_watch *, 75843e1988Sjohnlev const char **, unsigned int)) 76843e1988Sjohnlev { 77843e1988Sjohnlev int err; 78843e1988Sjohnlev 79843e1988Sjohnlev watch->node = path; 80843e1988Sjohnlev watch->callback = callback; 81843e1988Sjohnlev 82843e1988Sjohnlev err = register_xenbus_watch(watch); 83843e1988Sjohnlev 84843e1988Sjohnlev if (err) { 85843e1988Sjohnlev watch->node = NULL; 86843e1988Sjohnlev watch->callback = NULL; 87843e1988Sjohnlev xenbus_dev_fatal(dev, err, "adding watch on %s", path); 88843e1988Sjohnlev } 89843e1988Sjohnlev 90843e1988Sjohnlev return (err); 91843e1988Sjohnlev } 92843e1988Sjohnlev 93843e1988Sjohnlev 94843e1988Sjohnlev int 95843e1988Sjohnlev xenbus_watch_path2(struct xenbus_device *dev, const char *path, 96843e1988Sjohnlev const char *path2, struct xenbus_watch *watch, 97843e1988Sjohnlev void (*callback)(struct xenbus_watch *, 98843e1988Sjohnlev const char **, unsigned int)) 99843e1988Sjohnlev { 100843e1988Sjohnlev int err; 101843e1988Sjohnlev char *state; 102843e1988Sjohnlev 103843e1988Sjohnlev state = kmem_alloc(strlen(path) + 1 + strlen(path2) + 1, KM_SLEEP); 104843e1988Sjohnlev (void) strcpy(state, path); 105843e1988Sjohnlev (void) strcat(state, "/"); 106843e1988Sjohnlev (void) strcat(state, path2); 107843e1988Sjohnlev 108843e1988Sjohnlev err = xenbus_watch_path(dev, state, watch, callback); 109843e1988Sjohnlev if (err) 110843e1988Sjohnlev kmem_free(state, strlen(state) + 1); 111843e1988Sjohnlev return (err); 112843e1988Sjohnlev } 113843e1988Sjohnlev 114843e1988Sjohnlev /* 115843e1988Sjohnlev * Returns 0 on success, -1 if no change was made, or an errno on failure. We 116843e1988Sjohnlev * check whether the state is currently set to the given value, and if not, 117843e1988Sjohnlev * then the state is set. We don't want to unconditionally write the given 118843e1988Sjohnlev * state, because we don't want to fire watches unnecessarily. Furthermore, if 119843e1988Sjohnlev * the node has gone, we don't write to it, as the device will be tearing down, 120843e1988Sjohnlev * and we don't want to resurrect that directory. 121843e1988Sjohnlev * 122843e1988Sjohnlev * XXPV: not clear that this is still safe if two threads are racing to update 123843e1988Sjohnlev * the state? 124843e1988Sjohnlev */ 125843e1988Sjohnlev int 126843e1988Sjohnlev xenbus_switch_state(struct xenbus_device *dev, xenbus_transaction_t xbt, 127843e1988Sjohnlev XenbusState state) 128843e1988Sjohnlev { 129843e1988Sjohnlev int current_state; 130843e1988Sjohnlev int err; 131843e1988Sjohnlev 132843e1988Sjohnlev err = xenbus_scanf(xbt, dev->nodename, "state", "%d", ¤t_state); 133843e1988Sjohnlev 134843e1988Sjohnlev /* XXPV: is this really the right thing to do? */ 135843e1988Sjohnlev if (err == ENOENT) 136843e1988Sjohnlev return (0); 137843e1988Sjohnlev if (err) 138843e1988Sjohnlev return (err); 139843e1988Sjohnlev 140843e1988Sjohnlev err = -1; 141843e1988Sjohnlev 142843e1988Sjohnlev if ((XenbusState)current_state != state) { 143843e1988Sjohnlev err = xenbus_printf(xbt, dev->nodename, "state", "%d", state); 144843e1988Sjohnlev if (err) 145843e1988Sjohnlev xenbus_dev_fatal(dev, err, "writing new state"); 146843e1988Sjohnlev } 147843e1988Sjohnlev 148843e1988Sjohnlev return (err); 149843e1988Sjohnlev } 150843e1988Sjohnlev 151843e1988Sjohnlev 152843e1988Sjohnlev /* 153843e1988Sjohnlev * Return the path to the error node for the given device, or NULL on failure. 154843e1988Sjohnlev * If the value returned is non-NULL, then it is the caller's to kmem_free. 155843e1988Sjohnlev */ 156843e1988Sjohnlev static char * 157843e1988Sjohnlev error_path(struct xenbus_device *dev) 158843e1988Sjohnlev { 159843e1988Sjohnlev char *path_buffer; 160843e1988Sjohnlev 161843e1988Sjohnlev path_buffer = kmem_alloc(strlen("error/") + strlen(dev->nodename) + 162843e1988Sjohnlev 1, KM_SLEEP); 163843e1988Sjohnlev 164843e1988Sjohnlev (void) strcpy(path_buffer, "error/"); 165843e1988Sjohnlev (void) strcpy(path_buffer + strlen("error/"), dev->nodename); 166843e1988Sjohnlev 167843e1988Sjohnlev return (path_buffer); 168843e1988Sjohnlev } 169843e1988Sjohnlev 170843e1988Sjohnlev static void 171843e1988Sjohnlev common_dev_error(struct xenbus_device *dev, int err, const char *fmt, 172843e1988Sjohnlev va_list ap) 173843e1988Sjohnlev { 174843e1988Sjohnlev int ret; 175843e1988Sjohnlev unsigned int len; 176843e1988Sjohnlev char *printf_buffer = NULL, *path_buffer = NULL; 177843e1988Sjohnlev 178843e1988Sjohnlev #define PRINTF_BUFFER_SIZE 4096 179843e1988Sjohnlev printf_buffer = kmem_alloc(PRINTF_BUFFER_SIZE, KM_SLEEP); 180843e1988Sjohnlev 181843e1988Sjohnlev (void) snprintf(printf_buffer, PRINTF_BUFFER_SIZE, "%d ", err); 182843e1988Sjohnlev len = strlen(printf_buffer); 183843e1988Sjohnlev ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); 184843e1988Sjohnlev 185843e1988Sjohnlev ASSERT(len + ret <= PRINTF_BUFFER_SIZE-1); 186843e1988Sjohnlev dev->has_error = 1; 187843e1988Sjohnlev 188843e1988Sjohnlev path_buffer = error_path(dev); 189843e1988Sjohnlev 190843e1988Sjohnlev if (path_buffer == NULL) { 191843e1988Sjohnlev printf("xenbus: failed to write error node for %s (%s)\n", 192843e1988Sjohnlev dev->nodename, printf_buffer); 193843e1988Sjohnlev goto fail; 194843e1988Sjohnlev } 195843e1988Sjohnlev 196843e1988Sjohnlev if (xenbus_write(NULL, path_buffer, "error", printf_buffer) != 0) { 197843e1988Sjohnlev printf("xenbus: failed to write error node for %s (%s)\n", 198843e1988Sjohnlev dev->nodename, printf_buffer); 199843e1988Sjohnlev goto fail; 200843e1988Sjohnlev } 201843e1988Sjohnlev 202843e1988Sjohnlev fail: 203843e1988Sjohnlev if (printf_buffer) 204843e1988Sjohnlev kmem_free(printf_buffer, PRINTF_BUFFER_SIZE); 205843e1988Sjohnlev if (path_buffer) 206843e1988Sjohnlev kmem_free(path_buffer, strlen(path_buffer) + 1); 207843e1988Sjohnlev } 208843e1988Sjohnlev 209843e1988Sjohnlev 210843e1988Sjohnlev void 211843e1988Sjohnlev xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) 212843e1988Sjohnlev { 213843e1988Sjohnlev va_list ap; 214843e1988Sjohnlev 215843e1988Sjohnlev va_start(ap, fmt); 216843e1988Sjohnlev common_dev_error(dev, err, fmt, ap); 217843e1988Sjohnlev va_end(ap); 218843e1988Sjohnlev } 219843e1988Sjohnlev 220843e1988Sjohnlev 221843e1988Sjohnlev void 222843e1988Sjohnlev xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...) 223843e1988Sjohnlev { 224843e1988Sjohnlev va_list ap; 225843e1988Sjohnlev 226843e1988Sjohnlev va_start(ap, fmt); 227843e1988Sjohnlev common_dev_error(dev, err, fmt, ap); 228843e1988Sjohnlev va_end(ap); 229843e1988Sjohnlev 230843e1988Sjohnlev (void) xenbus_switch_state(dev, XBT_NULL, XenbusStateClosing); 231843e1988Sjohnlev } 232843e1988Sjohnlev 233843e1988Sjohnlev /* Clear any error. */ 234843e1988Sjohnlev void 235843e1988Sjohnlev xenbus_dev_ok(struct xenbus_device *dev) 236843e1988Sjohnlev { 237843e1988Sjohnlev if (dev->has_error) { 238843e1988Sjohnlev if (xenbus_rm(NULL, dev->nodename, "error") != 0) 239843e1988Sjohnlev printf("xenbus: failed to clear error node for %s\n", 240843e1988Sjohnlev dev->nodename); 241843e1988Sjohnlev else 242843e1988Sjohnlev dev->has_error = 0; 243843e1988Sjohnlev } 244843e1988Sjohnlev } 245843e1988Sjohnlev 246843e1988Sjohnlev int 247843e1988Sjohnlev xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) 248843e1988Sjohnlev { 249843e1988Sjohnlev int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); 250843e1988Sjohnlev if (err < 0) 251843e1988Sjohnlev xenbus_dev_fatal(dev, err, "granting access to ring page"); 252843e1988Sjohnlev return (err); 253843e1988Sjohnlev } 254843e1988Sjohnlev 255843e1988Sjohnlev 256843e1988Sjohnlev int 257843e1988Sjohnlev xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) 258843e1988Sjohnlev { 259843e1988Sjohnlev int err; 260843e1988Sjohnlev 261843e1988Sjohnlev err = xen_alloc_unbound_evtchn(dev->otherend_id, port); 262843e1988Sjohnlev if (err) 263843e1988Sjohnlev xenbus_dev_fatal(dev, err, "allocating event channel"); 264843e1988Sjohnlev return (err); 265843e1988Sjohnlev } 266843e1988Sjohnlev 267843e1988Sjohnlev 268843e1988Sjohnlev XenbusState 269843e1988Sjohnlev xenbus_read_driver_state(const char *path) 270843e1988Sjohnlev { 271843e1988Sjohnlev XenbusState result; 272843e1988Sjohnlev 273843e1988Sjohnlev int err = xenbus_gather(XBT_NULL, path, "state", "%d", &result, NULL); 274843e1988Sjohnlev if (err) 275843e1988Sjohnlev result = XenbusStateClosed; 276843e1988Sjohnlev 277843e1988Sjohnlev return (result); 278843e1988Sjohnlev } 279843e1988Sjohnlev 280843e1988Sjohnlev 281843e1988Sjohnlev /* 282843e1988Sjohnlev * Local variables: 283843e1988Sjohnlev * c-file-style: "solaris" 284843e1988Sjohnlev * indent-tabs-mode: t 285843e1988Sjohnlev * c-indent-level: 8 286843e1988Sjohnlev * c-basic-offset: 8 287843e1988Sjohnlev * tab-width: 8 288843e1988Sjohnlev * End: 289843e1988Sjohnlev */ 290