1 /****************************************************************************** 2 * Copyright (C) 2005 XenSource Ltd 3 * 4 * This file may be distributed separately from the Linux kernel, or 5 * incorporated into other software packages, subject to the following license: 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this source file (the "Software"), to deal in the Software without 9 * restriction, including without limitation the rights to use, copy, modify, 10 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 * IN THE SOFTWARE. 24 */ 25 26 /** 27 * \file xenbus.c 28 * 29 * \brief Client-facing interface for the Xenbus driver. 30 * 31 * In other words, the interface between the Xenbus and the device-specific 32 * code, be it the frontend or the backend of that driver. 33 */ 34 35 #if 0 36 #define DPRINTK(fmt, args...) \ 37 printk("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) 38 #else 39 #define DPRINTK(fmt, args...) ((void)0) 40 #endif 41 42 #include <sys/cdefs.h> 43 44 #include <sys/param.h> 45 #include <sys/kernel.h> 46 #include <sys/types.h> 47 #include <sys/malloc.h> 48 #include <sys/libkern.h> 49 #include <sys/sbuf.h> 50 51 #include <xen/xen-os.h> 52 #include <xen/hypervisor.h> 53 #include <xen/evtchn.h> 54 #include <xen/gnttab.h> 55 #include <xen/xenbus/xenbusvar.h> 56 57 #include <machine/stdarg.h> 58 59 MALLOC_DEFINE(M_XENBUS, "xenbus", "XenBus Support"); 60 61 /*------------------------- Private Functions --------------------------------*/ 62 /** 63 * \brief Construct the error path corresponding to the given XenBus 64 * device. 65 * 66 * \param dev The XenBus device for which we are constructing an error path. 67 * 68 * \return On success, the contructed error path. Otherwise NULL. 69 * 70 * It is the caller's responsibility to free any returned error path 71 * node using the M_XENBUS malloc type. 72 */ 73 static char * 74 error_path(device_t dev) 75 { 76 char *path_buffer = malloc(strlen("error/") 77 + strlen(xenbus_get_node(dev)) + 1,M_XENBUS, M_WAITOK); 78 79 strcpy(path_buffer, "error/"); 80 strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); 81 82 return (path_buffer); 83 } 84 85 /*--------------------------- Public Functions -------------------------------*/ 86 /*-------- API comments for these methods can be found in xenbusvar.h --------*/ 87 const char * 88 xenbus_strstate(XenbusState state) 89 { 90 static const char *const name[] = { 91 [ XenbusStateUnknown ] = "Unknown", 92 [ XenbusStateInitialising ] = "Initialising", 93 [ XenbusStateInitWait ] = "InitWait", 94 [ XenbusStateInitialised ] = "Initialised", 95 [ XenbusStateConnected ] = "Connected", 96 [ XenbusStateClosing ] = "Closing", 97 [ XenbusStateClosed ] = "Closed", 98 }; 99 100 return ((state < (XenbusStateClosed + 1)) ? name[state] : "INVALID"); 101 } 102 103 void 104 xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap) 105 { 106 int ret __diagused; 107 unsigned int len; 108 char *printf_buffer = NULL, *path_buffer = NULL; 109 110 #define PRINTF_BUFFER_SIZE 4096 111 printf_buffer = malloc(PRINTF_BUFFER_SIZE,M_XENBUS, M_WAITOK); 112 113 len = sprintf(printf_buffer, "%i ", err); 114 ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); 115 116 KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big")); 117 device_printf(dev, "Error %s\n", printf_buffer); 118 path_buffer = error_path(dev); 119 120 if (path_buffer == NULL) { 121 printf("xenbus: failed to write error node for %s (%s)\n", 122 xenbus_get_node(dev), printf_buffer); 123 goto fail; 124 } 125 126 if (xs_write(XST_NIL, path_buffer, "error", printf_buffer) != 0) { 127 printf("xenbus: failed to write error node for %s (%s)\n", 128 xenbus_get_node(dev), printf_buffer); 129 goto fail; 130 } 131 132 fail: 133 if (printf_buffer) 134 free(printf_buffer,M_XENBUS); 135 if (path_buffer) 136 free(path_buffer,M_XENBUS); 137 } 138 139 void 140 xenbus_dev_error(device_t dev, int err, const char *fmt, ...) 141 { 142 va_list ap; 143 144 va_start(ap, fmt); 145 xenbus_dev_verror(dev, err, fmt, ap); 146 va_end(ap); 147 } 148 149 void 150 xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list ap) 151 { 152 xenbus_dev_verror(dev, err, fmt, ap); 153 device_printf(dev, "Fatal error. Transitioning to Closing State\n"); 154 xenbus_set_state(dev, XenbusStateClosing); 155 } 156 157 void 158 xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) 159 { 160 va_list ap; 161 162 va_start(ap, fmt); 163 xenbus_dev_vfatal(dev, err, fmt, ap); 164 va_end(ap); 165 } 166 167 int 168 xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp) 169 { 170 int error; 171 172 error = gnttab_grant_foreign_access( 173 xenbus_get_otherend_id(dev), ring_mfn, 0, refp); 174 if (error) { 175 xenbus_dev_fatal(dev, error, "granting access to ring page"); 176 return (error); 177 } 178 179 return (0); 180 } 181 182 XenbusState 183 xenbus_read_driver_state(const char *path) 184 { 185 XenbusState result; 186 int error; 187 188 error = xs_gather(XST_NIL, path, "state", "%d", &result, NULL); 189 if (error) 190 result = XenbusStateClosed; 191 192 return (result); 193 } 194 195 int 196 xenbus_dev_is_online(device_t dev) 197 { 198 const char *path; 199 int error; 200 int value; 201 202 path = xenbus_get_node(dev); 203 error = xs_gather(XST_NIL, path, "online", "%d", &value, NULL); 204 if (error != 0) { 205 /* Default to not online. */ 206 value = 0; 207 } 208 209 return (value); 210 } 211 212 void 213 xenbus_localend_changed(device_t dev, const char *path) 214 { 215 } 216