xref: /titanic_44/usr/src/uts/common/xen/io/xenbus_dev.c (revision 416369f6ab2ab327f0e71cbdb854f9e5bdc6f5ec)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * xenbus_dev.c
29  *
30  * Driver giving user-space access to the kernel's xenbus connection
31  * to xenstore.
32  *
33  * Copyright (c) 2005, Christian Limpach
34  * Copyright (c) 2005, Rusty Russell, IBM Corporation
35  *
36  * This file may be distributed separately from the Linux kernel, or
37  * incorporated into other software packages, subject to the following license:
38  *
39  * Permission is hereby granted, free of charge, to any person obtaining a copy
40  * of this source file (the "Software"), to deal in the Software without
41  * restriction, including without limitation the rights to use, copy, modify,
42  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
43  * and to permit persons to whom the Software is furnished to do so, subject to
44  * the following conditions:
45  *
46  * The above copyright notice and this permission notice shall be included in
47  * all copies or substantial portions of the Software.
48  *
49  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
54  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
55  * IN THE SOFTWARE.
56  */
57 
58 #pragma ident	"%Z%%M%	%I%	%E% SMI"
59 
60 #include <sys/types.h>
61 #include <sys/sysmacros.h>
62 #include <sys/conf.h>
63 #include <sys/stat.h>
64 #include <sys/modctl.h>
65 #include <sys/uio.h>
66 #include <sys/list.h>
67 #include <sys/file.h>
68 #include <sys/errno.h>
69 #include <sys/open.h>
70 #include <sys/cred.h>
71 #include <sys/condvar.h>
72 #include <sys/ddi.h>
73 #include <sys/sunddi.h>
74 #include <sys/hypervisor.h>
75 #include <xen/sys/xenbus_comms.h>
76 #include <xen/sys/xenbus_impl.h>
77 #include <xen/sys/xenbus.h>
78 #include <xen/public/io/xs_wire.h>
79 
80 #ifdef DEBUG
81 #define	XENBUSDRV_DBPRINT(fmt) { if (xenbusdrv_debug) cmn_err fmt; }
82 #else
83 #define	XENBUSDRV_DBPRINT(fmt)
84 #endif /* ifdef DEBUG */
85 
86 /* Some handy macros */
87 #define	XENBUSDRV_MASK_READ_IDX(idx)	((idx) & (PAGESIZE - 1))
88 #define	XENBUSDRV_MINOR2INST(minor)	((int)(minor))
89 #define	XENBUSDRV_NCLONES 		256
90 #define	XENBUSDRV_INST2SOFTS(instance)	\
91 	((xenbus_dev_t *)ddi_get_soft_state(xenbusdrv_statep, (instance)))
92 
93 static int xenbusdrv_debug = 0;
94 static int xenbusdrv_clone_tab[XENBUSDRV_NCLONES];
95 static dev_info_t *xenbusdrv_dip;
96 static kmutex_t xenbusdrv_clone_tab_mutex;
97 
98 struct xenbus_dev_transaction {
99 	list_t list;
100 	xenbus_transaction_t handle;
101 };
102 
103 /* Soft state data structure for xenbus driver */
104 struct xenbus_dev_data {
105 	dev_info_t *dip;
106 
107 	/* In-progress transaction. */
108 	list_t transactions;
109 
110 	/* Partial request. */
111 	unsigned int len;
112 	union {
113 		struct xsd_sockmsg msg;
114 		char buffer[MMU_PAGESIZE];
115 	} u;
116 
117 	/* Response queue. */
118 	char read_buffer[MMU_PAGESIZE];
119 	unsigned int read_cons, read_prod;
120 	kcondvar_t read_cv;
121 	kmutex_t read_mutex;
122 	int xenstore_inst;
123 };
124 typedef struct xenbus_dev_data xenbus_dev_t;
125 static void *xenbusdrv_statep;
126 
127 static int xenbusdrv_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
128 static int xenbusdrv_attach(dev_info_t *, ddi_attach_cmd_t);
129 static int xenbusdrv_detach(dev_info_t *, ddi_detach_cmd_t);
130 static int xenbusdrv_open(dev_t *, int, int, cred_t *);
131 static int xenbusdrv_close(dev_t, int, int, cred_t *);
132 static int xenbusdrv_read(dev_t, struct uio *, cred_t *);
133 static int xenbusdrv_write(dev_t, struct uio *, cred_t *);
134 static int xenbusdrv_devmap(dev_t, devmap_cookie_t, offset_t, size_t, size_t *,
135     uint_t);
136 static int xenbusdrv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
137 static int xenbusdrv_queue_reply(xenbus_dev_t *, const struct xsd_sockmsg *,
138     const char *);
139 
140 /* Solaris driver framework */
141 
142 static 	struct cb_ops xenbusdrv_cb_ops = {
143 	xenbusdrv_open,			/* cb_open */
144 	xenbusdrv_close,		/* cb_close */
145 	nodev,				/* cb_strategy */
146 	nodev,				/* cb_print */
147 	nodev,				/* cb_dump */
148 	xenbusdrv_read,			/* cb_read */
149 	xenbusdrv_write,		/* cb_write */
150 	xenbusdrv_ioctl,		/* cb_ioctl */
151 	xenbusdrv_devmap,		/* cb_devmap */
152 	NULL,				/* cb_mmap */
153 	NULL,				/* cb_segmap */
154 	nochpoll,			/* cb_chpoll */
155 	ddi_prop_op,			/* cb_prop_op */
156 	0,				/* cb_stream */
157 	D_DEVMAP | D_NEW | D_MP,	/* cb_flag */
158 	CB_REV
159 };
160 
161 static struct dev_ops xenbusdrv_dev_ops = {
162 	DEVO_REV,		/* devo_rev */
163 	0,			/* devo_refcnt */
164 	xenbusdrv_info,		/* devo_getinfo */
165 	nulldev,		/* devo_identify */
166 	nulldev,		/* devo_probe */
167 	xenbusdrv_attach,	/* devo_attach */
168 	xenbusdrv_detach,	/* devo_detach */
169 	nodev,			/* devo_reset */
170 	&xenbusdrv_cb_ops,	/* devo_cb_ops */
171 	NULL,			/* devo_bus_ops */
172 	NULL			/* power */
173 };
174 
175 static struct modldrv modldrv = {
176 	&mod_driverops,		/* Type of module.  This one is a driver */
177 	"virtual bus driver v%I%",	/* Name of the module. */
178 	&xenbusdrv_dev_ops	/* driver ops */
179 };
180 
181 static struct modlinkage modlinkage = {
182 	MODREV_1,
183 	&modldrv,
184 	NULL
185 };
186 
187 int
188 _init(void)
189 {
190 	int e;
191 
192 	e = ddi_soft_state_init(&xenbusdrv_statep, sizeof (xenbus_dev_t), 1);
193 	if (e)
194 		return (e);
195 
196 	e = mod_install(&modlinkage);
197 	if (e)
198 		ddi_soft_state_fini(&xenbusdrv_statep);
199 
200 	return (e);
201 }
202 
203 int
204 _fini(void)
205 {
206 	int e;
207 
208 	e = mod_remove(&modlinkage);
209 	if (e)
210 		return (e);
211 
212 	ddi_soft_state_fini(&xenbusdrv_statep);
213 
214 	return (0);
215 }
216 
217 int
218 _info(struct modinfo *modinfop)
219 {
220 	return (mod_info(&modlinkage, modinfop));
221 }
222 
223 /* ARGSUSED */
224 static int
225 xenbusdrv_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
226 {
227 	dev_t	dev = (dev_t)arg;
228 	minor_t	minor = getminor(dev);
229 	int	retval;
230 
231 	switch (cmd) {
232 	case DDI_INFO_DEVT2DEVINFO:
233 		if (minor != 0 || xenbusdrv_dip == NULL) {
234 			*result = (void *)NULL;
235 			retval = DDI_FAILURE;
236 		} else {
237 			*result = (void *)xenbusdrv_dip;
238 			retval = DDI_SUCCESS;
239 		}
240 		break;
241 	case DDI_INFO_DEVT2INSTANCE:
242 		*result = (void *)0;
243 		retval = DDI_SUCCESS;
244 		break;
245 	default:
246 		retval = DDI_FAILURE;
247 	}
248 	return (retval);
249 }
250 
251 static int
252 xenbusdrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
253 {
254 	int	error;
255 	int	unit = ddi_get_instance(dip);
256 
257 
258 	switch (cmd) {
259 	case DDI_ATTACH:
260 		break;
261 	case DDI_RESUME:
262 		return (DDI_SUCCESS);
263 	default:
264 		cmn_err(CE_WARN, "xenbus_attach: unknown cmd 0x%x\n", cmd);
265 		return (DDI_FAILURE);
266 	}
267 
268 	/* DDI_ATTACH */
269 
270 	/*
271 	 * only one instance - but we clone using the open routine
272 	 */
273 	if (ddi_get_instance(dip) > 0)
274 		return (DDI_FAILURE);
275 
276 	mutex_init(&xenbusdrv_clone_tab_mutex, NULL, MUTEX_DRIVER,
277 	    NULL);
278 
279 	error = ddi_create_minor_node(dip, "xenbus", S_IFCHR, unit,
280 	    DDI_PSEUDO, NULL);
281 	if (error != DDI_SUCCESS)
282 		goto fail;
283 
284 	/*
285 	 * save dip for getinfo
286 	 */
287 	xenbusdrv_dip = dip;
288 	ddi_report_dev(dip);
289 
290 	if (DOMAIN_IS_INITDOMAIN(xen_info))
291 		xs_dom0_init();
292 
293 	return (DDI_SUCCESS);
294 
295 fail:
296 	(void) xenbusdrv_detach(dip, DDI_DETACH);
297 	return (error);
298 }
299 
300 static int
301 xenbusdrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
302 {
303 	/*
304 	 * again, only one instance
305 	 */
306 	if (ddi_get_instance(dip) > 0)
307 		return (DDI_FAILURE);
308 
309 	switch (cmd) {
310 	case DDI_DETACH:
311 		ddi_remove_minor_node(dip, NULL);
312 		mutex_destroy(&xenbusdrv_clone_tab_mutex);
313 		xenbusdrv_dip = NULL;
314 		return (DDI_SUCCESS);
315 	case DDI_SUSPEND:
316 		return (DDI_SUCCESS);
317 	default:
318 		cmn_err(CE_WARN, "xenbus_detach: unknown cmd 0x%x\n", cmd);
319 		return (DDI_FAILURE);
320 	}
321 }
322 
323 /* ARGSUSED */
324 static int
325 xenbusdrv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
326 {
327 	xenbus_dev_t *xbs;
328 	minor_t minor = getminor(*devp);
329 
330 	if (otyp == OTYP_BLK)
331 		return (ENXIO);
332 
333 	/*
334 	 * only allow open on minor = 0 - the clone device
335 	 */
336 	if (minor != 0)
337 		return (ENXIO);
338 
339 	/*
340 	 * find a free slot and grab it
341 	 */
342 	mutex_enter(&xenbusdrv_clone_tab_mutex);
343 	for (minor = 1; minor < XENBUSDRV_NCLONES; minor++) {
344 		if (xenbusdrv_clone_tab[minor] == 0) {
345 			xenbusdrv_clone_tab[minor] = 1;
346 			break;
347 		}
348 	}
349 	mutex_exit(&xenbusdrv_clone_tab_mutex);
350 	if (minor == XENBUSDRV_NCLONES)
351 		return (EAGAIN);
352 
353 	/* Allocate softstate structure */
354 	if (ddi_soft_state_zalloc(xenbusdrv_statep,
355 	    XENBUSDRV_MINOR2INST(minor)) != DDI_SUCCESS) {
356 		mutex_enter(&xenbusdrv_clone_tab_mutex);
357 		xenbusdrv_clone_tab[minor] = 0;
358 		mutex_exit(&xenbusdrv_clone_tab_mutex);
359 		return (EAGAIN);
360 	}
361 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor));
362 
363 	/* ... and init it */
364 	xbs->dip = xenbusdrv_dip;
365 	mutex_init(&xbs->read_mutex, NULL, MUTEX_DRIVER, NULL);
366 	cv_init(&xbs->read_cv, NULL, CV_DEFAULT, NULL);
367 	list_create(&xbs->transactions, sizeof (struct xenbus_dev_transaction),
368 	    offsetof(struct xenbus_dev_transaction, list));
369 
370 	/* clone driver */
371 	*devp = makedevice(getmajor(*devp), minor);
372 	XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv open succeeded, minor=%d",
373 	    minor));
374 
375 	return (0);
376 }
377 
378 /* ARGSUSED */
379 static int
380 xenbusdrv_close(dev_t dev, int flag, int otyp, struct cred *credp)
381 {
382 	xenbus_dev_t *xbs;
383 	minor_t minor = getminor(dev);
384 	struct xenbus_dev_transaction *trans;
385 
386 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(minor));
387 	if (xbs == NULL)
388 		return (ENXIO);
389 
390 #ifdef notyet
391 	/*
392 	 * XXPV - would like to be able to notify xenstore down here, but
393 	 * as the daemon is currently written, it doesn't leave the device
394 	 * open after initial setup, so we have no way of knowing if it has
395 	 * gone away.
396 	 */
397 	if (xbs->xenstore_inst)
398 		xs_notify_xenstore_down();
399 #endif
400 	/* free pending transaction */
401 	while (trans = (struct xenbus_dev_transaction *)
402 	    list_head(&xbs->transactions)) {
403 		(void) xenbus_transaction_end(trans->handle, 1);
404 		list_remove(&xbs->transactions, (void *)trans);
405 		kmem_free(trans, sizeof (*trans));
406 	}
407 
408 	mutex_destroy(&xbs->read_mutex);
409 	cv_destroy(&xbs->read_cv);
410 	ddi_soft_state_free(xenbusdrv_statep, XENBUSDRV_MINOR2INST(minor));
411 
412 	/*
413 	 * free clone tab slot
414 	 */
415 	mutex_enter(&xenbusdrv_clone_tab_mutex);
416 	xenbusdrv_clone_tab[minor] = 0;
417 	mutex_exit(&xenbusdrv_clone_tab_mutex);
418 
419 	XENBUSDRV_DBPRINT((CE_NOTE, "Xenbus drv close succeeded, minor=%d",
420 	    minor));
421 
422 	return (0);
423 }
424 
425 /* ARGSUSED */
426 static int
427 xenbusdrv_read(dev_t dev, struct uio *uiop, cred_t *credp)
428 {
429 	xenbus_dev_t *xbs;
430 	size_t len;
431 	int res, ret;
432 	int idx;
433 
434 	XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_read called"));
435 
436 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
437 
438 	mutex_enter(&xbs->read_mutex);
439 
440 	/* check if we have something to read */
441 	while (xbs->read_prod == xbs->read_cons) {
442 		if (cv_wait_sig(&xbs->read_cv, &xbs->read_mutex) == 0) {
443 			mutex_exit(&xbs->read_mutex);
444 			return (EINTR);
445 		}
446 	}
447 
448 	idx = XENBUSDRV_MASK_READ_IDX(xbs->read_cons);
449 	res = uiop->uio_resid;
450 
451 	len = xbs->read_prod - xbs->read_cons;
452 
453 	if (len > (sizeof (xbs->read_buffer) - idx))
454 		len = sizeof (xbs->read_buffer) - idx;
455 	if (len > res)
456 		len = res;
457 
458 	ret = uiomove(xbs->read_buffer + idx, len, UIO_READ, uiop);
459 	xbs->read_cons += res - uiop->uio_resid;
460 	mutex_exit(&xbs->read_mutex);
461 
462 	return (ret);
463 }
464 
465 /*
466  * prepare data for xenbusdrv_read()
467  */
468 static int
469 xenbusdrv_queue_reply(xenbus_dev_t *xbs, const struct xsd_sockmsg *msg,
470     const char *reply)
471 {
472 	int i;
473 	int remaining;
474 
475 	XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply called"));
476 
477 	mutex_enter(&xbs->read_mutex);
478 
479 	remaining = sizeof (xbs->read_buffer) -
480 	    (xbs->read_prod - xbs->read_cons);
481 
482 	if (sizeof (*msg) + msg->len > remaining) {
483 		mutex_exit(&xbs->read_mutex);
484 		return (EOVERFLOW);
485 	}
486 
487 	for (i = 0; i < sizeof (*msg); i++, xbs->read_prod++) {
488 		xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] =
489 		    ((char *)msg)[i];
490 	}
491 
492 	for (i = 0; i < msg->len; i++, xbs->read_prod++) {
493 		xbs->read_buffer[XENBUSDRV_MASK_READ_IDX(xbs->read_prod)] =
494 		    reply[i];
495 	}
496 
497 	cv_broadcast(&xbs->read_cv);
498 
499 	mutex_exit(&xbs->read_mutex);
500 
501 	XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_queue_reply exited"));
502 
503 	return (0);
504 }
505 
506 /* ARGSUSED */
507 static int
508 xenbusdrv_write(dev_t dev, struct uio *uiop, cred_t *credp)
509 {
510 	xenbus_dev_t *xbs;
511 	struct xenbus_dev_transaction *trans;
512 	void *reply;
513 	size_t len;
514 	int rc = 0;
515 
516 	XENBUSDRV_DBPRINT((CE_NOTE, "xenbusdrv_write called"));
517 
518 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
519 	len = uiop->uio_resid;
520 
521 	if ((len + xbs->len) > sizeof (xbs->u.buffer)) {
522 		XENBUSDRV_DBPRINT((CE_WARN, "Request is too big"));
523 		rc = EINVAL;
524 		goto out;
525 	}
526 
527 	if (uiomove(xbs->u.buffer + xbs->len, len, UIO_WRITE, uiop) != 0) {
528 		XENBUSDRV_DBPRINT((CE_WARN, "Uiomove failed"));
529 		rc = EFAULT;
530 		goto out;
531 	}
532 
533 	xbs->len += len;
534 
535 	if (xbs->len < (sizeof (xbs->u.msg)) ||
536 	    xbs->len < (sizeof (xbs->u.msg) + xbs->u.msg.len)) {
537 		XENBUSDRV_DBPRINT((CE_NOTE, "Partial request"));
538 		return (0);
539 	}
540 
541 	switch (xbs->u.msg.type) {
542 	case XS_TRANSACTION_START:
543 	case XS_TRANSACTION_END:
544 	case XS_DIRECTORY:
545 	case XS_READ:
546 	case XS_GET_PERMS:
547 	case XS_RELEASE:
548 	case XS_GET_DOMAIN_PATH:
549 	case XS_WRITE:
550 	case XS_MKDIR:
551 	case XS_RM:
552 	case XS_SET_PERMS:
553 		/* send the request to xenstore and get feedback */
554 		rc = xenbus_dev_request_and_reply(&xbs->u.msg, &reply);
555 		if (rc) {
556 			XENBUSDRV_DBPRINT((CE_WARN,
557 			    "xenbus_dev_request_and_reply failed"));
558 			goto out;
559 		}
560 
561 		/* handle transaction start/end */
562 		if (xbs->u.msg.type == XS_TRANSACTION_START) {
563 			trans = kmem_alloc(sizeof (*trans), KM_SLEEP);
564 			(void) ddi_strtoul((char *)reply, NULL, 0,
565 			    (unsigned long *)&trans->handle);
566 			list_insert_tail(&xbs->transactions, (void *)trans);
567 		} else if (xbs->u.msg.type == XS_TRANSACTION_END) {
568 			/* try to find out the ending transaction */
569 			for (trans = (struct xenbus_dev_transaction *)
570 			    list_head(&xbs->transactions); trans;
571 			    trans = (struct xenbus_dev_transaction *)
572 			    list_next(&xbs->transactions, (void *)trans))
573 				if (trans->handle ==
574 				    (xenbus_transaction_t)
575 				    xbs->u.msg.tx_id)
576 					break;
577 			ASSERT(trans);
578 			/* free it, if we find it */
579 			list_remove(&xbs->transactions, (void *)trans);
580 			kmem_free(trans, sizeof (*trans));
581 		}
582 
583 		/* prepare data for xenbusdrv_read() to get */
584 		rc = xenbusdrv_queue_reply(xbs, &xbs->u.msg, reply);
585 
586 		kmem_free(reply, xbs->u.msg.len + 1);
587 		break;
588 	default:
589 		rc = EINVAL;
590 	}
591 
592 out:
593 	xbs->len = 0;
594 	return (rc);
595 }
596 
597 /*ARGSUSED*/
598 static int
599 xenbusdrv_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
600     size_t *maplen, uint_t model)
601 {
602 	xenbus_dev_t *xbs;
603 	int err;
604 
605 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
606 
607 	if (off != 0 || len != PAGESIZE)
608 		return (-1);
609 
610 	if (!DOMAIN_IS_INITDOMAIN(xen_info))
611 		return (-1);
612 
613 	err = devmap_umem_setup(dhp, xbs->dip, NULL, xb_xenstore_cookie(),
614 	    0, PAGESIZE, PROT_READ | PROT_WRITE | PROT_USER, 0, NULL);
615 
616 	if (err)
617 		return (err);
618 
619 	*maplen = PAGESIZE;
620 
621 	return (0);
622 }
623 
624 /*ARGSUSED*/
625 static int
626 xenbusdrv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
627     int *rvalp)
628 {
629 	xenbus_dev_t *xbs;
630 
631 	xbs = XENBUSDRV_INST2SOFTS(XENBUSDRV_MINOR2INST(getminor(dev)));
632 	switch (cmd) {
633 	case IOCTL_XENBUS_XENSTORE_EVTCHN:
634 		*rvalp = xen_info->store_evtchn;
635 		break;
636 	case IOCTL_XENBUS_NOTIFY_UP:
637 		xs_notify_xenstore_up();
638 		xbs->xenstore_inst = 1;
639 		break;
640 	default:
641 		return (EINVAL);
642 	}
643 
644 	return (0);
645 }
646