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 __FBSDID("$FreeBSD$"); 44 45 #include <sys/cdefs.h> 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/types.h> 49 #include <sys/malloc.h> 50 #include <sys/libkern.h> 51 #include <sys/sbuf.h> 52 53 #include <machine/xen/xen-os.h> 54 #include <xen/hypervisor.h> 55 #include <xen/evtchn.h> 56 #include <xen/gnttab.h> 57 #include <xen/xenbus/xenbusvar.h> 58 #include <machine/stdarg.h> 59 60 MALLOC_DEFINE(M_XENBUS, "xenbus", "XenBus Support"); 61 62 /*------------------------- Private Functions --------------------------------*/ 63 /** 64 * \brief Construct the error path corresponding to the given XenBus 65 * device. 66 * 67 * \param dev The XenBus device for which we are constructing an error path. 68 * 69 * \return On success, the contructed error path. Otherwise NULL. 70 * 71 * It is the caller's responsibility to free any returned error path 72 * node using the M_XENBUS malloc type. 73 */ 74 static char * 75 error_path(device_t dev) 76 { 77 char *path_buffer = malloc(strlen("error/") 78 + strlen(xenbus_get_node(dev)) + 1,M_XENBUS, M_WAITOK); 79 80 strcpy(path_buffer, "error/"); 81 strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); 82 83 return (path_buffer); 84 } 85 86 /*--------------------------- Public Functions -------------------------------*/ 87 /*-------- API comments for these methods can be found in xenbusvar.h --------*/ 88 const char * 89 xenbus_strstate(XenbusState state) 90 { 91 static const char *const name[] = { 92 [ XenbusStateUnknown ] = "Unknown", 93 [ XenbusStateInitialising ] = "Initialising", 94 [ XenbusStateInitWait ] = "InitWait", 95 [ XenbusStateInitialised ] = "Initialised", 96 [ XenbusStateConnected ] = "Connected", 97 [ XenbusStateClosing ] = "Closing", 98 [ XenbusStateClosed ] = "Closed", 99 }; 100 101 return ((state < (XenbusStateClosed + 1)) ? name[state] : "INVALID"); 102 } 103 104 int 105 xenbus_watch_path(device_t dev, char *path, struct xs_watch *watch, 106 xs_watch_cb_t *callback, uintptr_t callback_data) 107 { 108 int error; 109 110 watch->node = path; 111 watch->callback = callback; 112 watch->callback_data = callback_data; 113 114 error = xs_register_watch(watch); 115 116 if (error) { 117 watch->node = NULL; 118 watch->callback = NULL; 119 xenbus_dev_fatal(dev, error, "adding watch on %s", path); 120 } 121 122 return (error); 123 } 124 125 int 126 xenbus_watch_path2(device_t dev, const char *path, 127 const char *path2, struct xs_watch *watch, 128 xs_watch_cb_t *callback, uintptr_t callback_data) 129 { 130 int error; 131 char *state = malloc(strlen(path) + 1 + strlen(path2) + 1, 132 M_XENBUS, M_WAITOK); 133 134 strcpy(state, path); 135 strcat(state, "/"); 136 strcat(state, path2); 137 138 error = xenbus_watch_path(dev, state, watch, callback, callback_data); 139 if (error) { 140 free(state,M_XENBUS); 141 } 142 143 return (error); 144 } 145 146 void 147 xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap) 148 { 149 int ret; 150 unsigned int len; 151 char *printf_buffer = NULL, *path_buffer = NULL; 152 153 #define PRINTF_BUFFER_SIZE 4096 154 printf_buffer = malloc(PRINTF_BUFFER_SIZE,M_XENBUS, M_WAITOK); 155 156 len = sprintf(printf_buffer, "%i ", err); 157 ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); 158 159 KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big")); 160 device_printf(dev, "Error %s\n", printf_buffer); 161 path_buffer = error_path(dev); 162 163 if (path_buffer == NULL) { 164 printf("xenbus: failed to write error node for %s (%s)\n", 165 xenbus_get_node(dev), printf_buffer); 166 goto fail; 167 } 168 169 if (xs_write(XST_NIL, path_buffer, "error", printf_buffer) != 0) { 170 printf("xenbus: failed to write error node for %s (%s)\n", 171 xenbus_get_node(dev), printf_buffer); 172 goto fail; 173 } 174 175 fail: 176 if (printf_buffer) 177 free(printf_buffer,M_XENBUS); 178 if (path_buffer) 179 free(path_buffer,M_XENBUS); 180 } 181 182 void 183 xenbus_dev_error(device_t dev, int err, const char *fmt, ...) 184 { 185 va_list ap; 186 187 va_start(ap, fmt); 188 xenbus_dev_verror(dev, err, fmt, ap); 189 va_end(ap); 190 } 191 192 void 193 xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list ap) 194 { 195 xenbus_dev_verror(dev, err, fmt, ap); 196 device_printf(dev, "Fatal error. Transitioning to Closing State\n"); 197 xenbus_set_state(dev, XenbusStateClosing); 198 } 199 200 void 201 xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) 202 { 203 va_list ap; 204 205 va_start(ap, fmt); 206 xenbus_dev_vfatal(dev, err, fmt, ap); 207 va_end(ap); 208 } 209 210 int 211 xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp) 212 { 213 int error; 214 215 error = gnttab_grant_foreign_access( 216 xenbus_get_otherend_id(dev), ring_mfn, 0, refp); 217 if (error) { 218 xenbus_dev_fatal(dev, error, "granting access to ring page"); 219 return (error); 220 } 221 222 return (0); 223 } 224 225 int 226 xenbus_alloc_evtchn(device_t dev, evtchn_port_t *port) 227 { 228 struct evtchn_alloc_unbound alloc_unbound; 229 int err; 230 231 alloc_unbound.dom = DOMID_SELF; 232 alloc_unbound.remote_dom = xenbus_get_otherend_id(dev); 233 234 err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, 235 &alloc_unbound); 236 237 if (err) { 238 xenbus_dev_fatal(dev, -err, "allocating event channel"); 239 return (-err); 240 } 241 *port = alloc_unbound.port; 242 return (0); 243 } 244 245 int 246 xenbus_free_evtchn(device_t dev, evtchn_port_t port) 247 { 248 struct evtchn_close close; 249 int err; 250 251 close.port = port; 252 253 err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); 254 if (err) { 255 xenbus_dev_error(dev, -err, "freeing event channel %d", port); 256 return (-err); 257 } 258 return (0); 259 } 260 261 XenbusState 262 xenbus_read_driver_state(const char *path) 263 { 264 XenbusState result; 265 int error; 266 267 error = xs_gather(XST_NIL, path, "state", "%d", &result, NULL); 268 if (error) 269 result = XenbusStateClosed; 270 271 return (result); 272 } 273 274 int 275 xenbus_dev_is_online(device_t dev) 276 { 277 const char *path; 278 int error; 279 int value; 280 281 path = xenbus_get_node(dev); 282 error = xs_gather(XST_NIL, path, "online", "%d", &value, NULL); 283 if (error != 0) { 284 /* Default to not online. */ 285 value = 0; 286 } 287 288 return (value); 289 } 290 291 void 292 xenbus_localend_changed(device_t dev, const char *path) 293 { 294 } 295