xref: /illumos-gate/usr/src/uts/sun4v/io/glvc/glvc.c (revision 968633ad8faee931821fd6b656eb0d96d4b186c0)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <sys/time.h>
28 #include <sys/errno.h>
29 #include <sys/kmem.h>
30 #include <sys/stat.h>
31 #include <sys/cmn_err.h>
32 
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/devops.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/callb.h>
39 #include <sys/disp.h>
40 #include <sys/strlog.h>
41 #include <sys/file.h>
42 
43 #include <sys/uadmin.h>
44 #include <sys/machsystm.h>
45 #include <sys/hypervisor_api.h>
46 #include <sys/hsvc.h>
47 #include <sys/glvc.h>
48 
49 /*
50  * Global Variables - can be patched from Solaris
51  * ==============================================
52  */
53 
54 /* bit defination in virtual device register */
55 #define	GLVC_REG_RECV		0x0001
56 #define	GLVC_REG_RECV_ENA	0x0002
57 #define	GLVC_REG_SEND		0x0004
58 #define	GLVC_REG_SEND_ENA	0x0008
59 #define	GLVC_REG_ERR		0x8000
60 
61 /*
62  * For interrupt mode
63  */
64 #define	GLVC_MODE_NONE		0
65 #define	GLVC_POLLING_MODE	1
66 #define	GLVC_INTR_MODE		2
67 
68 /*
69  * For open
70  */
71 #define	GLVC_NO_OPEN		0
72 #define	GLVC_OPEN		1
73 #define	GLVC_EXCL_OPEN		2
74 
75 /*
76  * For timeout polling, in microsecond.
77  */
78 #define	GLVC_TIMEOUT_POLL	5000000		/* Timeout in intr mode */
79 #define	GLVC_POLLMODE_POLL	500000		/* Interval in polling mode */
80 
81 /*
82  * For debug printing
83  */
84 #define	_PRINTF			printf
85 #define	DPRINTF(args)		if (glvc_debug) _PRINTF args;
86 
87 /*
88  * Driver entry points
89  */
90 static int	glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
91 static int	glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
92 static int	glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
93 static int	glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
94 static int	glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
95     cred_t *cred_p, int *rval_p);
96 static int	glvc_read(dev_t dev, struct uio *uiop, cred_t *credp);
97 static int	glvc_write(dev_t dev, struct uio *uiop, cred_t *credp);
98 
99 static struct cb_ops glvc_cb_ops = {
100 	glvc_open,	/* open */
101 	glvc_close,	/* close */
102 	nodev,		/* strategy() */
103 	nodev,		/* print() */
104 	nodev,		/* dump() */
105 	glvc_read,	/* read() */
106 	glvc_write,	/* write() */
107 	glvc_ioctl,	/* ioctl() */
108 	nodev,		/* devmap() */
109 	nodev,		/* mmap() */
110 	ddi_segmap,	/* segmap() */
111 	nochpoll,	/* poll() */
112 	ddi_prop_op,    /* prop_op() */
113 	NULL,		/* cb_str */
114 	D_NEW | D_MP	/* cb_flag */
115 };
116 
117 
118 static struct dev_ops glvc_ops = {
119 	DEVO_REV,
120 	0,			/* ref count */
121 	ddi_getinfo_1to1,	/* getinfo() */
122 	nulldev,		/* identify() */
123 	nulldev,		/* probe() */
124 	glvc_attach,		/* attach() */
125 	glvc_detach,		/* detach */
126 	nodev,			/* reset */
127 	&glvc_cb_ops,		/* pointer to cb_ops structure */
128 	(struct bus_ops *)NULL,
129 	nulldev,		/* power() */
130 	ddi_quiesce_not_needed,		/* quiesce */
131 };
132 
133 /*
134  * Loadable module support.
135  */
136 extern struct mod_ops mod_driverops;
137 
138 static struct modldrv modldrv = {
139 	&mod_driverops,			/* Type of module. This is a driver */
140 	"Sun4v virtual channel driver",	/* Name of the module */
141 	&glvc_ops			/* pointer to the dev_ops structure */
142 };
143 
144 static struct modlinkage modlinkage = {
145 	MODREV_1,
146 	&modldrv,
147 	NULL
148 };
149 
150 typedef struct glvc_soft_state {
151 	dev_info_t *dip;	/* dev info of myself */
152 	uint64_t s_id;		/* service id for this node */
153 	uint64_t mtu;		/* max transmit unit size */
154 	uint64_t flag;		/* flag register */
155 	kmutex_t open_mutex;	/* protect open_state flag */
156 	uint8_t open_state;	/* no-open, open or open exclusively */
157 	kmutex_t recv_mutex;
158 	kmutex_t send_complete_mutex;
159 	uint8_t send_complete_flag;	/* 1 = send completed */
160 	uint8_t intr_mode;	/* 1 = polling mode, 2 = interrupt mode */
161 	clock_t polling_interval;
162 	ddi_softintr_t poll_mode_softint_id;
163 	kcondvar_t recv_cv;
164 	kcondvar_t send_complete_cv;
165 	kmutex_t statusreg_mutex;	/* Protects status register */
166 	char *mb_recv_buf;
167 	char *mb_send_buf;
168 	uint64_t mb_recv_buf_pa;
169 	uint64_t mb_send_buf_pa;
170 } glvc_soft_state_t;
171 
172 /*
173  * Hypervisor VSC api versioning information for glvc driver.
174  */
175 static uint64_t	glvc_vsc_min_ver; /* Negotiated VSC API minor version */
176 static uint_t glvc_vsc_users = 0; /* VSC API users */
177 static kmutex_t glvc_vsc_users_mutex;	/* Mutex to protect user count */
178 
179 static hsvc_info_t glvc_hsvc = {
180 	HSVC_REV_1, NULL, HSVC_GROUP_VSC, GLVC_VSC_MAJOR_VER,
181 	GLVC_VSC_MINOR_VER, "glvc"
182 };
183 
184 /*
185  * Module Variables
186  * ================
187  */
188 
189 /*
190  * functions local to this driver.
191  */
192 static int	glvc_add_intr_handlers(dev_info_t *dip);
193 static int	glvc_remove_intr_handlers(dev_info_t *dip);
194 static uint_t	glvc_intr(caddr_t arg);
195 static int	glvc_peek(glvc_soft_state_t *softsp,
196     glvc_xport_msg_peek_t *msg_peek);
197 static uint_t	glvc_soft_intr(caddr_t arg);
198 static int	glvc_emap_h2s(uint64_t hv_errcode);
199 static int	glvc_ioctl_opt_op(glvc_soft_state_t *softsp,
200     intptr_t arg, int mode);
201 
202 /*
203  * Driver globals
204  */
205 static void *glvc_ssp; /* pointer to driver soft state */
206 
207 static uint_t glvc_debug = 0;
208 
209 int
210 _init(void)
211 {
212 	int	error = 0;
213 
214 	if ((error = ddi_soft_state_init(&glvc_ssp,
215 	    sizeof (glvc_soft_state_t), 1)) != 0)
216 		return (error);
217 
218 	/*
219 	 * Initialize the mutex for global data structure
220 	 */
221 	mutex_init(&glvc_vsc_users_mutex, NULL, MUTEX_DRIVER, NULL);
222 
223 	error = mod_install(&modlinkage);
224 
225 	return (error);
226 }
227 
228 
229 int
230 _info(struct modinfo *modinfop)
231 {
232 	return (mod_info(&modlinkage, modinfop));
233 }
234 
235 
236 int
237 _fini(void)
238 {
239 	int	error = 0;
240 
241 	error = mod_remove(&modlinkage);
242 	if (error)
243 		return (error);
244 
245 	mutex_destroy(&glvc_vsc_users_mutex);
246 
247 	ddi_soft_state_fini(&glvc_ssp);
248 	return (0);
249 }
250 
251 
252 static int
253 glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
254 {
255 	int			instance;
256 	int			err;
257 	glvc_soft_state_t 	*softsp;
258 
259 	switch (cmd) {
260 	case DDI_ATTACH:
261 		instance = ddi_get_instance(dip);
262 
263 		/*
264 		 * Negotiate the API version for VSC hypervisor services.
265 		 */
266 		mutex_enter(&glvc_vsc_users_mutex);
267 		if (glvc_vsc_users == 0 &&
268 		    (err = hsvc_register(&glvc_hsvc, &glvc_vsc_min_ver))
269 		    != 0) {
270 			cmn_err(CE_WARN, "%s: cannot negotiate hypervisor "
271 			    "services group: 0x%lx major: 0x%lx minor: 0x%lx "
272 			    "errno: %d\n", glvc_hsvc.hsvc_modname,
273 			    glvc_hsvc.hsvc_group, glvc_hsvc.hsvc_major,
274 			    glvc_hsvc.hsvc_minor, err);
275 
276 			mutex_exit(&glvc_vsc_users_mutex);
277 			return (DDI_FAILURE);
278 		} else {
279 			glvc_vsc_users++;
280 			mutex_exit(&glvc_vsc_users_mutex);
281 		}
282 
283 		DPRINTF(("Glvc instance %d negotiated VSC API version, "
284 		    " major 0x%lx minor 0x%lx\n",
285 		    instance, glvc_hsvc.hsvc_major, glvc_vsc_min_ver));
286 
287 		if (ddi_soft_state_zalloc(glvc_ssp, instance)
288 		    != DDI_SUCCESS) {
289 			mutex_enter(&glvc_vsc_users_mutex);
290 			if (--glvc_vsc_users == 0)
291 				(void) hsvc_unregister(&glvc_hsvc);
292 			mutex_exit(&glvc_vsc_users_mutex);
293 			return (DDI_FAILURE);
294 		}
295 
296 		softsp = ddi_get_soft_state(glvc_ssp, instance);
297 
298 		/* Set the dip in the soft state */
299 		softsp->dip = dip;
300 
301 		softsp->open_state = GLVC_NO_OPEN;
302 		softsp->send_complete_flag = 1;
303 
304 		glvc_debug = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
305 		    softsp->dip, DDI_PROP_DONTPASS, "glvc_debug", glvc_debug);
306 
307 		if ((softsp->s_id = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
308 		    softsp->dip, DDI_PROP_DONTPASS, "channel#", -1))
309 		    == -1) {
310 			cmn_err(CE_WARN, "Failed to get channel#");
311 			goto bad;
312 		}
313 
314 		if ((softsp->mtu = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
315 		    softsp->dip, DDI_PROP_DONTPASS, "mtu", -1))
316 		    <= 0) {
317 			cmn_err(CE_WARN, "Failed to get mtu");
318 			goto bad;
319 		}
320 
321 		softsp->mb_recv_buf =
322 		    (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
323 		if (softsp->mb_recv_buf == NULL) {
324 			cmn_err(CE_WARN, "Failed to alloc mem for recv buf");
325 			goto bad;
326 		}
327 		softsp->mb_recv_buf_pa =
328 		    va_to_pa((caddr_t)softsp->mb_recv_buf);
329 
330 		softsp->mb_send_buf =
331 		    (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
332 		if (softsp->mb_send_buf == NULL) {
333 			kmem_free(softsp->mb_recv_buf, softsp->mtu);
334 			cmn_err(CE_WARN, "Failed to alloc mem for send buf");
335 			goto bad;
336 		}
337 		softsp->mb_send_buf_pa =
338 		    va_to_pa((caddr_t)softsp->mb_send_buf);
339 
340 		err = ddi_create_minor_node(dip, "glvc", S_IFCHR,
341 		    instance, DDI_PSEUDO, NULL);
342 		if (err != DDI_SUCCESS) {
343 			kmem_free(softsp->mb_recv_buf, softsp->mtu);
344 			kmem_free(softsp->mb_send_buf, softsp->mtu);
345 			cmn_err(CE_WARN, "Failed to create minor node");
346 			goto bad;
347 		}
348 
349 		mutex_init(&(softsp->open_mutex), NULL, MUTEX_DRIVER, NULL);
350 		mutex_init(&(softsp->recv_mutex), NULL, MUTEX_DRIVER, NULL);
351 		mutex_init(&(softsp->send_complete_mutex), NULL,
352 		    MUTEX_DRIVER, NULL);
353 		mutex_init(&(softsp->statusreg_mutex), NULL,
354 		    MUTEX_DRIVER, NULL);
355 		cv_init(&(softsp->recv_cv), NULL, CV_DRIVER, NULL);
356 		cv_init(&(softsp->send_complete_cv), NULL, CV_DRIVER, NULL);
357 
358 		/*
359 		 * Add the handlers which watch for unsolicited messages
360 		 * and post event to Sysevent Framework.
361 		 */
362 		err = glvc_add_intr_handlers(dip);
363 		if (err != DDI_SUCCESS) {
364 			cmn_err(CE_WARN, "Failed to add intr handler");
365 			kmem_free(softsp->mb_recv_buf, softsp->mtu);
366 			kmem_free(softsp->mb_send_buf, softsp->mtu);
367 			ddi_remove_minor_node(dip, NULL);
368 			goto bad1;
369 		}
370 
371 		/*
372 		 * Trigger soft interrupt to start polling device if
373 		 * we are in the polling mode
374 		 */
375 		if (softsp->intr_mode == GLVC_POLLING_MODE)
376 			ddi_trigger_softintr(softsp->poll_mode_softint_id);
377 
378 		ddi_report_dev(dip);
379 
380 		DPRINTF(("glvc instance %d, s_id %lu,"
381 		    "mtu %lu attached\n", instance, softsp->s_id,
382 		    softsp->mtu));
383 
384 		return (DDI_SUCCESS);
385 	case DDI_RESUME:
386 		return (DDI_SUCCESS);
387 	default:
388 		return (DDI_FAILURE);
389 	}
390 
391 bad1:
392 	cv_destroy(&(softsp->send_complete_cv));
393 	cv_destroy(&(softsp->recv_cv));
394 	mutex_destroy(&(softsp->open_mutex));
395 	mutex_destroy(&(softsp->send_complete_mutex));
396 	mutex_destroy(&(softsp->recv_mutex));
397 	mutex_destroy(&(softsp->statusreg_mutex));
398 
399 bad:
400 	mutex_enter(&glvc_vsc_users_mutex);
401 	if (--glvc_vsc_users == 0)
402 		(void) hsvc_unregister(&glvc_hsvc);
403 	mutex_exit(&glvc_vsc_users_mutex);
404 	cmn_err(CE_WARN, "glvc: attach failed for instance %d\n", instance);
405 	ddi_soft_state_free(glvc_ssp, instance);
406 	return (DDI_FAILURE);
407 }
408 
409 
410 static int
411 glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
412 {
413 	int	instance;
414 	int	err;
415 	glvc_soft_state_t 	*softsp;
416 
417 
418 	switch (cmd) {
419 	case DDI_DETACH:
420 		instance = ddi_get_instance(dip);
421 
422 		softsp = ddi_get_soft_state(glvc_ssp, instance);
423 
424 		cv_destroy(&(softsp->send_complete_cv));
425 		cv_destroy(&(softsp->recv_cv));
426 		mutex_destroy(&(softsp->open_mutex));
427 		mutex_destroy(&(softsp->statusreg_mutex));
428 		mutex_destroy(&(softsp->send_complete_mutex));
429 		mutex_destroy(&(softsp->recv_mutex));
430 
431 		kmem_free(softsp->mb_recv_buf, softsp->mtu);
432 		kmem_free(softsp->mb_send_buf, softsp->mtu);
433 
434 		err = glvc_remove_intr_handlers(dip);
435 
436 		if (err != DDI_SUCCESS) {
437 			cmn_err(CE_WARN, "Failed to remove event handlers");
438 			return (DDI_FAILURE);
439 		}
440 
441 		ddi_remove_minor_node(dip, NULL);
442 
443 		ddi_soft_state_free(glvc_ssp, instance);
444 
445 		mutex_enter(&glvc_vsc_users_mutex);
446 		if (--glvc_vsc_users == 0)
447 			(void) hsvc_unregister(&glvc_hsvc);
448 		mutex_exit(&glvc_vsc_users_mutex);
449 
450 		return (DDI_SUCCESS);
451 	case DDI_SUSPEND:
452 		return (DDI_SUCCESS);
453 	default:
454 		return (DDI_FAILURE);
455 	}
456 }
457 
458 static int
459 glvc_add_intr_handlers(dev_info_t *dip)
460 {
461 	int	instance;
462 	glvc_soft_state_t	*softsp;
463 	int	err = DDI_FAILURE;
464 	uint64_t polling_interval;
465 
466 	instance = ddi_get_instance(dip);
467 	softsp = ddi_get_soft_state(glvc_ssp, instance);
468 
469 	if ((uint64_t)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
470 	    DDI_PROP_DONTPASS, "flags", -1) != -1) {
471 		err = ddi_add_intr(dip, 0, NULL, NULL, glvc_intr,
472 		    (caddr_t)softsp);
473 		if (err != DDI_SUCCESS)
474 			cmn_err(CE_NOTE, "glvc, instance %d"
475 			    " ddi_add_intr() failed, using"
476 			    " polling mode", instance);
477 	}
478 
479 	if (err == DDI_SUCCESS) {
480 		softsp->intr_mode = GLVC_INTR_MODE;
481 		polling_interval = (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
482 		    softsp->dip, DDI_PROP_DONTPASS, "intrmode_poll",
483 		    GLVC_TIMEOUT_POLL);
484 		DPRINTF(("glvc instance %d polling_interval = %lu\n",
485 		    instance, polling_interval));
486 		softsp->polling_interval = drv_usectohz(polling_interval);
487 	} else {
488 		DPRINTF(("glvc, instance %d  intr support not found, "
489 		    "err = %d , use polling mode", instance, err));
490 		softsp->intr_mode = GLVC_POLLING_MODE;
491 		polling_interval =
492 		    (uint64_t)ddi_getprop(DDI_DEV_T_ANY,
493 		    softsp->dip, DDI_PROP_DONTPASS, "pollmode_poll",
494 		    GLVC_POLLMODE_POLL);
495 		DPRINTF(("glvc instance %d polling_interval = %lu\n",
496 		    instance, polling_interval));
497 		softsp->polling_interval =
498 		    drv_usectohz(polling_interval);
499 	}
500 
501 	/* Now enable interrupt bits in the status register */
502 	if (softsp->intr_mode == GLVC_INTR_MODE) {
503 		err = hv_service_setstatus(softsp->s_id,
504 		    GLVC_REG_RECV_ENA|GLVC_REG_SEND_ENA);
505 		if (err != H_EOK) {
506 			cmn_err(CE_NOTE, "glvc instance %d"
507 			    " cannot enable receive interrupt\n",
508 			    instance);
509 			return (DDI_FAILURE);
510 		}
511 	}
512 
513 
514 	err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
515 	    &softsp->poll_mode_softint_id, NULL, NULL,
516 	    glvc_soft_intr, (caddr_t)softsp);
517 
518 	return (err);
519 }
520 
521 static int
522 glvc_remove_intr_handlers(dev_info_t *dip)
523 {
524 	int	instance;
525 	glvc_soft_state_t	*softsp;
526 
527 	instance = ddi_get_instance(dip);
528 	softsp = ddi_get_soft_state(glvc_ssp, instance);
529 
530 	if (softsp->intr_mode ==  GLVC_INTR_MODE)
531 		ddi_remove_intr(dip, 0, NULL);
532 
533 	ddi_remove_softintr(softsp->poll_mode_softint_id);
534 
535 	softsp->intr_mode = GLVC_MODE_NONE;
536 	softsp->polling_interval = 0;
537 
538 	return (DDI_SUCCESS);
539 }
540 
541 static uint_t
542 glvc_soft_intr(caddr_t arg)
543 {
544 	/*
545 	 * Call the interrupt handle routine to check the register
546 	 * status.
547 	 */
548 	(uint_t)glvc_intr(arg);
549 
550 	return (DDI_INTR_CLAIMED);
551 }
552 
553 /*ARGSUSED*/
554 static int
555 glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
556 {
557 	int error = 0;
558 	int instance;
559 	glvc_soft_state_t *softsp;
560 
561 	instance = getminor(*dev_p);
562 
563 	softsp = ddi_get_soft_state(glvc_ssp, instance);
564 
565 	mutex_enter(&softsp->open_mutex);
566 
567 	switch (softsp->open_state) {
568 	case GLVC_NO_OPEN:
569 		if (flag & FEXCL)
570 			softsp->open_state = GLVC_EXCL_OPEN;
571 		else
572 			softsp->open_state = GLVC_OPEN;
573 		break;
574 
575 	case GLVC_OPEN:
576 		if (flag & FEXCL)
577 			error = EBUSY;
578 		break;
579 
580 	case GLVC_EXCL_OPEN:
581 		error = EBUSY;
582 		break;
583 
584 	default:
585 		/* Should not happen */
586 		cmn_err(CE_WARN, "glvc_open: bad open state %d.",
587 		    softsp->open_state);
588 		error = ENXIO;
589 		break;
590 	}
591 
592 	mutex_exit(&softsp->open_mutex);
593 
594 	return (error);
595 }
596 
597 /*ARGSUSED*/
598 static int
599 glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
600 {
601 	glvc_soft_state_t *softsp;
602 	int instance;
603 	int error = 0;
604 
605 	instance = getminor(dev);
606 
607 	softsp = ddi_get_soft_state(glvc_ssp, instance);
608 
609 	mutex_enter(&softsp->open_mutex);
610 	if (softsp->open_state == GLVC_NO_OPEN) {
611 		cmn_err(CE_WARN,
612 		    "glvc_close: device already closed");
613 		error = ENXIO;
614 	} else {
615 		softsp->open_state = GLVC_NO_OPEN;
616 	}
617 	mutex_exit(&softsp->open_mutex);
618 
619 	return (error);
620 }
621 
622 /*ARGSUSED*/
623 static int
624 glvc_read(dev_t dev, struct uio *uiop, cred_t *credp)
625 {
626 	glvc_soft_state_t *softsp;
627 	int instance;
628 	int rv, error = DDI_SUCCESS;
629 	uint64_t hverr, recv_count = 0;
630 	uint64_t status_reg;
631 	clock_t	tick;
632 
633 	instance = getminor(dev);
634 
635 	softsp = ddi_get_soft_state(glvc_ssp, instance);
636 
637 	mutex_enter(&softsp->recv_mutex);
638 
639 	hverr = hv_service_getstatus(softsp->s_id, &status_reg);
640 	DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx",
641 	    hverr, status_reg));
642 
643 
644 	/*
645 	 * If no data available, we wait till we get some.
646 	 * Notice we still holding the recv_mutex lock at this
647 	 * point.
648 	 */
649 	while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) !=
650 	    GLVC_REG_RECV) {
651 		tick = ddi_get_lbolt() + softsp->polling_interval;
652 		rv =  cv_timedwait_sig(&softsp->recv_cv,
653 		    &softsp->recv_mutex, tick);
654 		if (rv == 0) {
655 			/*
656 			 * We got interrupted.
657 			 */
658 			mutex_exit(&softsp->recv_mutex);
659 			return (EINTR);
660 		}
661 		if (rv == -1) {
662 			/*
663 			 * Timeout wait, trigger a soft intr in case
664 			 * we miss an interrupt or in polling mode.
665 			 */
666 			ddi_trigger_softintr(softsp->poll_mode_softint_id);
667 		}
668 		hverr = hv_service_getstatus(softsp->s_id, &status_reg);
669 		DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx",
670 		    hverr, status_reg));
671 	}
672 
673 	/* Read data into kernel buffer */
674 	hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa,
675 	    softsp->mtu, &recv_count);
676 
677 	DPRINTF(("Instance %d glvc_read returns error = %ld, recv_count = %lu",
678 	    instance, hverr, recv_count));
679 
680 	if (hverr == H_EOK) {
681 		if (uiop->uio_resid < recv_count) {
682 			DPRINTF(("Instance %d, glvc_read user buffer "
683 			    "size(%lu) smaller than number of bytes "
684 			    "received(%lu).", instance, uiop->uio_resid,
685 			    recv_count));
686 			mutex_exit(&softsp->recv_mutex);
687 			return (EINVAL);
688 		}
689 		/* move data from kernel to user space */
690 		error = uiomove(softsp->mb_recv_buf, recv_count,
691 		    UIO_READ, uiop);
692 	} else {
693 		error = glvc_emap_h2s(hverr);
694 	}
695 
696 	/* Clear the RECV data interrupt bit on device register */
697 	if (hv_service_clrstatus(softsp->s_id, GLVC_REG_RECV) != H_EOK) {
698 		cmn_err(CE_WARN, "glvc_read clear status reg failed");
699 	}
700 
701 	/* Set RECV interrupt enable bit so we can receive interrupt */
702 	if (softsp->intr_mode == GLVC_INTR_MODE)
703 		if (hv_service_setstatus(softsp->s_id, GLVC_REG_RECV_ENA)
704 		    != H_EOK) {
705 			cmn_err(CE_WARN, "glvc_read set status reg failed");
706 		}
707 
708 	mutex_exit(&softsp->recv_mutex);
709 
710 	return (error);
711 }
712 
713 /*ARGSUSED*/
714 static int
715 glvc_write(dev_t dev, struct uio *uiop, cred_t *credp)
716 {
717 	glvc_soft_state_t *softsp;
718 	int instance;
719 	int rv, error = DDI_SUCCESS;
720 	uint64_t hverr, send_count = 0;
721 	clock_t tick;
722 
723 	instance = getminor(dev);
724 
725 	softsp = ddi_get_soft_state(glvc_ssp, instance);
726 
727 	if (uiop->uio_resid > softsp->mtu)
728 		return (EINVAL);
729 
730 	send_count = uiop->uio_resid;
731 	DPRINTF(("instance %d glvc_write: request to send %lu bytes",
732 	    instance, send_count));
733 
734 	mutex_enter(&softsp->send_complete_mutex);
735 	while (softsp->send_complete_flag == 0) {
736 		tick = ddi_get_lbolt() + softsp->polling_interval;
737 		rv = cv_timedwait_sig(&softsp->send_complete_cv,
738 		    &softsp->send_complete_mutex, tick);
739 		if (rv == 0) {
740 			/*
741 			 * We got interrupted.
742 			 */
743 			mutex_exit(&softsp->send_complete_mutex);
744 			return (EINTR);
745 		}
746 		if (rv == -1) {
747 			/*
748 			 * Timeout wait, trigger a soft intr in case
749 			 * we miss an interrupt or in polling mode.
750 			 */
751 			ddi_trigger_softintr(softsp->poll_mode_softint_id);
752 		}
753 	}
754 
755 	/* move data from to user to kernel space */
756 	error = uiomove(softsp->mb_send_buf, send_count,
757 	    UIO_WRITE, uiop);
758 
759 	if (error == 0) {
760 		hverr = hv_service_send(softsp->s_id,
761 		    softsp->mb_send_buf_pa, send_count, &send_count);
762 		error = glvc_emap_h2s(hverr);
763 	}
764 
765 	DPRINTF(("instance %d glvc_write write check error = %d,"
766 	    " send_count = %lu", instance, error, send_count));
767 
768 	softsp->send_complete_flag = 0;
769 
770 	mutex_exit(&softsp->send_complete_mutex);
771 
772 	return (error);
773 }
774 
775 /*
776  * Interrupt handler
777  */
778 static uint_t
779 glvc_intr(caddr_t arg)
780 {
781 	glvc_soft_state_t *softsp = (glvc_soft_state_t *)arg;
782 	uint64_t status_reg;
783 	int error = DDI_INTR_UNCLAIMED;
784 	uint64_t hverr = H_EOK;
785 	uint64_t clr_bits = 0;
786 
787 	mutex_enter(&softsp->recv_mutex);
788 	mutex_enter(&softsp->send_complete_mutex);
789 	hverr = hv_service_getstatus(softsp->s_id, &status_reg);
790 	DPRINTF(("glvc_intr: err = %ld, getstatus = 0x%lx",
791 	    hverr, status_reg));
792 
793 	/*
794 	 * Clear SEND_COMPLETE bit and disable RECV interrupt
795 	 */
796 	if (status_reg & GLVC_REG_SEND)
797 		clr_bits |= GLVC_REG_SEND;
798 	if ((softsp->intr_mode == GLVC_INTR_MODE) &&
799 	    (status_reg & GLVC_REG_RECV))
800 		clr_bits |= GLVC_REG_RECV_ENA;
801 
802 	if ((hverr = hv_service_clrstatus(softsp->s_id, clr_bits))
803 	    != H_EOK) {
804 		cmn_err(CE_WARN, "glvc_intr clear status reg failed"
805 		    "error = %ld", hverr);
806 		mutex_exit(&softsp->send_complete_mutex);
807 		mutex_exit(&softsp->recv_mutex);
808 		return (DDI_INTR_UNCLAIMED);
809 	}
810 
811 	if (status_reg & GLVC_REG_RECV) {
812 		cv_broadcast(&softsp->recv_cv);
813 		error = DDI_INTR_CLAIMED;
814 	}
815 
816 	if (status_reg & GLVC_REG_SEND) {
817 		softsp->send_complete_flag = 1;
818 		cv_broadcast(&softsp->send_complete_cv);
819 		error = DDI_INTR_CLAIMED;
820 	}
821 
822 	mutex_exit(&softsp->send_complete_mutex);
823 	mutex_exit(&softsp->recv_mutex);
824 
825 	return (error);
826 }
827 
828 /*
829  * Peek to see if there is data received. If no data available,
830  * we sleep wait. If there is data, read from hypervisor and copy
831  * to ioctl buffer. We don't clear the receive data interrupt bit.
832  */
833 static int
834 glvc_peek(glvc_soft_state_t *softsp, glvc_xport_msg_peek_t *msg_peek)
835 {
836 	int rv, error = 0;
837 	uint64_t hverr = H_EOK;
838 	uint64_t recv_count = 0;
839 	uint64_t status_reg;
840 	clock_t tick;
841 
842 	mutex_enter(&softsp->recv_mutex);
843 
844 	hverr = hv_service_getstatus(softsp->s_id, &status_reg);
845 	DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx",
846 	    hverr, status_reg));
847 
848 	/*
849 	 * If no data available, we wait till we get some.
850 	 * Notice we still holding the recv_mutex lock at
851 	 * this point.
852 	 */
853 	while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) !=
854 	    GLVC_REG_RECV) {
855 		tick = ddi_get_lbolt() + softsp->polling_interval;
856 		rv = cv_timedwait_sig(&softsp->recv_cv,
857 		    &softsp->recv_mutex, tick);
858 		if (rv == 0) {
859 			/*
860 			 * We got interrupted.
861 			 */
862 			mutex_exit(&softsp->recv_mutex);
863 			return (EINTR);
864 		}
865 		if (rv == -1) {
866 			/*
867 			 * Timeout wait, trigger a soft intr in case
868 			 * we miss an interrupt or in polling mode.
869 			 */
870 			ddi_trigger_softintr(softsp->poll_mode_softint_id);
871 		}
872 		hverr = hv_service_getstatus(softsp->s_id, &status_reg);
873 		DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx",
874 		    hverr, status_reg));
875 	}
876 
877 	/* Read data into kernel buffer */
878 	hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa,
879 	    softsp->mtu, &recv_count);
880 	DPRINTF(("glvc_peek recv data, error = %ld, recv_count = %lu",
881 	    hverr, recv_count));
882 
883 	if (hverr == H_EOK && recv_count > 0) {
884 		(void *) memcpy(msg_peek->buf,
885 		    softsp->mb_recv_buf, recv_count);
886 		msg_peek->buflen = recv_count;
887 	} else {
888 		error = glvc_emap_h2s(hverr);
889 	}
890 
891 	mutex_exit(&softsp->recv_mutex);
892 
893 	return (error);
894 }
895 
896 static int
897 glvc_ioctl_opt_op(glvc_soft_state_t *softsp, intptr_t arg, int mode)
898 {
899 	glvc_xport_opt_op_t glvc_xport_cmd;
900 	uint64_t status_reg;
901 	int retval = 0;
902 	uint64_t hverr;
903 
904 	if (ddi_copyin((caddr_t)arg, (caddr_t)&glvc_xport_cmd,
905 	    sizeof (glvc_xport_opt_op_t), mode) != 0) {
906 		return (EFAULT);
907 	}
908 
909 	switch (glvc_xport_cmd.opt_sel) {
910 	case GLVC_XPORT_OPT_MTU_SZ:
911 		if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) {
912 			glvc_xport_cmd.opt_val = softsp->mtu;
913 			retval = ddi_copyout((caddr_t)&glvc_xport_cmd,
914 			    (caddr_t)arg, sizeof (glvc_xport_opt_op_t),
915 			    mode);
916 		} else
917 			retval = ENOTSUP;
918 
919 		break;
920 
921 	case GLVC_XPORT_OPT_REG_STATUS:
922 		if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) {
923 			mutex_enter(&softsp->statusreg_mutex);
924 			hverr = hv_service_getstatus(softsp->s_id, &status_reg);
925 			mutex_exit(&softsp->statusreg_mutex);
926 			if (hverr == H_EOK) {
927 				glvc_xport_cmd.opt_val = (uint32_t)status_reg;
928 				retval = ddi_copyout((caddr_t)&glvc_xport_cmd,
929 				    (caddr_t)arg, sizeof (glvc_xport_opt_op_t),
930 				    mode);
931 			} else {
932 				retval = EIO;
933 			}
934 		} else {
935 			retval = ENOTSUP;
936 		}
937 
938 		break;
939 
940 	default:
941 		retval = ENOTSUP;
942 		break;
943 	}
944 
945 	return (retval);
946 }
947 
948 
949 /*ARGSUSED*/
950 static int
951 glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
952     int *rval_p)
953 {
954 	glvc_soft_state_t *softsp;
955 	int instance = getminor(dev);
956 	glvc_xport_msg_peek_t glvc_peek_msg, msg_peek_cmd;
957 	glvc_xport_msg_peek32_t msg_peek_cmd32;
958 
959 	int retval = 0;
960 
961 	softsp = ddi_get_soft_state(glvc_ssp, instance);
962 
963 	switch (cmd) {
964 	case GLVC_XPORT_IOCTL_OPT_OP:
965 		retval = glvc_ioctl_opt_op(softsp, arg, mode);
966 		break;
967 
968 	case GLVC_XPORT_IOCTL_DATA_PEEK:
969 		glvc_peek_msg.buf =
970 		    (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP);
971 		if (glvc_peek_msg.buf == NULL)
972 			return (EBUSY);
973 		retval = glvc_peek(softsp, &glvc_peek_msg);
974 		if (retval == 0) {
975 			switch (ddi_model_convert_from(mode)) {
976 			case DDI_MODEL_ILP32:
977 				if (ddi_copyin((caddr_t)arg,
978 				    (caddr_t)&msg_peek_cmd32,
979 				    sizeof (glvc_xport_msg_peek32_t),
980 				    mode) == -1) {
981 					retval = EFAULT;
982 					break;
983 				}
984 
985 				if (msg_peek_cmd32.buflen32 == 0) {
986 					retval = EINVAL;
987 					break;
988 				}
989 
990 				if (msg_peek_cmd32.buflen32 >
991 				    glvc_peek_msg.buflen)
992 					msg_peek_cmd32.buflen32 =
993 					    glvc_peek_msg.buflen;
994 
995 				if (ddi_copyout((caddr_t)glvc_peek_msg.buf,
996 				    (caddr_t)(uintptr_t)msg_peek_cmd32.buf32,
997 				    msg_peek_cmd32.buflen32, mode) == -1) {
998 					retval = EFAULT;
999 					break;
1000 				}
1001 
1002 				if (ddi_copyout((caddr_t)&msg_peek_cmd32,
1003 				    (caddr_t)arg,
1004 				    sizeof (glvc_xport_msg_peek32_t), mode)
1005 				    == -1)
1006 					retval = EFAULT;
1007 				break;
1008 
1009 			case DDI_MODEL_NONE:
1010 				if (ddi_copyin((caddr_t)arg,
1011 				    (caddr_t)&msg_peek_cmd,
1012 				    sizeof (glvc_xport_msg_peek_t), mode) == -1)
1013 					retval = EFAULT;
1014 
1015 				if (msg_peek_cmd.buflen == 0) {
1016 					retval = EINVAL;
1017 					break;
1018 				}
1019 
1020 				if (msg_peek_cmd.buflen > glvc_peek_msg.buflen)
1021 					msg_peek_cmd.buflen =
1022 					    glvc_peek_msg.buflen;
1023 
1024 				if (ddi_copyout((caddr_t)glvc_peek_msg.buf,
1025 				    (caddr_t)msg_peek_cmd.buf,
1026 				    msg_peek_cmd.buflen, mode) == -1) {
1027 					retval = EFAULT;
1028 					break;
1029 				}
1030 
1031 				if (ddi_copyout((caddr_t)&msg_peek_cmd,
1032 				    (caddr_t)arg,
1033 				    sizeof (glvc_xport_msg_peek_t), mode) == -1)
1034 					retval = EFAULT;
1035 				break;
1036 
1037 			default:
1038 				retval = EFAULT;
1039 				break;
1040 			}
1041 		}
1042 		kmem_free(glvc_peek_msg.buf, softsp->mtu);
1043 		break;
1044 
1045 	default:
1046 		retval = ENOTSUP;
1047 		break;
1048 	}
1049 	return (retval);
1050 }
1051 
1052 /*
1053  * Map hypervisor error code to solaris. Only
1054  * H_EOK, H_EINVA, H_EWOULDBLOCK and H_EIO are meaningful
1055  * to this device. All other error codes are mapped to EIO.
1056  */
1057 static int
1058 glvc_emap_h2s(uint64_t hv_errcode)
1059 {
1060 	int s_errcode;
1061 
1062 	switch (hv_errcode) {
1063 	case H_EOK:
1064 		s_errcode = 0;
1065 		break;
1066 
1067 	case H_EINVAL:
1068 		s_errcode = EINVAL;
1069 		break;
1070 
1071 	case H_EWOULDBLOCK:
1072 		s_errcode = EWOULDBLOCK;
1073 		break;
1074 
1075 	case H_EIO:
1076 		s_errcode = EIO;
1077 		break;
1078 
1079 	default:
1080 		/* should not happen */
1081 		DPRINTF(("Unexpected device error code %ld received, "
1082 		    "mapped to EIO", hv_errcode));
1083 		s_errcode = EIO;
1084 		break;
1085 	}
1086 
1087 	return (s_errcode);
1088 }
1089