1 5084 johnlev /* 2 5084 johnlev * CDDL HEADER START 3 5084 johnlev * 4 5084 johnlev * The contents of this file are subject to the terms of the 5 5084 johnlev * Common Development and Distribution License (the "License"). 6 5084 johnlev * You may not use this file except in compliance with the License. 7 5084 johnlev * 8 5084 johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 5084 johnlev * or http://www.opensolaris.org/os/licensing. 10 5084 johnlev * See the License for the specific language governing permissions 11 5084 johnlev * and limitations under the License. 12 5084 johnlev * 13 5084 johnlev * When distributing Covered Code, include this CDDL HEADER in each 14 5084 johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 5084 johnlev * If applicable, add the following below this CDDL HEADER, with the 16 5084 johnlev * fields enclosed by brackets "[]" replaced with your own identifying 17 5084 johnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18 5084 johnlev * 19 5084 johnlev * CDDL HEADER END 20 5084 johnlev */ 21 5084 johnlev 22 5084 johnlev /* 23 8863 Edward * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 5084 johnlev * Use is subject to license terms. 25 5084 johnlev */ 26 5084 johnlev 27 5084 johnlev /* 28 5084 johnlev * Xen virtual device driver interfaces 29 5084 johnlev */ 30 5084 johnlev 31 5084 johnlev /* 32 5084 johnlev * todo: 33 5084 johnlev * + name space clean up: 34 5084 johnlev * xvdi_* - public xen interfaces, for use by all leaf drivers 35 5084 johnlev * xd_* - public xen data structures 36 5084 johnlev * i_xvdi_* - implementation private functions 37 5084 johnlev * xendev_* - xendev driver interfaces, both internal and in cb_ops/bus_ops 38 5084 johnlev * + add mdb dcmds to dump ring status 39 5084 johnlev * + implement xvdi_xxx to wrap xenbus_xxx read/write function 40 5084 johnlev * + convert (xendev_ring_t *) into xvdi_ring_handle_t 41 5084 johnlev */ 42 5084 johnlev #include <sys/conf.h> 43 5084 johnlev #include <sys/param.h> 44 5084 johnlev #include <sys/kmem.h> 45 5084 johnlev #include <vm/seg_kmem.h> 46 5084 johnlev #include <sys/debug.h> 47 5084 johnlev #include <sys/modctl.h> 48 5084 johnlev #include <sys/autoconf.h> 49 5084 johnlev #include <sys/ddi_impldefs.h> 50 5084 johnlev #include <sys/ddi_subrdefs.h> 51 5084 johnlev #include <sys/ddi.h> 52 5084 johnlev #include <sys/sunddi.h> 53 5084 johnlev #include <sys/sunndi.h> 54 5084 johnlev #include <sys/sunldi.h> 55 5084 johnlev #include <sys/fs/dv_node.h> 56 5084 johnlev #include <sys/avintr.h> 57 5084 johnlev #include <sys/psm.h> 58 5084 johnlev #include <sys/spl.h> 59 5084 johnlev #include <sys/promif.h> 60 5084 johnlev #include <sys/list.h> 61 5084 johnlev #include <sys/bootconf.h> 62 5084 johnlev #include <sys/bootsvcs.h> 63 5084 johnlev #include <sys/bootinfo.h> 64 5084 johnlev #include <sys/note.h> 65 8863 Edward #include <sys/sysmacros.h> 66 5741 mrj #ifdef XPV_HVM_DRIVER 67 5741 mrj #include <sys/xpv_support.h> 68 5741 mrj #include <sys/hypervisor.h> 69 5741 mrj #include <public/grant_table.h> 70 5741 mrj #include <public/xen.h> 71 5741 mrj #include <public/io/xenbus.h> 72 5741 mrj #include <public/io/xs_wire.h> 73 5741 mrj #include <public/event_channel.h> 74 5741 mrj #include <public/io/xenbus.h> 75 5741 mrj #else /* XPV_HVM_DRIVER */ 76 5741 mrj #include <sys/hypervisor.h> 77 5084 johnlev #include <sys/xen_mmu.h> 78 5084 johnlev #include <xen/sys/xenbus_impl.h> 79 5741 mrj #include <sys/evtchn_impl.h> 80 5741 mrj #endif /* XPV_HVM_DRIVER */ 81 5741 mrj #include <sys/gnttab.h> 82 5084 johnlev #include <xen/sys/xendev.h> 83 5084 johnlev #include <vm/hat_i86.h> 84 5084 johnlev #include <sys/scsi/generic/inquiry.h> 85 5084 johnlev #include <util/sscanf.h> 86 5084 johnlev #include <xen/public/io/xs_wire.h> 87 5084 johnlev 88 6318 edp 89 6318 edp #define isdigit(ch) ((ch) >= '0' && (ch) <= '9') 90 6318 edp #define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \ 91 6318 edp ((ch) >= 'A' && (ch) <= 'F')) 92 5084 johnlev 93 5084 johnlev static void xvdi_ring_init_sring(xendev_ring_t *); 94 5084 johnlev static void xvdi_ring_init_front_ring(xendev_ring_t *, size_t, size_t); 95 5741 mrj #ifndef XPV_HVM_DRIVER 96 5084 johnlev static void xvdi_ring_init_back_ring(xendev_ring_t *, size_t, size_t); 97 5741 mrj #endif 98 5084 johnlev static void xvdi_reinit_ring(dev_info_t *, grant_ref_t *, xendev_ring_t *); 99 5084 johnlev 100 5084 johnlev static int i_xvdi_add_watches(dev_info_t *); 101 5084 johnlev static void i_xvdi_rem_watches(dev_info_t *); 102 5084 johnlev 103 5084 johnlev static int i_xvdi_add_watch_oestate(dev_info_t *); 104 5084 johnlev static void i_xvdi_rem_watch_oestate(dev_info_t *); 105 5084 johnlev static void i_xvdi_oestate_cb(struct xenbus_device *, XenbusState); 106 5084 johnlev static void i_xvdi_oestate_handler(void *); 107 5084 johnlev 108 5084 johnlev static int i_xvdi_add_watch_hpstate(dev_info_t *); 109 5084 johnlev static void i_xvdi_rem_watch_hpstate(dev_info_t *); 110 5084 johnlev static void i_xvdi_hpstate_cb(struct xenbus_watch *, const char **, 111 5084 johnlev unsigned int); 112 5084 johnlev static void i_xvdi_hpstate_handler(void *); 113 5084 johnlev 114 5084 johnlev static int i_xvdi_add_watch_bepath(dev_info_t *); 115 5084 johnlev static void i_xvdi_rem_watch_bepath(dev_info_t *); 116 5084 johnlev static void i_xvdi_bepath_cb(struct xenbus_watch *, const char **, 117 5084 johnlev unsigned in); 118 5084 johnlev 119 5084 johnlev static void xendev_offline_device(void *); 120 5084 johnlev 121 5084 johnlev static void i_xvdi_probe_path_cb(struct xenbus_watch *, const char **, 122 5084 johnlev unsigned int); 123 5084 johnlev static void i_xvdi_probe_path_handler(void *); 124 7679 Max 125 7679 Max typedef struct oestate_evt { 126 7679 Max dev_info_t *dip; 127 7679 Max XenbusState state; 128 7679 Max } i_oestate_evt_t; 129 5084 johnlev 130 5084 johnlev typedef struct xd_cfg { 131 5084 johnlev xendev_devclass_t devclass; 132 5084 johnlev char *xsdev; 133 5084 johnlev char *xs_path_fe; 134 5084 johnlev char *xs_path_be; 135 5084 johnlev char *node_fe; 136 5084 johnlev char *node_be; 137 5084 johnlev char *device_type; 138 5084 johnlev int xd_ipl; 139 5084 johnlev int flags; 140 5084 johnlev } i_xd_cfg_t; 141 5084 johnlev 142 5084 johnlev #define XD_DOM_ZERO 0x01 /* dom0 only. */ 143 5084 johnlev #define XD_DOM_GUEST 0x02 /* Guest domains (i.e. non-dom0). */ 144 5084 johnlev #define XD_DOM_IO 0x04 /* IO domains. */ 145 5084 johnlev 146 5084 johnlev #define XD_DOM_ALL (XD_DOM_ZERO | XD_DOM_GUEST) 147 5084 johnlev 148 5084 johnlev static i_xd_cfg_t xdci[] = { 149 5084 johnlev { XEN_CONSOLE, NULL, NULL, NULL, "xencons", NULL, 150 5084 johnlev "console", IPL_CONS, XD_DOM_ALL, }, 151 5084 johnlev 152 5084 johnlev { XEN_VNET, "vif", "device/vif", "backend/vif", "xnf", "xnb", 153 5084 johnlev "network", IPL_VIF, XD_DOM_ALL, }, 154 5084 johnlev 155 5084 johnlev { XEN_VBLK, "vbd", "device/vbd", "backend/vbd", "xdf", "xdb", 156 7756 Mark "block", IPL_VBD, XD_DOM_ALL, }, 157 7756 Mark 158 7756 Mark { XEN_BLKTAP, "tap", NULL, "backend/tap", NULL, "xpvtap", 159 5084 johnlev "block", IPL_VBD, XD_DOM_ALL, }, 160 5084 johnlev 161 5084 johnlev { XEN_XENBUS, NULL, NULL, NULL, "xenbus", NULL, 162 5084 johnlev NULL, 0, XD_DOM_ALL, }, 163 5084 johnlev 164 5084 johnlev { XEN_DOMCAPS, NULL, NULL, NULL, "domcaps", NULL, 165 5084 johnlev NULL, 0, XD_DOM_ALL, }, 166 5084 johnlev 167 5084 johnlev { XEN_BALLOON, NULL, NULL, NULL, "balloon", NULL, 168 5084 johnlev NULL, 0, XD_DOM_ALL, }, 169 5084 johnlev 170 5084 johnlev { XEN_EVTCHN, NULL, NULL, NULL, "evtchn", NULL, 171 5084 johnlev NULL, 0, XD_DOM_ZERO, }, 172 5084 johnlev 173 5084 johnlev { XEN_PRIVCMD, NULL, NULL, NULL, "privcmd", NULL, 174 5084 johnlev NULL, 0, XD_DOM_ZERO, }, 175 5084 johnlev }; 176 5084 johnlev #define NXDC (sizeof (xdci) / sizeof (xdci[0])) 177 5084 johnlev 178 5084 johnlev static void i_xvdi_enum_fe(dev_info_t *, i_xd_cfg_t *); 179 5084 johnlev static void i_xvdi_enum_be(dev_info_t *, i_xd_cfg_t *); 180 5084 johnlev static void i_xvdi_enum_worker(dev_info_t *, i_xd_cfg_t *, char *); 181 5084 johnlev 182 5084 johnlev /* 183 5084 johnlev * Xen device channel device access and DMA attributes 184 5084 johnlev */ 185 5084 johnlev static ddi_device_acc_attr_t xendev_dc_accattr = { 186 5084 johnlev DDI_DEVICE_ATTR_V0, DDI_NEVERSWAP_ACC, DDI_STRICTORDER_ACC 187 5084 johnlev }; 188 5084 johnlev 189 5084 johnlev static ddi_dma_attr_t xendev_dc_dmaattr = { 190 5084 johnlev DMA_ATTR_V0, /* version of this structure */ 191 5084 johnlev 0, /* lowest usable address */ 192 5084 johnlev 0xffffffffffffffffULL, /* highest usable address */ 193 5084 johnlev 0x7fffffff, /* maximum DMAable byte count */ 194 5084 johnlev MMU_PAGESIZE, /* alignment in bytes */ 195 5084 johnlev 0x7ff, /* bitmap of burst sizes */ 196 5084 johnlev 1, /* minimum transfer */ 197 5084 johnlev 0xffffffffU, /* maximum transfer */ 198 5084 johnlev 0xffffffffffffffffULL, /* maximum segment length */ 199 5084 johnlev 1, /* maximum number of segments */ 200 5084 johnlev 1, /* granularity */ 201 5084 johnlev 0, /* flags (reserved) */ 202 5084 johnlev }; 203 5084 johnlev 204 5084 johnlev static dev_info_t *xendev_dip = NULL; 205 5084 johnlev 206 5084 johnlev #define XVDI_DBG_STATE 0x01 207 5084 johnlev #define XVDI_DBG_PROBE 0x02 208 5084 johnlev 209 5084 johnlev #ifdef DEBUG 210 5316 johnlev int i_xvdi_debug = 0; 211 5084 johnlev 212 5084 johnlev #define XVDI_DPRINTF(flag, format, ...) \ 213 5084 johnlev { \ 214 5084 johnlev if (i_xvdi_debug & (flag)) \ 215 5084 johnlev prom_printf((format), __VA_ARGS__); \ 216 5084 johnlev } 217 5084 johnlev #else 218 5084 johnlev #define XVDI_DPRINTF(flag, format, ...) 219 5084 johnlev #endif /* DEBUG */ 220 5084 johnlev 221 5084 johnlev static i_xd_cfg_t * 222 5084 johnlev i_xvdi_devclass2cfg(xendev_devclass_t devclass) 223 5084 johnlev { 224 5084 johnlev i_xd_cfg_t *xdcp; 225 5084 johnlev int i; 226 5084 johnlev 227 5084 johnlev for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++) 228 5084 johnlev if (xdcp->devclass == devclass) 229 5084 johnlev return (xdcp); 230 5084 johnlev 231 5084 johnlev return (NULL); 232 5084 johnlev } 233 5084 johnlev 234 5084 johnlev int 235 5084 johnlev xvdi_init_dev(dev_info_t *dip) 236 5084 johnlev { 237 5084 johnlev xendev_devclass_t devcls; 238 5084 johnlev int vdevnum; 239 5084 johnlev domid_t domid; 240 5084 johnlev struct xendev_ppd *pdp; 241 5084 johnlev i_xd_cfg_t *xdcp; 242 5084 johnlev boolean_t backend; 243 5084 johnlev char xsnamebuf[TYPICALMAXPATHLEN]; 244 5084 johnlev char *xsname; 245 6500 jhd void *prop_str; 246 6503 jhd unsigned int prop_len; 247 6500 jhd char unitaddr[8]; 248 5084 johnlev 249 5084 johnlev devcls = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 250 5084 johnlev DDI_PROP_DONTPASS, "devclass", XEN_INVAL); 251 5084 johnlev vdevnum = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 252 6175 johnlev DDI_PROP_DONTPASS, "vdev", VDEV_NOXS); 253 5084 johnlev domid = (domid_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 254 5084 johnlev DDI_PROP_DONTPASS, "domain", DOMID_SELF); 255 5084 johnlev 256 5084 johnlev backend = (domid != DOMID_SELF); 257 5084 johnlev xdcp = i_xvdi_devclass2cfg(devcls); 258 5084 johnlev if (xdcp->device_type != NULL) 259 5084 johnlev (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 260 5084 johnlev "device_type", xdcp->device_type); 261 5084 johnlev 262 5084 johnlev pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP); 263 5084 johnlev pdp->xd_domain = domid; 264 5084 johnlev pdp->xd_vdevnum = vdevnum; 265 5084 johnlev pdp->xd_devclass = devcls; 266 5084 johnlev pdp->xd_evtchn = INVALID_EVTCHN; 267 8863 Edward list_create(&pdp->xd_xb_watches, sizeof (xd_xb_watches_t), 268 8863 Edward offsetof(xd_xb_watches_t, xxw_list)); 269 7756 Mark mutex_init(&pdp->xd_evt_lk, NULL, MUTEX_DRIVER, NULL); 270 7756 Mark mutex_init(&pdp->xd_ndi_lk, NULL, MUTEX_DRIVER, NULL); 271 5084 johnlev ddi_set_parent_data(dip, pdp); 272 5084 johnlev 273 5084 johnlev /* 274 5084 johnlev * devices that do not need to interact with xenstore 275 5084 johnlev */ 276 6175 johnlev if (vdevnum == VDEV_NOXS) { 277 5084 johnlev (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 278 5084 johnlev "unit-address", "0"); 279 5084 johnlev if (devcls == XEN_CONSOLE) 280 5084 johnlev (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 281 5084 johnlev "pm-hardware-state", "needs-suspend-resume"); 282 5084 johnlev return (DDI_SUCCESS); 283 5084 johnlev } 284 5084 johnlev 285 5084 johnlev /* 286 5084 johnlev * PV devices that need to probe xenstore 287 5084 johnlev */ 288 5084 johnlev 289 5084 johnlev (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 290 5084 johnlev "pm-hardware-state", "needs-suspend-resume"); 291 5084 johnlev 292 5084 johnlev xsname = xsnamebuf; 293 5084 johnlev if (!backend) 294 5084 johnlev (void) snprintf(xsnamebuf, sizeof (xsnamebuf), 295 5084 johnlev "%s/%d", xdcp->xs_path_fe, vdevnum); 296 5084 johnlev else 297 5084 johnlev (void) snprintf(xsnamebuf, sizeof (xsnamebuf), 298 5084 johnlev "%s/%d/%d", xdcp->xs_path_be, domid, vdevnum); 299 5159 johnlev if ((xenbus_read_driver_state(xsname) >= XenbusStateClosing)) { 300 5159 johnlev /* Don't try to init a dev that may be closing */ 301 7756 Mark mutex_destroy(&pdp->xd_ndi_lk); 302 7756 Mark mutex_destroy(&pdp->xd_evt_lk); 303 5159 johnlev kmem_free(pdp, sizeof (*pdp)); 304 5159 johnlev ddi_set_parent_data(dip, NULL); 305 5159 johnlev return (DDI_FAILURE); 306 5159 johnlev } 307 5084 johnlev 308 5084 johnlev pdp->xd_xsdev.nodename = i_ddi_strdup(xsname, KM_SLEEP); 309 5084 johnlev pdp->xd_xsdev.devicetype = xdcp->xsdev; 310 5084 johnlev pdp->xd_xsdev.frontend = (backend ? 0 : 1); 311 5084 johnlev pdp->xd_xsdev.data = dip; 312 5084 johnlev pdp->xd_xsdev.otherend_id = (backend ? domid : -1); 313 5084 johnlev if (i_xvdi_add_watches(dip) != DDI_SUCCESS) { 314 5084 johnlev cmn_err(CE_WARN, "xvdi_init_dev: " 315 5084 johnlev "cannot add watches for %s", xsname); 316 5084 johnlev xvdi_uninit_dev(dip); 317 5084 johnlev return (DDI_FAILURE); 318 5084 johnlev } 319 5084 johnlev 320 6500 jhd if (backend) 321 6500 jhd return (DDI_SUCCESS); 322 6500 jhd 323 5084 johnlev /* 324 6500 jhd * The unit-address for frontend devices is the name of the 325 6500 jhd * of the xenstore node containing the device configuration 326 6500 jhd * and is contained in the 'vdev' property. 327 6500 jhd * VIF devices are named using an incrementing integer. 328 6500 jhd * VBD devices are either named using the 16-bit dev_t value 329 6500 jhd * for linux 'hd' and 'xvd' devices, or a simple integer value 330 6500 jhd * in the range 0..767. 768 is the base value of the linux 331 6500 jhd * dev_t namespace, the dev_t value for 'hda'. 332 5084 johnlev */ 333 6500 jhd (void) snprintf(unitaddr, sizeof (unitaddr), "%d", vdevnum); 334 6500 jhd (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unit-address", 335 6500 jhd unitaddr); 336 5084 johnlev 337 6500 jhd switch (devcls) { 338 6500 jhd case XEN_VNET: 339 6500 jhd if (xenbus_read(XBT_NULL, xsname, "mac", (void *)&prop_str, 340 6500 jhd &prop_len) != 0) 341 5084 johnlev break; 342 6500 jhd (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "mac", 343 6500 jhd prop_str); 344 6500 jhd kmem_free(prop_str, prop_len); 345 6500 jhd break; 346 6500 jhd case XEN_VBLK: 347 6500 jhd /* 348 6500 jhd * cache a copy of the otherend name 349 6500 jhd * for ease of observeability 350 6500 jhd */ 351 6500 jhd if (xenbus_read(XBT_NULL, pdp->xd_xsdev.otherend, "dev", 352 6500 jhd &prop_str, &prop_len) != 0) 353 5084 johnlev break; 354 6500 jhd (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 355 6500 jhd "dev-address", prop_str); 356 6500 jhd kmem_free(prop_str, prop_len); 357 6500 jhd break; 358 6500 jhd default: 359 6500 jhd break; 360 5084 johnlev } 361 5084 johnlev 362 5084 johnlev return (DDI_SUCCESS); 363 5084 johnlev } 364 5084 johnlev 365 5084 johnlev void 366 5084 johnlev xvdi_uninit_dev(dev_info_t *dip) 367 5084 johnlev { 368 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 369 5084 johnlev 370 5084 johnlev if (pdp != NULL) { 371 5084 johnlev /* Remove any registered callbacks. */ 372 5084 johnlev xvdi_remove_event_handler(dip, NULL); 373 5084 johnlev 374 5084 johnlev /* Remove any registered watches. */ 375 5084 johnlev i_xvdi_rem_watches(dip); 376 5159 johnlev 377 5159 johnlev /* tell other end to close */ 378 5741 mrj if (pdp->xd_xsdev.otherend_id != (domid_t)-1) 379 5741 mrj (void) xvdi_switch_state(dip, XBT_NULL, 380 5741 mrj XenbusStateClosed); 381 5084 johnlev 382 5084 johnlev if (pdp->xd_xsdev.nodename != NULL) 383 5084 johnlev kmem_free((char *)(pdp->xd_xsdev.nodename), 384 5084 johnlev strlen(pdp->xd_xsdev.nodename) + 1); 385 5084 johnlev 386 5084 johnlev ddi_set_parent_data(dip, NULL); 387 5084 johnlev 388 7756 Mark mutex_destroy(&pdp->xd_ndi_lk); 389 7756 Mark mutex_destroy(&pdp->xd_evt_lk); 390 5084 johnlev kmem_free(pdp, sizeof (*pdp)); 391 5084 johnlev } 392 5084 johnlev } 393 5084 johnlev 394 5084 johnlev /* 395 5084 johnlev * Bind the event channel for this device instance. 396 5084 johnlev * Currently we only support one evtchn per device instance. 397 5084 johnlev */ 398 5084 johnlev int 399 5084 johnlev xvdi_bind_evtchn(dev_info_t *dip, evtchn_port_t evtchn) 400 5084 johnlev { 401 5084 johnlev struct xendev_ppd *pdp; 402 5084 johnlev domid_t oeid; 403 5084 johnlev int r; 404 5084 johnlev 405 5084 johnlev pdp = ddi_get_parent_data(dip); 406 5084 johnlev ASSERT(pdp != NULL); 407 5084 johnlev ASSERT(pdp->xd_evtchn == INVALID_EVTCHN); 408 5084 johnlev 409 7756 Mark mutex_enter(&pdp->xd_evt_lk); 410 5084 johnlev if (pdp->xd_devclass == XEN_CONSOLE) { 411 5084 johnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 412 5084 johnlev pdp->xd_evtchn = xen_info->console.domU.evtchn; 413 5084 johnlev } else { 414 5084 johnlev pdp->xd_evtchn = INVALID_EVTCHN; 415 7756 Mark mutex_exit(&pdp->xd_evt_lk); 416 5084 johnlev return (DDI_SUCCESS); 417 5084 johnlev } 418 5084 johnlev } else { 419 5084 johnlev oeid = pdp->xd_xsdev.otherend_id; 420 5084 johnlev if (oeid == (domid_t)-1) { 421 7756 Mark mutex_exit(&pdp->xd_evt_lk); 422 5084 johnlev return (DDI_FAILURE); 423 5084 johnlev } 424 5084 johnlev 425 5084 johnlev if ((r = xen_bind_interdomain(oeid, evtchn, &pdp->xd_evtchn))) { 426 5084 johnlev xvdi_dev_error(dip, r, "bind event channel"); 427 7756 Mark mutex_exit(&pdp->xd_evt_lk); 428 5084 johnlev return (DDI_FAILURE); 429 5084 johnlev } 430 5084 johnlev } 431 5741 mrj #ifndef XPV_HVM_DRIVER 432 5084 johnlev pdp->xd_ispec.intrspec_vec = ec_bind_evtchn_to_irq(pdp->xd_evtchn); 433 5741 mrj #endif 434 7756 Mark mutex_exit(&pdp->xd_evt_lk); 435 5084 johnlev 436 5084 johnlev return (DDI_SUCCESS); 437 5084 johnlev } 438 5084 johnlev 439 5084 johnlev /* 440 5084 johnlev * Allocate an event channel for this device instance. 441 5084 johnlev * Currently we only support one evtchn per device instance. 442 5084 johnlev */ 443 5084 johnlev int 444 5084 johnlev xvdi_alloc_evtchn(dev_info_t *dip) 445 5084 johnlev { 446 5084 johnlev struct xendev_ppd *pdp; 447 5084 johnlev domid_t oeid; 448 5084 johnlev int rv; 449 5084 johnlev 450 5084 johnlev pdp = ddi_get_parent_data(dip); 451 5084 johnlev ASSERT(pdp != NULL); 452 5084 johnlev ASSERT(pdp->xd_evtchn == INVALID_EVTCHN); 453 5084 johnlev 454 7756 Mark mutex_enter(&pdp->xd_evt_lk); 455 5084 johnlev if (pdp->xd_devclass == XEN_CONSOLE) { 456 5084 johnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 457 5084 johnlev pdp->xd_evtchn = xen_info->console.domU.evtchn; 458 5084 johnlev } else { 459 5084 johnlev pdp->xd_evtchn = INVALID_EVTCHN; 460 7756 Mark mutex_exit(&pdp->xd_evt_lk); 461 5084 johnlev return (DDI_SUCCESS); 462 5084 johnlev } 463 5084 johnlev } else { 464 5084 johnlev oeid = pdp->xd_xsdev.otherend_id; 465 5084 johnlev if (oeid == (domid_t)-1) { 466 7756 Mark mutex_exit(&pdp->xd_evt_lk); 467 5084 johnlev return (DDI_FAILURE); 468 5084 johnlev } 469 5084 johnlev 470 5084 johnlev if ((rv = xen_alloc_unbound_evtchn(oeid, &pdp->xd_evtchn))) { 471 5084 johnlev xvdi_dev_error(dip, rv, "bind event channel"); 472 7756 Mark mutex_exit(&pdp->xd_evt_lk); 473 5084 johnlev return (DDI_FAILURE); 474 5084 johnlev } 475 5084 johnlev } 476 5741 mrj #ifndef XPV_HVM_DRIVER 477 5084 johnlev pdp->xd_ispec.intrspec_vec = ec_bind_evtchn_to_irq(pdp->xd_evtchn); 478 5741 mrj #endif 479 7756 Mark mutex_exit(&pdp->xd_evt_lk); 480 5084 johnlev 481 5084 johnlev return (DDI_SUCCESS); 482 5084 johnlev } 483 5084 johnlev 484 5084 johnlev /* 485 5084 johnlev * Unbind the event channel for this device instance. 486 5084 johnlev * Currently we only support one evtchn per device instance. 487 5084 johnlev */ 488 5084 johnlev void 489 5084 johnlev xvdi_free_evtchn(dev_info_t *dip) 490 5084 johnlev { 491 5084 johnlev struct xendev_ppd *pdp; 492 5084 johnlev 493 5084 johnlev pdp = ddi_get_parent_data(dip); 494 5084 johnlev ASSERT(pdp != NULL); 495 5084 johnlev 496 7756 Mark mutex_enter(&pdp->xd_evt_lk); 497 5084 johnlev if (pdp->xd_evtchn != INVALID_EVTCHN) { 498 5741 mrj #ifndef XPV_HVM_DRIVER 499 5084 johnlev ec_unbind_irq(pdp->xd_ispec.intrspec_vec); 500 5741 mrj pdp->xd_ispec.intrspec_vec = 0; 501 5741 mrj #endif 502 5084 johnlev pdp->xd_evtchn = INVALID_EVTCHN; 503 5084 johnlev } 504 7756 Mark mutex_exit(&pdp->xd_evt_lk); 505 5084 johnlev } 506 5084 johnlev 507 5741 mrj #ifndef XPV_HVM_DRIVER 508 5084 johnlev /* 509 5084 johnlev * Map an inter-domain communication ring for a virtual device. 510 5084 johnlev * This is used by backend drivers. 511 5084 johnlev */ 512 5084 johnlev int 513 5084 johnlev xvdi_map_ring(dev_info_t *dip, size_t nentry, size_t entrysize, 514 5084 johnlev grant_ref_t gref, xendev_ring_t **ringpp) 515 5084 johnlev { 516 5084 johnlev domid_t oeid; 517 5084 johnlev gnttab_map_grant_ref_t mapop; 518 5084 johnlev gnttab_unmap_grant_ref_t unmapop; 519 5084 johnlev caddr_t ringva; 520 5084 johnlev ddi_acc_hdl_t *ap; 521 5084 johnlev ddi_acc_impl_t *iap; 522 5084 johnlev xendev_ring_t *ring; 523 5084 johnlev int err; 524 5084 johnlev char errstr[] = "mapping in ring buffer"; 525 5084 johnlev 526 5084 johnlev ring = kmem_zalloc(sizeof (xendev_ring_t), KM_SLEEP); 527 5084 johnlev oeid = xvdi_get_oeid(dip); 528 5084 johnlev 529 5084 johnlev /* alloc va in backend dom for ring buffer */ 530 5084 johnlev ringva = vmem_xalloc(heap_arena, PAGESIZE, PAGESIZE, 531 5084 johnlev 0, 0, 0, 0, VM_SLEEP); 532 5084 johnlev 533 5084 johnlev /* map in ring page */ 534 7756 Mark hat_prepare_mapping(kas.a_hat, ringva, NULL); 535 5084 johnlev mapop.host_addr = (uint64_t)(uintptr_t)ringva; 536 5084 johnlev mapop.flags = GNTMAP_host_map; 537 5084 johnlev mapop.ref = gref; 538 5084 johnlev mapop.dom = oeid; 539 7756 Mark err = xen_map_gref(GNTTABOP_map_grant_ref, &mapop, 1, B_FALSE); 540 5084 johnlev if (err) { 541 5084 johnlev xvdi_fatal_error(dip, err, errstr); 542 5084 johnlev goto errout1; 543 5084 johnlev } 544 5084 johnlev 545 5084 johnlev if (mapop.status != 0) { 546 5084 johnlev xvdi_fatal_error(dip, err, errstr); 547 5084 johnlev goto errout2; 548 5084 johnlev } 549 5084 johnlev ring->xr_vaddr = ringva; 550 5084 johnlev ring->xr_grant_hdl = mapop.handle; 551 5084 johnlev ring->xr_gref = gref; 552 5084 johnlev 553 5084 johnlev /* 554 5084 johnlev * init an acc handle and associate it w/ this ring 555 5084 johnlev * this is only for backend drivers. we get the memory by calling 556 5084 johnlev * vmem_xalloc(), instead of calling any ddi function, so we have 557 5084 johnlev * to init an acc handle by ourselves 558 5084 johnlev */ 559 5084 johnlev ring->xr_acc_hdl = impl_acc_hdl_alloc(KM_SLEEP, NULL); 560 5084 johnlev ap = impl_acc_hdl_get(ring->xr_acc_hdl); 561 5084 johnlev ap->ah_vers = VERS_ACCHDL; 562 5084 johnlev ap->ah_dip = dip; 563 5084 johnlev ap->ah_xfermodes = DDI_DMA_CONSISTENT; 564 5084 johnlev ap->ah_acc = xendev_dc_accattr; 565 5084 johnlev iap = (ddi_acc_impl_t *)ap->ah_platform_private; 566 5084 johnlev iap->ahi_acc_attr |= DDI_ACCATTR_CPU_VADDR; 567 5084 johnlev impl_acc_hdl_init(ap); 568 5084 johnlev ap->ah_offset = 0; 569 5084 johnlev ap->ah_len = (off_t)PAGESIZE; 570 5084 johnlev ap->ah_addr = ring->xr_vaddr; 571 5084 johnlev 572 5084 johnlev /* init backend ring */ 573 5084 johnlev xvdi_ring_init_back_ring(ring, nentry, entrysize); 574 5084 johnlev 575 5084 johnlev *ringpp = ring; 576 5084 johnlev 577 5084 johnlev return (DDI_SUCCESS); 578 5084 johnlev 579 5084 johnlev errout2: 580 5084 johnlev /* unmap ring page */ 581 5084 johnlev unmapop.host_addr = (uint64_t)(uintptr_t)ringva; 582 5084 johnlev unmapop.handle = ring->xr_grant_hdl; 583 5084 johnlev unmapop.dev_bus_addr = NULL; 584 5084 johnlev (void) HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmapop, 1); 585 5084 johnlev hat_release_mapping(kas.a_hat, ringva); 586 5084 johnlev errout1: 587 5084 johnlev vmem_xfree(heap_arena, ringva, PAGESIZE); 588 5084 johnlev kmem_free(ring, sizeof (xendev_ring_t)); 589 5084 johnlev return (DDI_FAILURE); 590 5084 johnlev } 591 5084 johnlev 592 5084 johnlev /* 593 5084 johnlev * Unmap a ring for a virtual device. 594 5084 johnlev * This is used by backend drivers. 595 5084 johnlev */ 596 5084 johnlev void 597 5084 johnlev xvdi_unmap_ring(xendev_ring_t *ring) 598 5084 johnlev { 599 5084 johnlev gnttab_unmap_grant_ref_t unmapop; 600 5084 johnlev 601 5084 johnlev ASSERT((ring != NULL) && (ring->xr_vaddr != NULL)); 602 5084 johnlev 603 5084 johnlev impl_acc_hdl_free(ring->xr_acc_hdl); 604 5084 johnlev unmapop.host_addr = (uint64_t)(uintptr_t)ring->xr_vaddr; 605 5084 johnlev unmapop.handle = ring->xr_grant_hdl; 606 5084 johnlev unmapop.dev_bus_addr = NULL; 607 5084 johnlev (void) HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmapop, 1); 608 5084 johnlev hat_release_mapping(kas.a_hat, ring->xr_vaddr); 609 5084 johnlev vmem_xfree(heap_arena, ring->xr_vaddr, PAGESIZE); 610 5084 johnlev kmem_free(ring, sizeof (xendev_ring_t)); 611 5084 johnlev } 612 5741 mrj #endif /* XPV_HVM_DRIVER */ 613 5084 johnlev 614 5084 johnlev /* 615 5084 johnlev * Re-initialise an inter-domain communications ring for the backend domain. 616 5084 johnlev * ring will be re-initialized after re-grant succeed 617 5084 johnlev * ring will be freed if fails to re-grant access to backend domain 618 5084 johnlev * so, don't keep useful data in the ring 619 5084 johnlev * used only in frontend driver 620 5084 johnlev */ 621 5084 johnlev static void 622 5084 johnlev xvdi_reinit_ring(dev_info_t *dip, grant_ref_t *gref, xendev_ring_t *ringp) 623 5084 johnlev { 624 5084 johnlev paddr_t rpaddr; 625 5084 johnlev maddr_t rmaddr; 626 5084 johnlev 627 5084 johnlev ASSERT((ringp != NULL) && (ringp->xr_paddr != 0)); 628 5084 johnlev rpaddr = ringp->xr_paddr; 629 5084 johnlev 630 5084 johnlev rmaddr = DOMAIN_IS_INITDOMAIN(xen_info) ? rpaddr : pa_to_ma(rpaddr); 631 5084 johnlev gnttab_grant_foreign_access_ref(ringp->xr_gref, xvdi_get_oeid(dip), 632 5084 johnlev rmaddr >> PAGESHIFT, 0); 633 5084 johnlev *gref = ringp->xr_gref; 634 5084 johnlev 635 5084 johnlev /* init frontend ring */ 636 5084 johnlev xvdi_ring_init_sring(ringp); 637 5084 johnlev xvdi_ring_init_front_ring(ringp, ringp->xr_sring.fr.nr_ents, 638 5084 johnlev ringp->xr_entry_size); 639 5084 johnlev } 640 5084 johnlev 641 5084 johnlev /* 642 5084 johnlev * allocate Xen inter-domain communications ring for Xen virtual devices 643 5084 johnlev * used only in frontend driver 644 5084 johnlev * if *ringpp is not NULL, we'll simply re-init it 645 5084 johnlev */ 646 5084 johnlev int 647 5084 johnlev xvdi_alloc_ring(dev_info_t *dip, size_t nentry, size_t entrysize, 648 5084 johnlev grant_ref_t *gref, xendev_ring_t **ringpp) 649 5084 johnlev { 650 5084 johnlev size_t len; 651 5084 johnlev xendev_ring_t *ring; 652 5084 johnlev ddi_dma_cookie_t dma_cookie; 653 5084 johnlev uint_t ncookies; 654 5084 johnlev grant_ref_t ring_gref; 655 5084 johnlev domid_t oeid; 656 5084 johnlev maddr_t rmaddr; 657 5084 johnlev 658 5084 johnlev if (*ringpp) { 659 5084 johnlev xvdi_reinit_ring(dip, gref, *ringpp); 660 5084 johnlev return (DDI_SUCCESS); 661 5084 johnlev } 662 5084 johnlev 663 5084 johnlev *ringpp = ring = kmem_zalloc(sizeof (xendev_ring_t), KM_SLEEP); 664 5084 johnlev oeid = xvdi_get_oeid(dip); 665 5084 johnlev 666 5084 johnlev /* 667 5084 johnlev * Allocate page for this ring buffer 668 5084 johnlev */ 669 5084 johnlev if (ddi_dma_alloc_handle(dip, &xendev_dc_dmaattr, DDI_DMA_SLEEP, 670 5084 johnlev 0, &ring->xr_dma_hdl) != DDI_SUCCESS) 671 5084 johnlev goto err; 672 5084 johnlev 673 5084 johnlev if (ddi_dma_mem_alloc(ring->xr_dma_hdl, PAGESIZE, 674 5084 johnlev &xendev_dc_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, 675 5084 johnlev &ring->xr_vaddr, &len, &ring->xr_acc_hdl) != DDI_SUCCESS) { 676 5084 johnlev ddi_dma_free_handle(&ring->xr_dma_hdl); 677 5084 johnlev goto err; 678 5084 johnlev } 679 5084 johnlev 680 5084 johnlev if (ddi_dma_addr_bind_handle(ring->xr_dma_hdl, NULL, 681 5084 johnlev ring->xr_vaddr, len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 682 5084 johnlev DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_DMA_MAPPED) { 683 5084 johnlev ddi_dma_mem_free(&ring->xr_acc_hdl); 684 5084 johnlev ring->xr_vaddr = NULL; 685 5084 johnlev ddi_dma_free_handle(&ring->xr_dma_hdl); 686 5084 johnlev goto err; 687 5084 johnlev } 688 5084 johnlev ASSERT(ncookies == 1); 689 5084 johnlev ring->xr_paddr = dma_cookie.dmac_laddress; 690 5084 johnlev rmaddr = DOMAIN_IS_INITDOMAIN(xen_info) ? ring->xr_paddr : 691 5084 johnlev pa_to_ma(ring->xr_paddr); 692 5084 johnlev 693 5084 johnlev if ((ring_gref = gnttab_grant_foreign_access(oeid, 694 5084 johnlev rmaddr >> PAGESHIFT, 0)) == (grant_ref_t)-1) { 695 5084 johnlev (void) ddi_dma_unbind_handle(ring->xr_dma_hdl); 696 5084 johnlev ddi_dma_mem_free(&ring->xr_acc_hdl); 697 5084 johnlev ring->xr_vaddr = NULL; 698 5084 johnlev ddi_dma_free_handle(&ring->xr_dma_hdl); 699 5084 johnlev goto err; 700 5084 johnlev } 701 5084 johnlev *gref = ring->xr_gref = ring_gref; 702 5084 johnlev 703 5084 johnlev /* init frontend ring */ 704 5084 johnlev xvdi_ring_init_sring(ring); 705 5084 johnlev xvdi_ring_init_front_ring(ring, nentry, entrysize); 706 5084 johnlev 707 5084 johnlev return (DDI_SUCCESS); 708 5084 johnlev 709 5084 johnlev err: 710 5084 johnlev kmem_free(ring, sizeof (xendev_ring_t)); 711 5084 johnlev return (DDI_FAILURE); 712 5084 johnlev } 713 5084 johnlev 714 5084 johnlev /* 715 5084 johnlev * Release ring buffers allocated for Xen devices 716 5084 johnlev * used for frontend driver 717 5084 johnlev */ 718 5084 johnlev void 719 5084 johnlev xvdi_free_ring(xendev_ring_t *ring) 720 5084 johnlev { 721 5084 johnlev ASSERT((ring != NULL) && (ring->xr_vaddr != NULL)); 722 5084 johnlev 723 5084 johnlev (void) gnttab_end_foreign_access_ref(ring->xr_gref, 0); 724 5084 johnlev (void) ddi_dma_unbind_handle(ring->xr_dma_hdl); 725 5084 johnlev ddi_dma_mem_free(&ring->xr_acc_hdl); 726 5084 johnlev ddi_dma_free_handle(&ring->xr_dma_hdl); 727 5084 johnlev kmem_free(ring, sizeof (xendev_ring_t)); 728 5084 johnlev } 729 5084 johnlev 730 5084 johnlev dev_info_t * 731 5084 johnlev xvdi_create_dev(dev_info_t *parent, xendev_devclass_t devclass, 732 5084 johnlev domid_t dom, int vdev) 733 5084 johnlev { 734 5084 johnlev dev_info_t *dip; 735 5084 johnlev boolean_t backend; 736 5084 johnlev i_xd_cfg_t *xdcp; 737 5084 johnlev char xsnamebuf[TYPICALMAXPATHLEN]; 738 5084 johnlev char *type, *node = NULL, *xsname = NULL; 739 5084 johnlev unsigned int tlen; 740 5159 johnlev int ret; 741 5084 johnlev 742 5084 johnlev ASSERT(DEVI_BUSY_OWNED(parent)); 743 5084 johnlev 744 5084 johnlev backend = (dom != DOMID_SELF); 745 5084 johnlev xdcp = i_xvdi_devclass2cfg(devclass); 746 5084 johnlev ASSERT(xdcp != NULL); 747 5084 johnlev 748 6175 johnlev if (vdev != VDEV_NOXS) { 749 5084 johnlev if (!backend) { 750 5084 johnlev (void) snprintf(xsnamebuf, sizeof (xsnamebuf), 751 5084 johnlev "%s/%d", xdcp->xs_path_fe, vdev); 752 5084 johnlev xsname = xsnamebuf; 753 5084 johnlev node = xdcp->node_fe; 754 5084 johnlev } else { 755 5084 johnlev (void) snprintf(xsnamebuf, sizeof (xsnamebuf), 756 5084 johnlev "%s/%d/%d", xdcp->xs_path_be, dom, vdev); 757 5084 johnlev xsname = xsnamebuf; 758 5084 johnlev node = xdcp->node_be; 759 5084 johnlev } 760 5084 johnlev } else { 761 5084 johnlev node = xdcp->node_fe; 762 5084 johnlev } 763 5084 johnlev 764 5084 johnlev /* Must have a driver to use. */ 765 5084 johnlev if (node == NULL) 766 5084 johnlev return (NULL); 767 5084 johnlev 768 5084 johnlev /* 769 5084 johnlev * We need to check the state of this device before we go 770 5084 johnlev * further, otherwise we'll end up with a dead loop if 771 5084 johnlev * anything goes wrong. 772 5084 johnlev */ 773 5084 johnlev if ((xsname != NULL) && 774 5084 johnlev (xenbus_read_driver_state(xsname) >= XenbusStateClosing)) 775 5084 johnlev return (NULL); 776 5084 johnlev 777 5084 johnlev ndi_devi_alloc_sleep(parent, node, DEVI_SID_NODEID, &dip); 778 5084 johnlev 779 5084 johnlev /* 780 5084 johnlev * Driver binding uses the compatible property _before_ the 781 5084 johnlev * node name, so we set the node name to the 'model' of the 782 5084 johnlev * device (i.e. 'xnb' or 'xdb') and, if 'type' is present, 783 5084 johnlev * encode both the model and the type in a compatible property 784 5084 johnlev * (i.e. 'xnb,netfront' or 'xnb,SUNW_mac'). This allows a 785 5084 johnlev * driver binding based on the <model,type> pair _before_ a 786 5084 johnlev * binding based on the node name. 787 5084 johnlev */ 788 5084 johnlev if ((xsname != NULL) && 789 5084 johnlev (xenbus_read(XBT_NULL, xsname, "type", (void *)&type, &tlen) 790 5084 johnlev == 0)) { 791 5084 johnlev size_t clen; 792 5084 johnlev char *c[1]; 793 5084 johnlev 794 5084 johnlev clen = strlen(node) + strlen(type) + 2; 795 5084 johnlev c[0] = kmem_alloc(clen, KM_SLEEP); 796 5084 johnlev (void) snprintf(c[0], clen, "%s,%s", node, type); 797 5084 johnlev 798 5084 johnlev (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, 799 5084 johnlev dip, "compatible", (char **)c, 1); 800 5084 johnlev 801 5084 johnlev kmem_free(c[0], clen); 802 5084 johnlev kmem_free(type, tlen); 803 5084 johnlev } 804 5084 johnlev 805 5084 johnlev (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "devclass", devclass); 806 5084 johnlev (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "domain", dom); 807 5084 johnlev (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vdev", vdev); 808 5084 johnlev 809 5084 johnlev if (i_ddi_devi_attached(parent)) 810 5159 johnlev ret = ndi_devi_online(dip, 0); 811 5084 johnlev else 812 5159 johnlev ret = ndi_devi_bind_driver(dip, 0); 813 5159 johnlev if (ret != NDI_SUCCESS) 814 5159 johnlev (void) ndi_devi_offline(dip, NDI_DEVI_REMOVE); 815 5084 johnlev 816 5084 johnlev return (dip); 817 5084 johnlev } 818 5084 johnlev 819 5084 johnlev /* 820 5084 johnlev * xendev_enum_class() 821 5084 johnlev */ 822 5084 johnlev void 823 5084 johnlev xendev_enum_class(dev_info_t *parent, xendev_devclass_t devclass) 824 5084 johnlev { 825 5910 mrj boolean_t dom0 = DOMAIN_IS_INITDOMAIN(xen_info); 826 5910 mrj boolean_t domU = !dom0; 827 5084 johnlev i_xd_cfg_t *xdcp; 828 5084 johnlev 829 5084 johnlev xdcp = i_xvdi_devclass2cfg(devclass); 830 5084 johnlev ASSERT(xdcp != NULL); 831 5910 mrj 832 5910 mrj if (dom0 && !(xdcp->flags & XD_DOM_ZERO)) 833 5910 mrj return; 834 5910 mrj 835 5910 mrj if (domU && !(xdcp->flags & XD_DOM_GUEST)) 836 5910 mrj return; 837 5084 johnlev 838 5084 johnlev if (xdcp->xsdev == NULL) { 839 5084 johnlev int circ; 840 5084 johnlev 841 5084 johnlev /* 842 5084 johnlev * Don't need to probe this kind of device from the 843 5084 johnlev * store, just create one if it doesn't exist. 844 5084 johnlev */ 845 5084 johnlev 846 5084 johnlev ndi_devi_enter(parent, &circ); 847 6175 johnlev if (xvdi_find_dev(parent, devclass, DOMID_SELF, VDEV_NOXS) 848 5084 johnlev == NULL) 849 5084 johnlev (void) xvdi_create_dev(parent, devclass, 850 6175 johnlev DOMID_SELF, VDEV_NOXS); 851 5084 johnlev ndi_devi_exit(parent, circ); 852 5084 johnlev } else { 853 5084 johnlev /* 854 5084 johnlev * Probe this kind of device from the store, both 855 5084 johnlev * frontend and backend. 856 5084 johnlev */ 857 7756 Mark if (xdcp->node_fe != NULL) { 858 7756 Mark i_xvdi_enum_fe(parent, xdcp); 859 7756 Mark } 860 7756 Mark if (xdcp->node_be != NULL) { 861 7756 Mark i_xvdi_enum_be(parent, xdcp); 862 7756 Mark } 863 5084 johnlev } 864 5084 johnlev } 865 5084 johnlev 866 5084 johnlev /* 867 5084 johnlev * xendev_enum_all() 868 5084 johnlev */ 869 5084 johnlev void 870 5084 johnlev xendev_enum_all(dev_info_t *parent, boolean_t store_unavailable) 871 5084 johnlev { 872 5084 johnlev int i; 873 5084 johnlev i_xd_cfg_t *xdcp; 874 5084 johnlev boolean_t dom0 = DOMAIN_IS_INITDOMAIN(xen_info); 875 5084 johnlev 876 5084 johnlev for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++) { 877 5084 johnlev /* 878 5084 johnlev * Dom0 relies on watchpoints to create non-soft 879 5084 johnlev * devices - don't attempt to iterate over the store. 880 5084 johnlev */ 881 5084 johnlev if (dom0 && (xdcp->xsdev != NULL)) 882 5084 johnlev continue; 883 5084 johnlev 884 5084 johnlev /* 885 5084 johnlev * If the store is not yet available, don't attempt to 886 5084 johnlev * iterate. 887 5084 johnlev */ 888 5084 johnlev if (store_unavailable && (xdcp->xsdev != NULL)) 889 5084 johnlev continue; 890 5084 johnlev 891 5084 johnlev xendev_enum_class(parent, xdcp->devclass); 892 5084 johnlev } 893 5084 johnlev } 894 5084 johnlev 895 5084 johnlev xendev_devclass_t 896 5084 johnlev xendev_nodename_to_devclass(char *nodename) 897 5084 johnlev { 898 5084 johnlev int i; 899 5084 johnlev i_xd_cfg_t *xdcp; 900 5084 johnlev 901 5084 johnlev /* 902 5084 johnlev * This relies on the convention that variants of a base 903 5084 johnlev * driver share the same prefix and that there are no drivers 904 5084 johnlev * which share a common prefix with the name of any other base 905 5084 johnlev * drivers. 906 5084 johnlev * 907 5084 johnlev * So for a base driver 'xnb' (which is the name listed in 908 5084 johnlev * xdci) the variants all begin with the string 'xnb' (in fact 909 5084 johnlev * they are 'xnbe', 'xnbo' and 'xnbu') and there are no other 910 5084 johnlev * base drivers which have the prefix 'xnb'. 911 5084 johnlev */ 912 5084 johnlev ASSERT(nodename != NULL); 913 5084 johnlev for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++) { 914 5084 johnlev if (((xdcp->node_fe != NULL) && 915 5084 johnlev (strncmp(nodename, xdcp->node_fe, 916 5084 johnlev strlen(xdcp->node_fe)) == 0)) || 917 5084 johnlev ((xdcp->node_be != NULL) && 918 5084 johnlev (strncmp(nodename, xdcp->node_be, 919 5084 johnlev strlen(xdcp->node_be)) == 0))) 920 5084 johnlev 921 5084 johnlev return (xdcp->devclass); 922 5084 johnlev } 923 5084 johnlev return (XEN_INVAL); 924 5084 johnlev } 925 5084 johnlev 926 5084 johnlev int 927 5084 johnlev xendev_devclass_ipl(xendev_devclass_t devclass) 928 5084 johnlev { 929 5084 johnlev i_xd_cfg_t *xdcp; 930 5084 johnlev 931 5084 johnlev xdcp = i_xvdi_devclass2cfg(devclass); 932 5084 johnlev ASSERT(xdcp != NULL); 933 5084 johnlev 934 5084 johnlev return (xdcp->xd_ipl); 935 5084 johnlev } 936 5084 johnlev 937 5084 johnlev /* 938 5084 johnlev * Determine if a devinfo instance exists of a particular device 939 5084 johnlev * class, domain and xenstore virtual device number. 940 5084 johnlev */ 941 5084 johnlev dev_info_t * 942 5084 johnlev xvdi_find_dev(dev_info_t *parent, xendev_devclass_t devclass, 943 5084 johnlev domid_t dom, int vdev) 944 5084 johnlev { 945 5084 johnlev dev_info_t *dip; 946 5084 johnlev 947 5084 johnlev ASSERT(DEVI_BUSY_OWNED(parent)); 948 5084 johnlev 949 5084 johnlev switch (devclass) { 950 5084 johnlev case XEN_CONSOLE: 951 5084 johnlev case XEN_XENBUS: 952 5084 johnlev case XEN_DOMCAPS: 953 5084 johnlev case XEN_BALLOON: 954 5084 johnlev case XEN_EVTCHN: 955 5084 johnlev case XEN_PRIVCMD: 956 5084 johnlev /* Console and soft devices have no vdev. */ 957 6175 johnlev vdev = VDEV_NOXS; 958 5084 johnlev break; 959 5084 johnlev default: 960 5084 johnlev break; 961 5084 johnlev } 962 5084 johnlev 963 5084 johnlev for (dip = ddi_get_child(parent); dip != NULL; 964 5084 johnlev dip = ddi_get_next_sibling(dip)) { 965 5084 johnlev int *vdevnump, *domidp, *devclsp, vdevnum; 966 5084 johnlev uint_t ndomid, nvdevnum, ndevcls; 967 5084 johnlev xendev_devclass_t devcls; 968 5084 johnlev domid_t domid; 969 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 970 5084 johnlev 971 5084 johnlev if (pdp == NULL) { 972 5084 johnlev if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 973 5084 johnlev DDI_PROP_DONTPASS, "domain", &domidp, &ndomid) != 974 5084 johnlev DDI_PROP_SUCCESS) 975 5084 johnlev continue; 976 5084 johnlev ASSERT(ndomid == 1); 977 5084 johnlev domid = (domid_t)*domidp; 978 5084 johnlev ddi_prop_free(domidp); 979 5084 johnlev 980 5084 johnlev if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 981 5084 johnlev DDI_PROP_DONTPASS, "vdev", &vdevnump, &nvdevnum) != 982 5084 johnlev DDI_PROP_SUCCESS) 983 5084 johnlev continue; 984 5084 johnlev ASSERT(nvdevnum == 1); 985 5084 johnlev vdevnum = *vdevnump; 986 5084 johnlev ddi_prop_free(vdevnump); 987 5084 johnlev 988 5084 johnlev if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 989 5084 johnlev DDI_PROP_DONTPASS, "devclass", &devclsp, 990 5084 johnlev &ndevcls) != DDI_PROP_SUCCESS) 991 5084 johnlev continue; 992 5084 johnlev ASSERT(ndevcls == 1); 993 5084 johnlev devcls = (xendev_devclass_t)*devclsp; 994 5084 johnlev ddi_prop_free(devclsp); 995 5084 johnlev } else { 996 5084 johnlev domid = pdp->xd_domain; 997 5084 johnlev vdevnum = pdp->xd_vdevnum; 998 5084 johnlev devcls = pdp->xd_devclass; 999 5084 johnlev } 1000 5084 johnlev 1001 5084 johnlev if ((domid == dom) && (vdevnum == vdev) && (devcls == devclass)) 1002 5084 johnlev return (dip); 1003 5084 johnlev } 1004 5084 johnlev return (NULL); 1005 5084 johnlev } 1006 5084 johnlev 1007 5084 johnlev int 1008 5084 johnlev xvdi_get_evtchn(dev_info_t *xdip) 1009 5084 johnlev { 1010 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1011 5084 johnlev 1012 5084 johnlev ASSERT(pdp != NULL); 1013 5084 johnlev return (pdp->xd_evtchn); 1014 5084 johnlev } 1015 5084 johnlev 1016 5084 johnlev int 1017 5084 johnlev xvdi_get_vdevnum(dev_info_t *xdip) 1018 5084 johnlev { 1019 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1020 5084 johnlev 1021 5084 johnlev ASSERT(pdp != NULL); 1022 5084 johnlev return (pdp->xd_vdevnum); 1023 5084 johnlev } 1024 5084 johnlev 1025 5084 johnlev char * 1026 5084 johnlev xvdi_get_xsname(dev_info_t *xdip) 1027 5084 johnlev { 1028 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1029 5084 johnlev 1030 5084 johnlev ASSERT(pdp != NULL); 1031 5084 johnlev return ((char *)(pdp->xd_xsdev.nodename)); 1032 5084 johnlev } 1033 5084 johnlev 1034 5084 johnlev char * 1035 5084 johnlev xvdi_get_oename(dev_info_t *xdip) 1036 5084 johnlev { 1037 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1038 5084 johnlev 1039 5084 johnlev ASSERT(pdp != NULL); 1040 5084 johnlev if (pdp->xd_devclass == XEN_CONSOLE) 1041 5084 johnlev return (NULL); 1042 5084 johnlev return ((char *)(pdp->xd_xsdev.otherend)); 1043 5084 johnlev } 1044 5084 johnlev 1045 5084 johnlev struct xenbus_device * 1046 5084 johnlev xvdi_get_xsd(dev_info_t *xdip) 1047 5084 johnlev { 1048 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1049 5084 johnlev 1050 5084 johnlev ASSERT(pdp != NULL); 1051 5084 johnlev return (&pdp->xd_xsdev); 1052 5084 johnlev } 1053 5084 johnlev 1054 5084 johnlev domid_t 1055 5084 johnlev xvdi_get_oeid(dev_info_t *xdip) 1056 5084 johnlev { 1057 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(xdip); 1058 5084 johnlev 1059 5084 johnlev ASSERT(pdp != NULL); 1060 5084 johnlev if (pdp->xd_devclass == XEN_CONSOLE) 1061 5084 johnlev return ((domid_t)-1); 1062 5084 johnlev return ((domid_t)(pdp->xd_xsdev.otherend_id)); 1063 5084 johnlev } 1064 5084 johnlev 1065 5084 johnlev void 1066 5084 johnlev xvdi_dev_error(dev_info_t *dip, int errno, char *errstr) 1067 5084 johnlev { 1068 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1069 5084 johnlev 1070 5084 johnlev ASSERT(pdp != NULL); 1071 5084 johnlev xenbus_dev_error(&pdp->xd_xsdev, errno, errstr); 1072 5084 johnlev } 1073 5084 johnlev 1074 5084 johnlev void 1075 5084 johnlev xvdi_fatal_error(dev_info_t *dip, int errno, char *errstr) 1076 5084 johnlev { 1077 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1078 5084 johnlev 1079 5084 johnlev ASSERT(pdp != NULL); 1080 5084 johnlev xenbus_dev_fatal(&pdp->xd_xsdev, errno, errstr); 1081 5084 johnlev } 1082 5084 johnlev 1083 5084 johnlev static void 1084 5084 johnlev i_xvdi_oestate_handler(void *arg) 1085 5084 johnlev { 1086 7679 Max i_oestate_evt_t *evt = (i_oestate_evt_t *)arg; 1087 7679 Max dev_info_t *dip = evt->dip; 1088 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1089 5084 johnlev XenbusState oestate = pdp->xd_xsdev.otherend_state; 1090 7679 Max XenbusState curr_oestate = evt->state; 1091 5084 johnlev ddi_eventcookie_t evc; 1092 7679 Max 1093 7679 Max /* evt is alloc'ed in i_xvdi_oestate_cb */ 1094 7679 Max kmem_free(evt, sizeof (i_oestate_evt_t)); 1095 7679 Max 1096 7679 Max /* 1097 7679 Max * If the oestate we're handling is not the latest one, 1098 7679 Max * it does not make any sense to continue handling it. 1099 7679 Max */ 1100 7679 Max if (curr_oestate != oestate) 1101 7679 Max return; 1102 5084 johnlev 1103 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1104 5084 johnlev 1105 5084 johnlev if (pdp->xd_oe_ehid != NULL) { 1106 5084 johnlev /* send notification to driver */ 1107 5084 johnlev if (ddi_get_eventcookie(dip, XS_OE_STATE, 1108 5084 johnlev &evc) == DDI_SUCCESS) { 1109 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1110 5084 johnlev (void) ndi_post_event(dip, dip, evc, &oestate); 1111 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1112 5084 johnlev } 1113 5084 johnlev } else { 1114 5084 johnlev /* 1115 5084 johnlev * take default action, if driver hasn't registered its 1116 5084 johnlev * event handler yet 1117 5084 johnlev */ 1118 5084 johnlev if (oestate == XenbusStateClosing) { 1119 5084 johnlev (void) xvdi_switch_state(dip, XBT_NULL, 1120 5084 johnlev XenbusStateClosed); 1121 5084 johnlev } else if (oestate == XenbusStateClosed) { 1122 5084 johnlev (void) xvdi_switch_state(dip, XBT_NULL, 1123 5084 johnlev XenbusStateClosed); 1124 5084 johnlev (void) xvdi_post_event(dip, XEN_HP_REMOVE); 1125 5084 johnlev } 1126 5084 johnlev } 1127 5084 johnlev 1128 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1129 5084 johnlev 1130 5084 johnlev /* 1131 5084 johnlev * We'll try to remove the devinfo node of this device if the 1132 5084 johnlev * other end has closed. 1133 5084 johnlev */ 1134 5084 johnlev if (oestate == XenbusStateClosed) 1135 5084 johnlev (void) ddi_taskq_dispatch(DEVI(ddi_get_parent(dip))->devi_taskq, 1136 5084 johnlev xendev_offline_device, dip, DDI_SLEEP); 1137 5084 johnlev } 1138 5084 johnlev 1139 5084 johnlev static void 1140 5084 johnlev i_xvdi_hpstate_handler(void *arg) 1141 5084 johnlev { 1142 5084 johnlev dev_info_t *dip = (dev_info_t *)arg; 1143 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1144 5084 johnlev ddi_eventcookie_t evc; 1145 5084 johnlev char *hp_status; 1146 5084 johnlev unsigned int hpl; 1147 5084 johnlev 1148 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1149 5084 johnlev if ((ddi_get_eventcookie(dip, XS_HP_STATE, &evc) == DDI_SUCCESS) && 1150 5084 johnlev (xenbus_read(XBT_NULL, pdp->xd_hp_watch.node, "", 1151 5084 johnlev (void *)&hp_status, &hpl) == 0)) { 1152 5084 johnlev 1153 5084 johnlev xendev_hotplug_state_t new_state = Unrecognized; 1154 5084 johnlev 1155 5084 johnlev if (strcmp(hp_status, "connected") == 0) 1156 5084 johnlev new_state = Connected; 1157 5084 johnlev 1158 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1159 5084 johnlev 1160 5084 johnlev (void) ndi_post_event(dip, dip, evc, &new_state); 1161 5084 johnlev kmem_free(hp_status, hpl); 1162 5084 johnlev return; 1163 5084 johnlev } 1164 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1165 5084 johnlev } 1166 5084 johnlev 1167 5084 johnlev void 1168 5084 johnlev xvdi_notify_oe(dev_info_t *dip) 1169 5084 johnlev { 1170 5084 johnlev struct xendev_ppd *pdp; 1171 5084 johnlev 1172 5084 johnlev pdp = ddi_get_parent_data(dip); 1173 5084 johnlev ASSERT(pdp->xd_evtchn != INVALID_EVTCHN); 1174 5084 johnlev ec_notify_via_evtchn(pdp->xd_evtchn); 1175 5084 johnlev } 1176 5084 johnlev 1177 5084 johnlev static void 1178 5084 johnlev i_xvdi_bepath_cb(struct xenbus_watch *w, const char **vec, unsigned int len) 1179 5084 johnlev { 1180 5084 johnlev dev_info_t *dip = (dev_info_t *)w->dev; 1181 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1182 5084 johnlev char *be = NULL; 1183 5084 johnlev unsigned int bel; 1184 5084 johnlev 1185 5084 johnlev ASSERT(len > XS_WATCH_PATH); 1186 5084 johnlev ASSERT(vec[XS_WATCH_PATH] != NULL); 1187 5084 johnlev 1188 5084 johnlev /* 1189 5084 johnlev * If the backend is not the same as that we already stored, 1190 5084 johnlev * re-set our watch for its' state. 1191 5084 johnlev */ 1192 5084 johnlev if ((xenbus_read(XBT_NULL, "", vec[XS_WATCH_PATH], (void *)be, &bel) 1193 5084 johnlev == 0) && (strcmp(be, pdp->xd_xsdev.otherend) != 0)) 1194 5084 johnlev (void) i_xvdi_add_watch_oestate(dip); 1195 5084 johnlev 1196 5084 johnlev if (be != NULL) { 1197 5084 johnlev ASSERT(bel > 0); 1198 5084 johnlev kmem_free(be, bel); 1199 5084 johnlev } 1200 5084 johnlev } 1201 5084 johnlev 1202 8863 Edward static void 1203 8863 Edward i_xvdi_xb_watch_free(xd_xb_watches_t *xxwp) 1204 8863 Edward { 1205 8863 Edward ASSERT(xxwp->xxw_ref == 0); 1206 8863 Edward strfree((char *)xxwp->xxw_watch.node); 1207 8863 Edward kmem_free(xxwp, sizeof (*xxwp)); 1208 8863 Edward } 1209 8863 Edward 1210 8863 Edward static void 1211 8863 Edward i_xvdi_xb_watch_release(xd_xb_watches_t *xxwp) 1212 8863 Edward { 1213 8863 Edward ASSERT(MUTEX_HELD(&xxwp->xxw_xppd->xd_ndi_lk)); 1214 8863 Edward ASSERT(xxwp->xxw_ref > 0); 1215 8863 Edward if (--xxwp->xxw_ref == 0) 1216 8863 Edward i_xvdi_xb_watch_free(xxwp); 1217 8863 Edward } 1218 8863 Edward 1219 8863 Edward static void 1220 8863 Edward i_xvdi_xb_watch_hold(xd_xb_watches_t *xxwp) 1221 8863 Edward { 1222 8863 Edward ASSERT(MUTEX_HELD(&xxwp->xxw_xppd->xd_ndi_lk)); 1223 8863 Edward ASSERT(xxwp->xxw_ref > 0); 1224 8863 Edward xxwp->xxw_ref++; 1225 8863 Edward } 1226 8863 Edward 1227 8863 Edward static void 1228 8863 Edward i_xvdi_xb_watch_cb_tq(void *arg) 1229 8863 Edward { 1230 8863 Edward xd_xb_watches_t *xxwp = (xd_xb_watches_t *)arg; 1231 8863 Edward dev_info_t *dip = (dev_info_t *)xxwp->xxw_watch.dev; 1232 8863 Edward struct xendev_ppd *pdp = xxwp->xxw_xppd; 1233 8863 Edward 1234 8863 Edward xxwp->xxw_cb(dip, xxwp->xxw_watch.node, xxwp->xxw_arg); 1235 8863 Edward 1236 8863 Edward mutex_enter(&pdp->xd_ndi_lk); 1237 8863 Edward i_xvdi_xb_watch_release(xxwp); 1238 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1239 8863 Edward } 1240 8863 Edward 1241 8863 Edward static void 1242 8863 Edward i_xvdi_xb_watch_cb(struct xenbus_watch *w, const char **vec, unsigned int len) 1243 8863 Edward { 1244 8863 Edward dev_info_t *dip = (dev_info_t *)w->dev; 1245 8863 Edward struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1246 8863 Edward xd_xb_watches_t *xxwp; 1247 8863 Edward 1248 8863 Edward ASSERT(len > XS_WATCH_PATH); 1249 8863 Edward ASSERT(vec[XS_WATCH_PATH] != NULL); 1250 8863 Edward 1251 8863 Edward mutex_enter(&pdp->xd_ndi_lk); 1252 8863 Edward for (xxwp = list_head(&pdp->xd_xb_watches); xxwp != NULL; 1253 8863 Edward xxwp = list_next(&pdp->xd_xb_watches, xxwp)) { 1254 8863 Edward if (w == &xxwp->xxw_watch) 1255 8863 Edward break; 1256 8863 Edward } 1257 8863 Edward 1258 8863 Edward if (xxwp == NULL) { 1259 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1260 8863 Edward return; 1261 8863 Edward } 1262 8863 Edward 1263 8863 Edward i_xvdi_xb_watch_hold(xxwp); 1264 8863 Edward (void) ddi_taskq_dispatch(pdp->xd_xb_watch_taskq, 1265 8863 Edward i_xvdi_xb_watch_cb_tq, xxwp, DDI_SLEEP); 1266 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1267 8863 Edward } 1268 8863 Edward 1269 8863 Edward /* 1270 8863 Edward * Any watches registered with xvdi_add_xb_watch_handler() get torn down during 1271 8863 Edward * a suspend operation. So if a frontend driver want's to use these interfaces, 1272 8863 Edward * that driver is responsible for re-registering any watches it had before 1273 8863 Edward * the suspend operation. 1274 8863 Edward */ 1275 8863 Edward int 1276 8863 Edward xvdi_add_xb_watch_handler(dev_info_t *dip, const char *dir, const char *node, 1277 8863 Edward xvdi_xb_watch_cb_t cb, void *arg) 1278 8863 Edward { 1279 8863 Edward struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1280 8863 Edward xd_xb_watches_t *xxw_new, *xxwp; 1281 8863 Edward char *path; 1282 8863 Edward int n; 1283 8863 Edward 1284 8863 Edward ASSERT((dip != NULL) && (dir != NULL) && (node != NULL)); 1285 8863 Edward ASSERT(cb != NULL); 1286 8863 Edward 1287 8863 Edward n = strlen(dir) + 1 + strlen(node) + 1; 1288 8863 Edward path = kmem_zalloc(n, KM_SLEEP); 1289 8863 Edward (void) strlcat(path, dir, n); 1290 8863 Edward (void) strlcat(path, "/", n); 1291 8863 Edward (void) strlcat(path, node, n); 1292 8863 Edward ASSERT((strlen(path) + 1) == n); 1293 8863 Edward 1294 8863 Edward xxw_new = kmem_zalloc(sizeof (*xxw_new), KM_SLEEP); 1295 8863 Edward xxw_new->xxw_ref = 1; 1296 8863 Edward xxw_new->xxw_watch.node = path; 1297 8863 Edward xxw_new->xxw_watch.callback = i_xvdi_xb_watch_cb; 1298 8863 Edward xxw_new->xxw_watch.dev = (struct xenbus_device *)dip; 1299 8863 Edward xxw_new->xxw_xppd = pdp; 1300 8863 Edward xxw_new->xxw_cb = cb; 1301 8863 Edward xxw_new->xxw_arg = arg; 1302 8863 Edward 1303 8863 Edward mutex_enter(&pdp->xd_ndi_lk); 1304 8863 Edward 1305 8863 Edward /* 1306 8863 Edward * If this is the first watch we're setting up, create a taskq 1307 8863 Edward * to dispatch watch events and initialize the watch list. 1308 8863 Edward */ 1309 8863 Edward if (pdp->xd_xb_watch_taskq == NULL) { 1310 8863 Edward char tq_name[TASKQ_NAMELEN]; 1311 8863 Edward 1312 8863 Edward ASSERT(list_is_empty(&pdp->xd_xb_watches)); 1313 8863 Edward 1314 8863 Edward (void) snprintf(tq_name, sizeof (tq_name), 1315 8863 Edward "%s_xb_watch_tq", ddi_get_name(dip)); 1316 8863 Edward 1317 8863 Edward if ((pdp->xd_xb_watch_taskq = ddi_taskq_create(dip, tq_name, 1318 8863 Edward 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 1319 8863 Edward i_xvdi_xb_watch_release(xxw_new); 1320 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1321 8863 Edward return (DDI_FAILURE); 1322 8863 Edward } 1323 8863 Edward } 1324 8863 Edward 1325 8863 Edward /* Don't allow duplicate watches to be registered */ 1326 8863 Edward for (xxwp = list_head(&pdp->xd_xb_watches); xxwp != NULL; 1327 8863 Edward xxwp = list_next(&pdp->xd_xb_watches, xxwp)) { 1328 8863 Edward 1329 8863 Edward ASSERT(strcmp(xxwp->xxw_watch.node, path) != 0); 1330 8863 Edward if (strcmp(xxwp->xxw_watch.node, path) != 0) 1331 8863 Edward continue; 1332 8863 Edward i_xvdi_xb_watch_release(xxw_new); 1333 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1334 8863 Edward return (DDI_FAILURE); 1335 8863 Edward } 1336 8863 Edward 1337 8863 Edward if (register_xenbus_watch(&xxw_new->xxw_watch) != 0) { 1338 8863 Edward if (list_is_empty(&pdp->xd_xb_watches)) { 1339 8863 Edward ddi_taskq_destroy(pdp->xd_xb_watch_taskq); 1340 8863 Edward pdp->xd_xb_watch_taskq = NULL; 1341 8863 Edward } 1342 8863 Edward i_xvdi_xb_watch_release(xxw_new); 1343 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1344 8863 Edward return (DDI_FAILURE); 1345 8863 Edward } 1346 8863 Edward 1347 8863 Edward list_insert_head(&pdp->xd_xb_watches, xxw_new); 1348 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1349 8863 Edward return (DDI_SUCCESS); 1350 8863 Edward } 1351 8863 Edward 1352 8863 Edward /* 1353 8863 Edward * Tear down all xenbus watches registered by the specified dip. 1354 8863 Edward */ 1355 8863 Edward void 1356 8863 Edward xvdi_remove_xb_watch_handlers(dev_info_t *dip) 1357 8863 Edward { 1358 8863 Edward struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1359 8863 Edward xd_xb_watches_t *xxwp; 1360 8863 Edward ddi_taskq_t *tq; 1361 8863 Edward 1362 8863 Edward mutex_enter(&pdp->xd_ndi_lk); 1363 8863 Edward 1364 8863 Edward while ((xxwp = list_remove_head(&pdp->xd_xb_watches)) != NULL) { 1365 9243 Mark mutex_exit(&pdp->xd_ndi_lk); 1366 8863 Edward unregister_xenbus_watch(&xxwp->xxw_watch); 1367 9243 Mark mutex_enter(&pdp->xd_ndi_lk); 1368 8863 Edward i_xvdi_xb_watch_release(xxwp); 1369 8863 Edward } 1370 8863 Edward ASSERT(list_is_empty(&pdp->xd_xb_watches)); 1371 8863 Edward 1372 8863 Edward /* 1373 8863 Edward * We can't hold xd_ndi_lk while we destroy the xd_xb_watch_taskq. 1374 8863 Edward * This is because if there are currently any executing taskq threads, 1375 8863 Edward * we will block until they are finished, and to finish they need 1376 8863 Edward * to aquire xd_ndi_lk in i_xvdi_xb_watch_cb_tq() so they can release 1377 8863 Edward * their reference on their corresponding xxwp structure. 1378 8863 Edward */ 1379 8863 Edward tq = pdp->xd_xb_watch_taskq; 1380 8863 Edward pdp->xd_xb_watch_taskq = NULL; 1381 8863 Edward mutex_exit(&pdp->xd_ndi_lk); 1382 8863 Edward if (tq != NULL) 1383 8863 Edward ddi_taskq_destroy(tq); 1384 8863 Edward } 1385 8863 Edward 1386 5084 johnlev static int 1387 5084 johnlev i_xvdi_add_watch_oestate(dev_info_t *dip) 1388 5084 johnlev { 1389 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1390 5084 johnlev 1391 5084 johnlev ASSERT(pdp != NULL); 1392 5084 johnlev ASSERT(pdp->xd_xsdev.nodename != NULL); 1393 7756 Mark ASSERT(mutex_owned(&pdp->xd_ndi_lk)); 1394 5084 johnlev 1395 5084 johnlev /* 1396 5084 johnlev * Create taskq for delivering other end state change event to 1397 5084 johnlev * this device later. 1398 5084 johnlev * 1399 5084 johnlev * Set nthreads to 1 to make sure that events can be delivered 1400 5084 johnlev * in order. 1401 5084 johnlev * 1402 5084 johnlev * Note: It is _not_ guaranteed that driver can see every 1403 5084 johnlev * xenstore change under the path that it is watching. If two 1404 5084 johnlev * changes happen consecutively in a very short amount of 1405 5084 johnlev * time, it is likely that the driver will see only the last 1406 5084 johnlev * one. 1407 5084 johnlev */ 1408 5084 johnlev if (pdp->xd_oe_taskq == NULL) 1409 5084 johnlev if ((pdp->xd_oe_taskq = ddi_taskq_create(dip, 1410 5084 johnlev "xendev_oe_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL) 1411 5084 johnlev return (DDI_FAILURE); 1412 5084 johnlev 1413 5084 johnlev /* 1414 5084 johnlev * Watch for changes to the XenbusState of otherend. 1415 5084 johnlev */ 1416 5084 johnlev pdp->xd_xsdev.otherend_state = XenbusStateUnknown; 1417 5084 johnlev pdp->xd_xsdev.otherend_changed = i_xvdi_oestate_cb; 1418 5084 johnlev 1419 5084 johnlev if (talk_to_otherend(&pdp->xd_xsdev) != 0) { 1420 5084 johnlev i_xvdi_rem_watch_oestate(dip); 1421 5084 johnlev return (DDI_FAILURE); 1422 5084 johnlev } 1423 5084 johnlev 1424 5084 johnlev return (DDI_SUCCESS); 1425 5084 johnlev } 1426 5084 johnlev 1427 5084 johnlev static void 1428 5084 johnlev i_xvdi_rem_watch_oestate(dev_info_t *dip) 1429 5084 johnlev { 1430 5084 johnlev struct xendev_ppd *pdp; 1431 5084 johnlev struct xenbus_device *dev; 1432 5084 johnlev 1433 5084 johnlev pdp = ddi_get_parent_data(dip); 1434 5084 johnlev ASSERT(pdp != NULL); 1435 7756 Mark ASSERT(mutex_owned(&pdp->xd_ndi_lk)); 1436 5084 johnlev 1437 5084 johnlev dev = &pdp->xd_xsdev; 1438 5084 johnlev 1439 5084 johnlev /* Unwatch for changes to XenbusState of otherend */ 1440 5084 johnlev if (dev->otherend_watch.node != NULL) { 1441 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1442 5084 johnlev unregister_xenbus_watch(&dev->otherend_watch); 1443 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1444 5084 johnlev } 1445 5084 johnlev 1446 5084 johnlev /* make sure no event handler is running */ 1447 5084 johnlev if (pdp->xd_oe_taskq != NULL) { 1448 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1449 5084 johnlev ddi_taskq_destroy(pdp->xd_oe_taskq); 1450 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1451 5084 johnlev pdp->xd_oe_taskq = NULL; 1452 5084 johnlev } 1453 5084 johnlev 1454 5084 johnlev /* clean up */ 1455 5084 johnlev dev->otherend_state = XenbusStateUnknown; 1456 5084 johnlev dev->otherend_id = (domid_t)-1; 1457 5084 johnlev if (dev->otherend_watch.node != NULL) 1458 5084 johnlev kmem_free((void *)dev->otherend_watch.node, 1459 5084 johnlev strlen(dev->otherend_watch.node) + 1); 1460 5084 johnlev dev->otherend_watch.node = NULL; 1461 5084 johnlev if (dev->otherend != NULL) 1462 5084 johnlev kmem_free((void *)dev->otherend, strlen(dev->otherend) + 1); 1463 5084 johnlev dev->otherend = NULL; 1464 5084 johnlev } 1465 5084 johnlev 1466 5084 johnlev static int 1467 5084 johnlev i_xvdi_add_watch_hpstate(dev_info_t *dip) 1468 5084 johnlev { 1469 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1470 5084 johnlev 1471 5084 johnlev ASSERT(pdp != NULL); 1472 5084 johnlev ASSERT(pdp->xd_xsdev.frontend == 0); 1473 7756 Mark ASSERT(mutex_owned(&pdp->xd_ndi_lk)); 1474 5084 johnlev 1475 5084 johnlev /* 1476 5084 johnlev * Create taskq for delivering hotplug status change event to 1477 5084 johnlev * this device later. 1478 5084 johnlev * 1479 5084 johnlev * Set nthreads to 1 to make sure that events can be delivered 1480 5084 johnlev * in order. 1481 5084 johnlev * 1482 5084 johnlev * Note: It is _not_ guaranteed that driver can see every 1483 5084 johnlev * hotplug status change under the path that it is 1484 5084 johnlev * watching. If two changes happen consecutively in a very 1485 5084 johnlev * short amount of time, it is likely that the driver only 1486 5084 johnlev * sees the last one. 1487 5084 johnlev */ 1488 5084 johnlev if (pdp->xd_hp_taskq == NULL) 1489 5084 johnlev if ((pdp->xd_hp_taskq = ddi_taskq_create(dip, 1490 5084 johnlev "xendev_hp_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL) 1491 5084 johnlev return (DDI_FAILURE); 1492 5084 johnlev 1493 5084 johnlev if (pdp->xd_hp_watch.node == NULL) { 1494 5084 johnlev size_t len; 1495 5084 johnlev char *path; 1496 5084 johnlev 1497 5084 johnlev ASSERT(pdp->xd_xsdev.nodename != NULL); 1498 5084 johnlev 1499 5084 johnlev len = strlen(pdp->xd_xsdev.nodename) + 1500 5084 johnlev strlen("/hotplug-status") + 1; 1501 5084 johnlev path = kmem_alloc(len, KM_SLEEP); 1502 5084 johnlev (void) snprintf(path, len, "%s/hotplug-status", 1503 5084 johnlev pdp->xd_xsdev.nodename); 1504 5084 johnlev 1505 5084 johnlev pdp->xd_hp_watch.node = path; 1506 5084 johnlev pdp->xd_hp_watch.callback = i_xvdi_hpstate_cb; 1507 5084 johnlev pdp->xd_hp_watch.dev = (struct xenbus_device *)dip; /* yuck! */ 1508 5084 johnlev if (register_xenbus_watch(&pdp->xd_hp_watch) != 0) { 1509 5084 johnlev i_xvdi_rem_watch_hpstate(dip); 1510 5084 johnlev return (DDI_FAILURE); 1511 5084 johnlev } 1512 5084 johnlev } 1513 5084 johnlev 1514 5084 johnlev return (DDI_SUCCESS); 1515 5084 johnlev } 1516 5084 johnlev 1517 5084 johnlev static void 1518 5084 johnlev i_xvdi_rem_watch_hpstate(dev_info_t *dip) 1519 5084 johnlev { 1520 5084 johnlev struct xendev_ppd *pdp; 1521 5084 johnlev pdp = ddi_get_parent_data(dip); 1522 5084 johnlev 1523 5084 johnlev ASSERT(pdp != NULL); 1524 5084 johnlev ASSERT(pdp->xd_xsdev.frontend == 0); 1525 7756 Mark ASSERT(mutex_owned(&pdp->xd_ndi_lk)); 1526 5084 johnlev 1527 5084 johnlev /* Unwatch for changes to "hotplug-status" node for backend device. */ 1528 5084 johnlev if (pdp->xd_hp_watch.node != NULL) { 1529 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1530 5084 johnlev unregister_xenbus_watch(&pdp->xd_hp_watch); 1531 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1532 5084 johnlev } 1533 5084 johnlev 1534 5084 johnlev /* Make sure no event handler is running. */ 1535 5084 johnlev if (pdp->xd_hp_taskq != NULL) { 1536 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1537 5084 johnlev ddi_taskq_destroy(pdp->xd_hp_taskq); 1538 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1539 5084 johnlev pdp->xd_hp_taskq = NULL; 1540 5084 johnlev } 1541 5084 johnlev 1542 5084 johnlev /* Clean up. */ 1543 5084 johnlev if (pdp->xd_hp_watch.node != NULL) { 1544 5084 johnlev kmem_free((void *)pdp->xd_hp_watch.node, 1545 5084 johnlev strlen(pdp->xd_hp_watch.node) + 1); 1546 5084 johnlev pdp->xd_hp_watch.node = NULL; 1547 5084 johnlev } 1548 5084 johnlev } 1549 5084 johnlev 1550 5084 johnlev static int 1551 5084 johnlev i_xvdi_add_watches(dev_info_t *dip) 1552 5084 johnlev { 1553 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1554 5084 johnlev 1555 5084 johnlev ASSERT(pdp != NULL); 1556 5084 johnlev 1557 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1558 5084 johnlev 1559 5084 johnlev if (i_xvdi_add_watch_oestate(dip) != DDI_SUCCESS) { 1560 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1561 5084 johnlev return (DDI_FAILURE); 1562 5084 johnlev } 1563 5084 johnlev 1564 5084 johnlev if (pdp->xd_xsdev.frontend == 1) { 1565 5084 johnlev /* 1566 5084 johnlev * Frontend devices must watch for the backend path 1567 5084 johnlev * changing. 1568 5084 johnlev */ 1569 5084 johnlev if (i_xvdi_add_watch_bepath(dip) != DDI_SUCCESS) 1570 5084 johnlev goto unwatch_and_fail; 1571 5084 johnlev } else { 1572 5084 johnlev /* 1573 5084 johnlev * Backend devices must watch for hotplug events. 1574 5084 johnlev */ 1575 5084 johnlev if (i_xvdi_add_watch_hpstate(dip) != DDI_SUCCESS) 1576 5084 johnlev goto unwatch_and_fail; 1577 5084 johnlev } 1578 5084 johnlev 1579 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1580 5084 johnlev 1581 5084 johnlev return (DDI_SUCCESS); 1582 5084 johnlev 1583 5084 johnlev unwatch_and_fail: 1584 5084 johnlev i_xvdi_rem_watch_oestate(dip); 1585 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1586 5084 johnlev 1587 5084 johnlev return (DDI_FAILURE); 1588 5084 johnlev } 1589 5084 johnlev 1590 5084 johnlev static void 1591 5084 johnlev i_xvdi_rem_watches(dev_info_t *dip) 1592 5084 johnlev { 1593 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1594 5084 johnlev 1595 5084 johnlev ASSERT(pdp != NULL); 1596 5084 johnlev 1597 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1598 5084 johnlev 1599 5084 johnlev i_xvdi_rem_watch_oestate(dip); 1600 5084 johnlev 1601 5084 johnlev if (pdp->xd_xsdev.frontend == 1) 1602 5084 johnlev i_xvdi_rem_watch_bepath(dip); 1603 5084 johnlev else 1604 5084 johnlev i_xvdi_rem_watch_hpstate(dip); 1605 5084 johnlev 1606 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1607 8863 Edward 1608 8863 Edward xvdi_remove_xb_watch_handlers(dip); 1609 5084 johnlev } 1610 5084 johnlev 1611 5084 johnlev static int 1612 5084 johnlev i_xvdi_add_watch_bepath(dev_info_t *dip) 1613 5084 johnlev { 1614 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1615 5084 johnlev 1616 5084 johnlev ASSERT(pdp != NULL); 1617 5084 johnlev ASSERT(pdp->xd_xsdev.frontend == 1); 1618 5084 johnlev 1619 5084 johnlev /* 1620 5084 johnlev * Frontend devices need to watch for the backend path changing. 1621 5084 johnlev */ 1622 5084 johnlev if (pdp->xd_bepath_watch.node == NULL) { 1623 5084 johnlev size_t len; 1624 5084 johnlev char *path; 1625 5084 johnlev 1626 5084 johnlev ASSERT(pdp->xd_xsdev.nodename != NULL); 1627 5084 johnlev 1628 5084 johnlev len = strlen(pdp->xd_xsdev.nodename) + strlen("/backend") + 1; 1629 5084 johnlev path = kmem_alloc(len, KM_SLEEP); 1630 5084 johnlev (void) snprintf(path, len, "%s/backend", 1631 5084 johnlev pdp->xd_xsdev.nodename); 1632 5084 johnlev 1633 5084 johnlev pdp->xd_bepath_watch.node = path; 1634 5084 johnlev pdp->xd_bepath_watch.callback = i_xvdi_bepath_cb; 1635 5084 johnlev pdp->xd_bepath_watch.dev = (struct xenbus_device *)dip; 1636 5084 johnlev if (register_xenbus_watch(&pdp->xd_bepath_watch) != 0) { 1637 5084 johnlev kmem_free(path, len); 1638 5084 johnlev pdp->xd_bepath_watch.node = NULL; 1639 5084 johnlev return (DDI_FAILURE); 1640 5084 johnlev } 1641 5084 johnlev } 1642 5084 johnlev 1643 5084 johnlev return (DDI_SUCCESS); 1644 5084 johnlev } 1645 5084 johnlev 1646 5084 johnlev static void 1647 5084 johnlev i_xvdi_rem_watch_bepath(dev_info_t *dip) 1648 5084 johnlev { 1649 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1650 5084 johnlev 1651 5084 johnlev ASSERT(pdp != NULL); 1652 5084 johnlev ASSERT(pdp->xd_xsdev.frontend == 1); 1653 7756 Mark ASSERT(mutex_owned(&pdp->xd_ndi_lk)); 1654 5084 johnlev 1655 5084 johnlev if (pdp->xd_bepath_watch.node != NULL) { 1656 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1657 5084 johnlev unregister_xenbus_watch(&pdp->xd_bepath_watch); 1658 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1659 5084 johnlev 1660 5084 johnlev kmem_free((void *)(pdp->xd_bepath_watch.node), 1661 5084 johnlev strlen(pdp->xd_bepath_watch.node) + 1); 1662 5084 johnlev pdp->xd_bepath_watch.node = NULL; 1663 5084 johnlev } 1664 5084 johnlev } 1665 5084 johnlev 1666 5084 johnlev int 1667 5084 johnlev xvdi_switch_state(dev_info_t *dip, xenbus_transaction_t xbt, 1668 5084 johnlev XenbusState newState) 1669 5084 johnlev { 1670 5084 johnlev int rv; 1671 5084 johnlev struct xendev_ppd *pdp; 1672 5084 johnlev 1673 5084 johnlev pdp = ddi_get_parent_data(dip); 1674 5084 johnlev ASSERT(pdp != NULL); 1675 5084 johnlev 1676 5084 johnlev XVDI_DPRINTF(XVDI_DBG_STATE, 1677 7679 Max "xvdi_switch_state: %s@%s's xenbus state moves to %d\n", 1678 7679 Max ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip), 1679 7679 Max ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip), 1680 7679 Max newState); 1681 5084 johnlev 1682 5084 johnlev rv = xenbus_switch_state(&pdp->xd_xsdev, xbt, newState); 1683 5084 johnlev if (rv > 0) 1684 5084 johnlev cmn_err(CE_WARN, "xvdi_switch_state: change state failed"); 1685 5084 johnlev 1686 5084 johnlev return (rv); 1687 5084 johnlev } 1688 5084 johnlev 1689 5084 johnlev /* 1690 5084 johnlev * Notify hotplug script running in userland 1691 5084 johnlev */ 1692 5084 johnlev int 1693 5084 johnlev xvdi_post_event(dev_info_t *dip, xendev_hotplug_cmd_t hpc) 1694 5084 johnlev { 1695 5084 johnlev struct xendev_ppd *pdp; 1696 5084 johnlev nvlist_t *attr_list = NULL; 1697 5084 johnlev i_xd_cfg_t *xdcp; 1698 5084 johnlev sysevent_id_t eid; 1699 5084 johnlev int err; 1700 5084 johnlev char devname[256]; /* XXPV dme: ? */ 1701 5084 johnlev 1702 5084 johnlev pdp = ddi_get_parent_data(dip); 1703 5084 johnlev ASSERT(pdp != NULL); 1704 5084 johnlev 1705 5084 johnlev xdcp = i_xvdi_devclass2cfg(pdp->xd_devclass); 1706 5084 johnlev ASSERT(xdcp != NULL); 1707 5084 johnlev 1708 5084 johnlev (void) snprintf(devname, sizeof (devname) - 1, "%s%d", 1709 5084 johnlev ddi_driver_name(dip), ddi_get_instance(dip)); 1710 5084 johnlev 1711 5084 johnlev err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME, KM_NOSLEEP); 1712 5084 johnlev if (err != DDI_SUCCESS) 1713 5084 johnlev goto failure; 1714 5084 johnlev 1715 5084 johnlev err = nvlist_add_int32(attr_list, "domain", pdp->xd_domain); 1716 5084 johnlev if (err != DDI_SUCCESS) 1717 5084 johnlev goto failure; 1718 5084 johnlev err = nvlist_add_int32(attr_list, "vdev", pdp->xd_vdevnum); 1719 5084 johnlev if (err != DDI_SUCCESS) 1720 5084 johnlev goto failure; 1721 5084 johnlev err = nvlist_add_string(attr_list, "devclass", xdcp->xsdev); 1722 5084 johnlev if (err != DDI_SUCCESS) 1723 5084 johnlev goto failure; 1724 5084 johnlev err = nvlist_add_string(attr_list, "device", devname); 1725 5084 johnlev if (err != DDI_SUCCESS) 1726 5084 johnlev goto failure; 1727 5084 johnlev err = nvlist_add_string(attr_list, "fob", 1728 5084 johnlev ((pdp->xd_xsdev.frontend == 1) ? "frontend" : "backend")); 1729 5084 johnlev if (err != DDI_SUCCESS) 1730 5084 johnlev goto failure; 1731 5084 johnlev 1732 5084 johnlev switch (hpc) { 1733 5084 johnlev case XEN_HP_ADD: 1734 5084 johnlev err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev", 1735 5084 johnlev "add", attr_list, &eid, DDI_NOSLEEP); 1736 5084 johnlev break; 1737 5084 johnlev case XEN_HP_REMOVE: 1738 5084 johnlev err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev", 1739 5084 johnlev "remove", attr_list, &eid, DDI_NOSLEEP); 1740 5084 johnlev break; 1741 5084 johnlev default: 1742 5084 johnlev err = DDI_FAILURE; 1743 5084 johnlev goto failure; 1744 5084 johnlev } 1745 5084 johnlev 1746 5084 johnlev failure: 1747 5084 johnlev if (attr_list != NULL) 1748 5084 johnlev nvlist_free(attr_list); 1749 5084 johnlev 1750 5084 johnlev return (err); 1751 5084 johnlev } 1752 5084 johnlev 1753 5084 johnlev /* ARGSUSED */ 1754 5084 johnlev static void 1755 5084 johnlev i_xvdi_probe_path_cb(struct xenbus_watch *w, const char **vec, 1756 5084 johnlev unsigned int len) 1757 5084 johnlev { 1758 5084 johnlev char *path; 1759 5084 johnlev 1760 5084 johnlev if (xendev_dip == NULL) 1761 5084 johnlev xendev_dip = ddi_find_devinfo("xpvd", -1, 0); 1762 5084 johnlev 1763 5084 johnlev path = i_ddi_strdup((char *)vec[XS_WATCH_PATH], KM_SLEEP); 1764 5084 johnlev 1765 5084 johnlev (void) ddi_taskq_dispatch(DEVI(xendev_dip)->devi_taskq, 1766 5084 johnlev i_xvdi_probe_path_handler, (void *)path, DDI_SLEEP); 1767 5084 johnlev } 1768 5084 johnlev 1769 5084 johnlev static void 1770 5084 johnlev i_xvdi_watch_device(char *path) 1771 5084 johnlev { 1772 5084 johnlev struct xenbus_watch *w; 1773 5084 johnlev 1774 5084 johnlev ASSERT(path != NULL); 1775 5084 johnlev 1776 5084 johnlev w = kmem_zalloc(sizeof (*w), KM_SLEEP); 1777 5084 johnlev w->node = path; 1778 5084 johnlev w->callback = &i_xvdi_probe_path_cb; 1779 5084 johnlev w->dev = NULL; 1780 5084 johnlev 1781 5084 johnlev if (register_xenbus_watch(w) != 0) { 1782 5084 johnlev cmn_err(CE_WARN, "i_xvdi_watch_device: " 1783 5084 johnlev "cannot set watch on %s", path); 1784 5084 johnlev kmem_free(w, sizeof (*w)); 1785 5084 johnlev return; 1786 5084 johnlev } 1787 5084 johnlev } 1788 5084 johnlev 1789 5084 johnlev void 1790 5084 johnlev xvdi_watch_devices(int newstate) 1791 5084 johnlev { 1792 5084 johnlev int devclass; 1793 5084 johnlev 1794 5084 johnlev /* 1795 5084 johnlev * Watch for devices being created in the store. 1796 5084 johnlev */ 1797 5084 johnlev if (newstate == XENSTORE_DOWN) 1798 5084 johnlev return; 1799 5084 johnlev for (devclass = 0; devclass < NXDC; devclass++) { 1800 5084 johnlev if (xdci[devclass].xs_path_fe != NULL) 1801 5084 johnlev i_xvdi_watch_device(xdci[devclass].xs_path_fe); 1802 5084 johnlev if (xdci[devclass].xs_path_be != NULL) 1803 5084 johnlev i_xvdi_watch_device(xdci[devclass].xs_path_be); 1804 5084 johnlev } 1805 5084 johnlev } 1806 5084 johnlev 1807 5084 johnlev /* 1808 5084 johnlev * Iterate over the store looking for backend devices to create. 1809 5084 johnlev */ 1810 5084 johnlev static void 1811 5084 johnlev i_xvdi_enum_be(dev_info_t *parent, i_xd_cfg_t *xdcp) 1812 5084 johnlev { 1813 5084 johnlev char **domains; 1814 5084 johnlev unsigned int ndomains; 1815 5084 johnlev int ldomains, i; 1816 5084 johnlev 1817 5084 johnlev if ((domains = xenbus_directory(XBT_NULL, xdcp->xs_path_be, "", 1818 5084 johnlev &ndomains)) == NULL) 1819 5084 johnlev return; 1820 5084 johnlev 1821 5084 johnlev for (i = 0, ldomains = 0; i < ndomains; i++) { 1822 5084 johnlev ldomains += strlen(domains[i]) + 1 + sizeof (char *); 1823 5084 johnlev 1824 5084 johnlev i_xvdi_enum_worker(parent, xdcp, domains[i]); 1825 5084 johnlev } 1826 5084 johnlev kmem_free(domains, ldomains); 1827 5084 johnlev } 1828 5084 johnlev 1829 5084 johnlev /* 1830 5084 johnlev * Iterate over the store looking for frontend devices to create. 1831 5084 johnlev */ 1832 5084 johnlev static void 1833 5084 johnlev i_xvdi_enum_fe(dev_info_t *parent, i_xd_cfg_t *xdcp) 1834 5084 johnlev { 1835 5084 johnlev i_xvdi_enum_worker(parent, xdcp, NULL); 1836 5084 johnlev } 1837 5084 johnlev 1838 5084 johnlev static void 1839 5084 johnlev i_xvdi_enum_worker(dev_info_t *parent, i_xd_cfg_t *xdcp, 1840 5084 johnlev char *domain) 1841 5084 johnlev { 1842 5084 johnlev char *path, *domain_path, *ep; 1843 5084 johnlev char **devices; 1844 5084 johnlev unsigned int ndevices; 1845 5084 johnlev int ldevices, j, circ; 1846 5084 johnlev domid_t dom; 1847 6460 edp long tmplong; 1848 5084 johnlev 1849 5084 johnlev if (domain == NULL) { 1850 5084 johnlev dom = DOMID_SELF; 1851 5084 johnlev path = xdcp->xs_path_fe; 1852 5084 johnlev domain_path = ""; 1853 5084 johnlev } else { 1854 6460 edp (void) ddi_strtol(domain, &ep, 0, &tmplong); 1855 6460 edp dom = tmplong; 1856 5084 johnlev path = xdcp->xs_path_be; 1857 5084 johnlev domain_path = domain; 1858 5084 johnlev } 1859 5084 johnlev 1860 5084 johnlev if ((devices = xenbus_directory(XBT_NULL, path, domain_path, 1861 5084 johnlev &ndevices)) == NULL) 1862 5084 johnlev return; 1863 5084 johnlev 1864 5084 johnlev for (j = 0, ldevices = 0; j < ndevices; j++) { 1865 5084 johnlev int vdev; 1866 5084 johnlev 1867 5084 johnlev ldevices += strlen(devices[j]) + 1 + sizeof (char *); 1868 6460 edp (void) ddi_strtol(devices[j], &ep, 0, &tmplong); 1869 6460 edp vdev = tmplong; 1870 5084 johnlev 1871 5084 johnlev ndi_devi_enter(parent, &circ); 1872 5084 johnlev 1873 6460 edp if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL) 1874 5084 johnlev (void) xvdi_create_dev(parent, xdcp->devclass, 1875 5084 johnlev dom, vdev); 1876 5084 johnlev 1877 5084 johnlev ndi_devi_exit(parent, circ); 1878 5084 johnlev } 1879 5084 johnlev kmem_free(devices, ldevices); 1880 5084 johnlev } 1881 5084 johnlev 1882 5084 johnlev /* 1883 5084 johnlev * Leaf drivers should call this in their detach() routine during suspend. 1884 5084 johnlev */ 1885 5084 johnlev void 1886 5084 johnlev xvdi_suspend(dev_info_t *dip) 1887 5084 johnlev { 1888 5084 johnlev i_xvdi_rem_watches(dip); 1889 5084 johnlev } 1890 5084 johnlev 1891 5084 johnlev /* 1892 5084 johnlev * Leaf drivers should call this in their attach() routine during resume. 1893 5084 johnlev */ 1894 5084 johnlev int 1895 5084 johnlev xvdi_resume(dev_info_t *dip) 1896 5084 johnlev { 1897 5084 johnlev return (i_xvdi_add_watches(dip)); 1898 5084 johnlev } 1899 5084 johnlev 1900 5084 johnlev /* 1901 5084 johnlev * Add event handler for the leaf driver 1902 5084 johnlev * to handle event triggered by the change in xenstore 1903 5084 johnlev */ 1904 5084 johnlev int 1905 5084 johnlev xvdi_add_event_handler(dev_info_t *dip, char *name, 1906 7756 Mark void (*evthandler)(dev_info_t *, ddi_eventcookie_t, void *, void *), 1907 7756 Mark void *arg) 1908 5084 johnlev { 1909 5084 johnlev ddi_eventcookie_t ecv; 1910 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 1911 5084 johnlev ddi_callback_id_t *cbid; 1912 7756 Mark boolean_t call_handler; 1913 7756 Mark i_oestate_evt_t *evt = NULL; 1914 7756 Mark XenbusState oestate; 1915 5084 johnlev 1916 5084 johnlev ASSERT(pdp != NULL); 1917 5084 johnlev 1918 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 1919 5084 johnlev 1920 5084 johnlev if (strcmp(name, XS_OE_STATE) == 0) { 1921 5084 johnlev ASSERT(pdp->xd_xsdev.otherend != NULL); 1922 5084 johnlev 1923 5084 johnlev cbid = &pdp->xd_oe_ehid; 1924 5084 johnlev } else if (strcmp(name, XS_HP_STATE) == 0) { 1925 5084 johnlev if (pdp->xd_xsdev.frontend == 1) { 1926 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1927 5084 johnlev return (DDI_FAILURE); 1928 5084 johnlev } 1929 5084 johnlev 1930 5084 johnlev ASSERT(pdp->xd_hp_watch.node != NULL); 1931 5084 johnlev 1932 5084 johnlev cbid = &pdp->xd_hp_ehid; 1933 5084 johnlev } else { 1934 5084 johnlev /* Unsupported watch. */ 1935 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1936 5084 johnlev return (DDI_FAILURE); 1937 5084 johnlev } 1938 5084 johnlev 1939 5084 johnlev /* 1940 5084 johnlev * No event handler provided, take default action to handle 1941 5084 johnlev * event. 1942 5084 johnlev */ 1943 5084 johnlev if (evthandler == NULL) { 1944 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1945 5084 johnlev return (DDI_SUCCESS); 1946 5084 johnlev } 1947 5084 johnlev 1948 5084 johnlev ASSERT(*cbid == NULL); 1949 5084 johnlev 1950 5084 johnlev if (ddi_get_eventcookie(dip, name, &ecv) != DDI_SUCCESS) { 1951 5084 johnlev cmn_err(CE_WARN, "failed to find %s cookie for %s@%s", 1952 5084 johnlev name, ddi_get_name(dip), ddi_get_name_addr(dip)); 1953 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1954 5084 johnlev return (DDI_FAILURE); 1955 5084 johnlev } 1956 7756 Mark if (ddi_add_event_handler(dip, ecv, evthandler, arg, cbid) 1957 5084 johnlev != DDI_SUCCESS) { 1958 5084 johnlev cmn_err(CE_WARN, "failed to add %s event handler for %s@%s", 1959 5084 johnlev name, ddi_get_name(dip), ddi_get_name_addr(dip)); 1960 5084 johnlev *cbid = NULL; 1961 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1962 5084 johnlev return (DDI_FAILURE); 1963 5084 johnlev } 1964 5084 johnlev 1965 7756 Mark /* 1966 7756 Mark * if we're adding an oe state callback, and the ring has already 1967 7756 Mark * transitioned out of Unknown, call the handler after we release 1968 7756 Mark * the mutex. 1969 7756 Mark */ 1970 7756 Mark call_handler = B_FALSE; 1971 7756 Mark if ((strcmp(name, XS_OE_STATE) == 0) && 1972 7756 Mark (pdp->xd_xsdev.otherend_state != XenbusStateUnknown)) { 1973 7756 Mark oestate = pdp->xd_xsdev.otherend_state; 1974 7756 Mark call_handler = B_TRUE; 1975 7756 Mark } 1976 7756 Mark 1977 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 1978 7756 Mark 1979 7756 Mark if (call_handler) { 1980 7756 Mark evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP); 1981 7756 Mark evt->dip = dip; 1982 7756 Mark evt->state = oestate; 1983 7756 Mark (void) ddi_taskq_dispatch(pdp->xd_oe_taskq, 1984 7756 Mark i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP); 1985 7756 Mark } 1986 5084 johnlev 1987 5084 johnlev return (DDI_SUCCESS); 1988 5084 johnlev } 1989 5084 johnlev 1990 5084 johnlev /* 1991 5084 johnlev * Remove event handler for the leaf driver and unwatch xenstore 1992 5084 johnlev * so, driver will not be notified when xenstore entry changed later 1993 5084 johnlev */ 1994 5084 johnlev void 1995 5084 johnlev xvdi_remove_event_handler(dev_info_t *dip, char *name) 1996 5084 johnlev { 1997 5084 johnlev struct xendev_ppd *pdp; 1998 5084 johnlev boolean_t rem_oe = B_FALSE, rem_hp = B_FALSE; 1999 5084 johnlev ddi_callback_id_t oeid = NULL, hpid = NULL; 2000 5084 johnlev 2001 5084 johnlev pdp = ddi_get_parent_data(dip); 2002 5084 johnlev ASSERT(pdp != NULL); 2003 5084 johnlev 2004 5084 johnlev if (name == NULL) { 2005 5084 johnlev rem_oe = B_TRUE; 2006 5084 johnlev rem_hp = B_TRUE; 2007 5084 johnlev } else if (strcmp(name, XS_OE_STATE) == 0) { 2008 5084 johnlev rem_oe = B_TRUE; 2009 5084 johnlev } else if (strcmp(name, XS_HP_STATE) == 0) { 2010 5084 johnlev rem_hp = B_TRUE; 2011 5084 johnlev } else { 2012 5084 johnlev cmn_err(CE_WARN, "event %s not supported, cannot remove", name); 2013 5084 johnlev return; 2014 5084 johnlev } 2015 5084 johnlev 2016 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 2017 5084 johnlev 2018 5084 johnlev if (rem_oe && (pdp->xd_oe_ehid != NULL)) { 2019 5084 johnlev oeid = pdp->xd_oe_ehid; 2020 5084 johnlev pdp->xd_oe_ehid = NULL; 2021 5084 johnlev } 2022 5084 johnlev 2023 5084 johnlev if (rem_hp && (pdp->xd_hp_ehid != NULL)) { 2024 5084 johnlev hpid = pdp->xd_hp_ehid; 2025 5084 johnlev pdp->xd_hp_ehid = NULL; 2026 5084 johnlev } 2027 5084 johnlev 2028 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 2029 5084 johnlev 2030 5084 johnlev if (oeid != NULL) 2031 5084 johnlev (void) ddi_remove_event_handler(oeid); 2032 5084 johnlev if (hpid != NULL) 2033 5084 johnlev (void) ddi_remove_event_handler(hpid); 2034 5084 johnlev } 2035 5084 johnlev 2036 5084 johnlev 2037 5084 johnlev /* 2038 5084 johnlev * common ring interfaces 2039 5084 johnlev */ 2040 5084 johnlev 2041 5084 johnlev #define FRONT_RING(_ringp) (&(_ringp)->xr_sring.fr) 2042 5084 johnlev #define BACK_RING(_ringp) (&(_ringp)->xr_sring.br) 2043 5084 johnlev #define GET_RING_SIZE(_ringp) RING_SIZE(FRONT_RING(ringp)) 2044 5084 johnlev #define GET_RING_ENTRY_FE(_ringp, _idx) \ 2045 5084 johnlev (FRONT_RING(_ringp)->sring->ring + \ 2046 5084 johnlev (_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1))) 2047 5084 johnlev #define GET_RING_ENTRY_BE(_ringp, _idx) \ 2048 5084 johnlev (BACK_RING(_ringp)->sring->ring + \ 2049 5084 johnlev (_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1))) 2050 5084 johnlev 2051 5084 johnlev unsigned int 2052 5084 johnlev xvdi_ring_avail_slots(xendev_ring_t *ringp) 2053 5084 johnlev { 2054 5084 johnlev comif_ring_fe_t *frp; 2055 5084 johnlev comif_ring_be_t *brp; 2056 5084 johnlev 2057 5084 johnlev if (ringp->xr_frontend) { 2058 5084 johnlev frp = FRONT_RING(ringp); 2059 5084 johnlev return (GET_RING_SIZE(ringp) - 2060 5084 johnlev (frp->req_prod_pvt - frp->rsp_cons)); 2061 5084 johnlev } else { 2062 5084 johnlev brp = BACK_RING(ringp); 2063 5084 johnlev return (GET_RING_SIZE(ringp) - 2064 5084 johnlev (brp->rsp_prod_pvt - brp->req_cons)); 2065 5084 johnlev } 2066 5084 johnlev } 2067 5084 johnlev 2068 5084 johnlev int 2069 5084 johnlev xvdi_ring_has_unconsumed_requests(xendev_ring_t *ringp) 2070 5084 johnlev { 2071 5084 johnlev comif_ring_be_t *brp; 2072 5084 johnlev 2073 5084 johnlev ASSERT(!ringp->xr_frontend); 2074 5084 johnlev brp = BACK_RING(ringp); 2075 5084 johnlev return ((brp->req_cons != 2076 5084 johnlev ddi_get32(ringp->xr_acc_hdl, &brp->sring->req_prod)) && 2077 5084 johnlev ((brp->req_cons - brp->rsp_prod_pvt) != RING_SIZE(brp))); 2078 5084 johnlev } 2079 5084 johnlev 2080 5084 johnlev int 2081 5084 johnlev xvdi_ring_has_incomp_request(xendev_ring_t *ringp) 2082 5084 johnlev { 2083 5084 johnlev comif_ring_fe_t *frp; 2084 5084 johnlev 2085 5084 johnlev ASSERT(ringp->xr_frontend); 2086 5084 johnlev frp = FRONT_RING(ringp); 2087 5084 johnlev return (frp->req_prod_pvt != 2088 5084 johnlev ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod)); 2089 5084 johnlev } 2090 5084 johnlev 2091 5084 johnlev int 2092 5084 johnlev xvdi_ring_has_unconsumed_responses(xendev_ring_t *ringp) 2093 5084 johnlev { 2094 5084 johnlev comif_ring_fe_t *frp; 2095 5084 johnlev 2096 5084 johnlev ASSERT(ringp->xr_frontend); 2097 5084 johnlev frp = FRONT_RING(ringp); 2098 5084 johnlev return (frp->rsp_cons != 2099 5084 johnlev ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod)); 2100 5084 johnlev } 2101 5084 johnlev 2102 5084 johnlev /* NOTE: req_event will be increased as needed */ 2103 5084 johnlev void * 2104 5084 johnlev xvdi_ring_get_request(xendev_ring_t *ringp) 2105 5084 johnlev { 2106 5084 johnlev comif_ring_fe_t *frp; 2107 5084 johnlev comif_ring_be_t *brp; 2108 5084 johnlev 2109 5084 johnlev if (ringp->xr_frontend) { 2110 5084 johnlev /* for frontend ring */ 2111 5084 johnlev frp = FRONT_RING(ringp); 2112 5084 johnlev if (!RING_FULL(frp)) 2113 5084 johnlev return (GET_RING_ENTRY_FE(ringp, frp->req_prod_pvt++)); 2114 5084 johnlev else 2115 5084 johnlev return (NULL); 2116 5084 johnlev } else { 2117 5084 johnlev /* for backend ring */ 2118 5084 johnlev brp = BACK_RING(ringp); 2119 5084 johnlev /* RING_FINAL_CHECK_FOR_REQUESTS() */ 2120 5084 johnlev if (xvdi_ring_has_unconsumed_requests(ringp)) 2121 5084 johnlev return (GET_RING_ENTRY_BE(ringp, brp->req_cons++)); 2122 5084 johnlev else { 2123 5084 johnlev ddi_put32(ringp->xr_acc_hdl, &brp->sring->req_event, 2124 5084 johnlev brp->req_cons + 1); 2125 5084 johnlev membar_enter(); 2126 5084 johnlev if (xvdi_ring_has_unconsumed_requests(ringp)) 2127 5084 johnlev return (GET_RING_ENTRY_BE(ringp, 2128 5084 johnlev brp->req_cons++)); 2129 5084 johnlev else 2130 5084 johnlev return (NULL); 2131 5084 johnlev } 2132 5084 johnlev } 2133 5084 johnlev } 2134 5084 johnlev 2135 5084 johnlev int 2136 5084 johnlev xvdi_ring_push_request(xendev_ring_t *ringp) 2137 5084 johnlev { 2138 5084 johnlev RING_IDX old, new, reqevt; 2139 5084 johnlev comif_ring_fe_t *frp; 2140 5084 johnlev 2141 5084 johnlev /* only frontend should be able to push request */ 2142 5084 johnlev ASSERT(ringp->xr_frontend); 2143 5084 johnlev 2144 5084 johnlev /* RING_PUSH_REQUEST_AND_CHECK_NOTIFY() */ 2145 5084 johnlev frp = FRONT_RING(ringp); 2146 5084 johnlev old = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_prod); 2147 5084 johnlev new = frp->req_prod_pvt; 2148 5084 johnlev ddi_put32(ringp->xr_acc_hdl, &frp->sring->req_prod, new); 2149 5084 johnlev membar_enter(); 2150 5084 johnlev reqevt = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_event); 2151 5084 johnlev return ((RING_IDX)(new - reqevt) < (RING_IDX)(new - old)); 2152 5084 johnlev } 2153 5084 johnlev 2154 5084 johnlev /* NOTE: rsp_event will be increased as needed */ 2155 5084 johnlev void * 2156 5084 johnlev xvdi_ring_get_response(xendev_ring_t *ringp) 2157 5084 johnlev { 2158 5084 johnlev comif_ring_fe_t *frp; 2159 5084 johnlev comif_ring_be_t *brp; 2160 5084 johnlev 2161 5084 johnlev if (!ringp->xr_frontend) { 2162 5084 johnlev /* for backend ring */ 2163 5084 johnlev brp = BACK_RING(ringp); 2164 5084 johnlev return (GET_RING_ENTRY_BE(ringp, brp->rsp_prod_pvt++)); 2165 5084 johnlev } else { 2166 5084 johnlev /* for frontend ring */ 2167 5084 johnlev frp = FRONT_RING(ringp); 2168 5084 johnlev /* RING_FINAL_CHECK_FOR_RESPONSES() */ 2169 5084 johnlev if (xvdi_ring_has_unconsumed_responses(ringp)) 2170 5084 johnlev return (GET_RING_ENTRY_FE(ringp, frp->rsp_cons++)); 2171 5084 johnlev else { 2172 5084 johnlev ddi_put32(ringp->xr_acc_hdl, &frp->sring->rsp_event, 2173 5084 johnlev frp->rsp_cons + 1); 2174 5084 johnlev membar_enter(); 2175 5084 johnlev if (xvdi_ring_has_unconsumed_responses(ringp)) 2176 5084 johnlev return (GET_RING_ENTRY_FE(ringp, 2177 5084 johnlev frp->rsp_cons++)); 2178 5084 johnlev else 2179 5084 johnlev return (NULL); 2180 5084 johnlev } 2181 5084 johnlev } 2182 5084 johnlev } 2183 5084 johnlev 2184 5084 johnlev int 2185 5084 johnlev xvdi_ring_push_response(xendev_ring_t *ringp) 2186 5084 johnlev { 2187 5084 johnlev RING_IDX old, new, rspevt; 2188 5084 johnlev comif_ring_be_t *brp; 2189 5084 johnlev 2190 5084 johnlev /* only backend should be able to push response */ 2191 5084 johnlev ASSERT(!ringp->xr_frontend); 2192 5084 johnlev 2193 5084 johnlev /* RING_PUSH_RESPONSE_AND_CHECK_NOTIFY() */ 2194 5084 johnlev brp = BACK_RING(ringp); 2195 5084 johnlev old = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_prod); 2196 5084 johnlev new = brp->rsp_prod_pvt; 2197 5084 johnlev ddi_put32(ringp->xr_acc_hdl, &brp->sring->rsp_prod, new); 2198 5084 johnlev membar_enter(); 2199 5084 johnlev rspevt = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_event); 2200 5084 johnlev return ((RING_IDX)(new - rspevt) < (RING_IDX)(new - old)); 2201 5084 johnlev } 2202 5084 johnlev 2203 5084 johnlev static void 2204 5084 johnlev xvdi_ring_init_sring(xendev_ring_t *ringp) 2205 5084 johnlev { 2206 5084 johnlev ddi_acc_handle_t acchdl; 2207 5084 johnlev comif_sring_t *xsrp; 2208 5084 johnlev int i; 2209 5084 johnlev 2210 5084 johnlev xsrp = (comif_sring_t *)ringp->xr_vaddr; 2211 5084 johnlev acchdl = ringp->xr_acc_hdl; 2212 5084 johnlev 2213 5084 johnlev /* shared ring initialization */ 2214 5084 johnlev ddi_put32(acchdl, &xsrp->req_prod, 0); 2215 5084 johnlev ddi_put32(acchdl, &xsrp->rsp_prod, 0); 2216 5084 johnlev ddi_put32(acchdl, &xsrp->req_event, 1); 2217 5084 johnlev ddi_put32(acchdl, &xsrp->rsp_event, 1); 2218 5084 johnlev for (i = 0; i < sizeof (xsrp->pad); i++) 2219 5084 johnlev ddi_put8(acchdl, xsrp->pad + i, 0); 2220 5084 johnlev } 2221 5084 johnlev 2222 5084 johnlev static void 2223 5084 johnlev xvdi_ring_init_front_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize) 2224 5084 johnlev { 2225 5084 johnlev comif_ring_fe_t *xfrp; 2226 5084 johnlev 2227 5084 johnlev xfrp = &ringp->xr_sring.fr; 2228 5084 johnlev xfrp->req_prod_pvt = 0; 2229 5084 johnlev xfrp->rsp_cons = 0; 2230 5084 johnlev xfrp->nr_ents = nentry; 2231 5084 johnlev xfrp->sring = (comif_sring_t *)ringp->xr_vaddr; 2232 5084 johnlev 2233 5084 johnlev ringp->xr_frontend = 1; 2234 5084 johnlev ringp->xr_entry_size = entrysize; 2235 5084 johnlev } 2236 5084 johnlev 2237 5741 mrj #ifndef XPV_HVM_DRIVER 2238 5084 johnlev static void 2239 5084 johnlev xvdi_ring_init_back_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize) 2240 5084 johnlev { 2241 5084 johnlev comif_ring_be_t *xbrp; 2242 5084 johnlev 2243 5084 johnlev xbrp = &ringp->xr_sring.br; 2244 5084 johnlev xbrp->rsp_prod_pvt = 0; 2245 5084 johnlev xbrp->req_cons = 0; 2246 5084 johnlev xbrp->nr_ents = nentry; 2247 5084 johnlev xbrp->sring = (comif_sring_t *)ringp->xr_vaddr; 2248 5084 johnlev 2249 5084 johnlev ringp->xr_frontend = 0; 2250 5084 johnlev ringp->xr_entry_size = entrysize; 2251 5084 johnlev } 2252 5741 mrj #endif /* XPV_HVM_DRIVER */ 2253 5084 johnlev 2254 5084 johnlev static void 2255 5084 johnlev xendev_offline_device(void *arg) 2256 5084 johnlev { 2257 5084 johnlev dev_info_t *dip = (dev_info_t *)arg; 2258 5084 johnlev char devname[MAXNAMELEN] = {0}; 2259 5084 johnlev 2260 5084 johnlev /* 2261 5084 johnlev * This is currently the only chance to delete a devinfo node, which 2262 5084 johnlev * is _not_ always successful. 2263 5084 johnlev */ 2264 5084 johnlev (void) ddi_deviname(dip, devname); 2265 5084 johnlev (void) devfs_clean(ddi_get_parent(dip), devname + 1, DV_CLEAN_FORCE); 2266 5084 johnlev (void) ndi_devi_offline(dip, NDI_DEVI_REMOVE); 2267 5084 johnlev } 2268 5084 johnlev 2269 5084 johnlev static void 2270 5084 johnlev i_xvdi_oestate_cb(struct xenbus_device *dev, XenbusState oestate) 2271 5084 johnlev { 2272 5084 johnlev dev_info_t *dip = (dev_info_t *)dev->data; 2273 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 2274 7679 Max i_oestate_evt_t *evt = NULL; 2275 7756 Mark boolean_t call_handler; 2276 7679 Max 2277 7679 Max XVDI_DPRINTF(XVDI_DBG_STATE, 2278 7679 Max "i_xvdi_oestate_cb: %s@%s sees oestate change to %d\n", 2279 7679 Max ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip), 2280 7679 Max ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip), 2281 7679 Max oestate); 2282 5084 johnlev 2283 7756 Mark /* only call the handler if our state has changed */ 2284 7756 Mark call_handler = B_FALSE; 2285 7756 Mark mutex_enter(&pdp->xd_ndi_lk); 2286 7756 Mark if (dev->otherend_state != oestate) { 2287 7756 Mark dev->otherend_state = oestate; 2288 7756 Mark call_handler = B_TRUE; 2289 7756 Mark } 2290 7756 Mark mutex_exit(&pdp->xd_ndi_lk); 2291 5084 johnlev 2292 7756 Mark if (call_handler) { 2293 7756 Mark /* 2294 7756 Mark * Try to deliver the oestate change event to the dip 2295 7756 Mark */ 2296 7756 Mark evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP); 2297 7756 Mark evt->dip = dip; 2298 7756 Mark evt->state = oestate; 2299 7756 Mark (void) ddi_taskq_dispatch(pdp->xd_oe_taskq, 2300 7756 Mark i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP); 2301 7756 Mark } 2302 5084 johnlev } 2303 5084 johnlev 2304 5084 johnlev /*ARGSUSED*/ 2305 5084 johnlev static void 2306 5084 johnlev i_xvdi_hpstate_cb(struct xenbus_watch *w, const char **vec, 2307 5084 johnlev unsigned int len) 2308 5084 johnlev { 2309 5084 johnlev dev_info_t *dip = (dev_info_t *)w->dev; 2310 5084 johnlev struct xendev_ppd *pdp = ddi_get_parent_data(dip); 2311 7679 Max 2312 7679 Max #ifdef DEBUG 2313 7679 Max char *hp_status = NULL; 2314 7679 Max unsigned int hpl = 0; 2315 7679 Max 2316 7679 Max (void) xenbus_read(XBT_NULL, pdp->xd_hp_watch.node, "", 2317 7679 Max (void *)&hp_status, &hpl); 2318 7679 Max XVDI_DPRINTF(XVDI_DBG_STATE, 2319 7679 Max "i_xvdi_hpstate_cb: %s@%s sees hpstate change to %s\n", 2320 7679 Max ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip), 2321 7679 Max ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip), 2322 7679 Max hp_status == NULL ? "null" : hp_status); 2323 7679 Max if (hp_status != NULL) 2324 7679 Max kmem_free(hp_status, hpl); 2325 7679 Max #endif /* DEBUG */ 2326 5084 johnlev 2327 5084 johnlev (void) ddi_taskq_dispatch(pdp->xd_hp_taskq, 2328 5084 johnlev i_xvdi_hpstate_handler, (void *)dip, DDI_SLEEP); 2329 5084 johnlev } 2330 5084 johnlev 2331 5084 johnlev static void 2332 5084 johnlev i_xvdi_probe_path_handler(void *arg) 2333 5084 johnlev { 2334 5084 johnlev dev_info_t *parent; 2335 5084 johnlev char *path = arg, *p = NULL; 2336 5084 johnlev int i, vdev, circ; 2337 5084 johnlev i_xd_cfg_t *xdcp; 2338 5084 johnlev boolean_t frontend; 2339 5084 johnlev domid_t dom; 2340 5084 johnlev 2341 5084 johnlev for (i = 0, xdcp = &xdci[0]; i < NXDC; i++, xdcp++) { 2342 5084 johnlev 2343 5084 johnlev if ((xdcp->xs_path_fe != NULL) && 2344 5084 johnlev (strncmp(path, xdcp->xs_path_fe, strlen(xdcp->xs_path_fe)) 2345 5084 johnlev == 0)) { 2346 5084 johnlev 2347 5084 johnlev frontend = B_TRUE; 2348 5084 johnlev p = path + strlen(xdcp->xs_path_fe); 2349 5084 johnlev break; 2350 5084 johnlev } 2351 5084 johnlev 2352 5084 johnlev if ((xdcp->xs_path_be != NULL) && 2353 5084 johnlev (strncmp(path, xdcp->xs_path_be, strlen(xdcp->xs_path_be)) 2354 5084 johnlev == 0)) { 2355 5084 johnlev 2356 5084 johnlev frontend = B_FALSE; 2357 5084 johnlev p = path + strlen(xdcp->xs_path_be); 2358 5084 johnlev break; 2359 5084 johnlev } 2360 5084 johnlev 2361 5084 johnlev } 2362 5084 johnlev 2363 5084 johnlev if (p == NULL) { 2364 5084 johnlev cmn_err(CE_WARN, "i_xvdi_probe_path_handler: " 2365 5084 johnlev "unexpected path prefix in %s", path); 2366 5084 johnlev goto done; 2367 5084 johnlev } 2368 5084 johnlev 2369 5084 johnlev if (frontend) { 2370 5084 johnlev dom = DOMID_SELF; 2371 5084 johnlev if (sscanf(p, "/%d/", &vdev) != 1) { 2372 5084 johnlev XVDI_DPRINTF(XVDI_DBG_PROBE, 2373 5084 johnlev "i_xvdi_probe_path_handler: " 2374 5084 johnlev "cannot parse frontend path %s", 2375 5084 johnlev path); 2376 5084 johnlev goto done; 2377 5084 johnlev } 2378 5084 johnlev } else { 2379 7632 Nick if (sscanf(p, "/%hu/%d/", &dom, &vdev) != 2) { 2380 5084 johnlev XVDI_DPRINTF(XVDI_DBG_PROBE, 2381 5084 johnlev "i_xvdi_probe_path_handler: " 2382 5084 johnlev "cannot parse backend path %s", 2383 5084 johnlev path); 2384 5084 johnlev goto done; 2385 5084 johnlev } 2386 5084 johnlev } 2387 5084 johnlev 2388 6175 johnlev /* 2389 6175 johnlev * This is an oxymoron, so indicates a bogus configuration we 2390 6175 johnlev * must check for. 2391 6175 johnlev */ 2392 6175 johnlev if (vdev == VDEV_NOXS) { 2393 6175 johnlev cmn_err(CE_WARN, "i_xvdi_probe_path_handler: " 2394 6175 johnlev "invalid path %s", path); 2395 6175 johnlev goto done; 2396 6175 johnlev } 2397 6175 johnlev 2398 5084 johnlev parent = xendev_dip; 2399 5084 johnlev ASSERT(parent != NULL); 2400 5084 johnlev 2401 5084 johnlev ndi_devi_enter(parent, &circ); 2402 5084 johnlev 2403 5084 johnlev if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL) { 2404 5084 johnlev XVDI_DPRINTF(XVDI_DBG_PROBE, 2405 5084 johnlev "i_xvdi_probe_path_handler: create for %s", path); 2406 5084 johnlev (void) xvdi_create_dev(parent, xdcp->devclass, dom, vdev); 2407 5084 johnlev } else { 2408 5084 johnlev XVDI_DPRINTF(XVDI_DBG_PROBE, 2409 5084 johnlev "i_xvdi_probe_path_handler: %s already exists", path); 2410 5084 johnlev } 2411 5084 johnlev 2412 5084 johnlev ndi_devi_exit(parent, circ); 2413 5084 johnlev 2414 5084 johnlev done: 2415 5084 johnlev kmem_free(path, strlen(path) + 1); 2416 5084 johnlev } 2417