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