Home | History | Annotate | Download | only in io
      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 /*
     29  * sun4v console driver
     30  */
     31 
     32 #include <sys/errno.h>
     33 #include <sys/stat.h>
     34 #include <sys/kmem.h>
     35 #include <sys/conf.h>
     36 #include <sys/termios.h>
     37 #include <sys/modctl.h>
     38 #include <sys/kbio.h>
     39 #include <sys/stropts.h>
     40 #include <sys/stream.h>
     41 #include <sys/strsun.h>
     42 #include <sys/sysmacros.h>
     43 #include <sys/promif.h>
     44 #include <sys/ddi.h>
     45 #include <sys/sunddi.h>
     46 #include <sys/cyclic.h>
     47 #include <sys/intr.h>
     48 #include <sys/spl.h>
     49 #include <sys/qcn.h>
     50 #include <sys/hypervisor_api.h>
     51 #include <sys/hsvc.h>
     52 #include <sys/machsystm.h>
     53 #include <sys/consdev.h>
     54 
     55 /* dev_ops and cb_ops for device driver */
     56 static int qcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
     57 static int qcn_attach(dev_info_t *, ddi_attach_cmd_t);
     58 static int qcn_detach(dev_info_t *, ddi_detach_cmd_t);
     59 static int qcn_open(queue_t *, dev_t *, int, int, cred_t *);
     60 static int qcn_close(queue_t *, int, cred_t *);
     61 static int qcn_wput(queue_t *, mblk_t *);
     62 static int qcn_wsrv(queue_t *);
     63 static int qcn_rsrv(queue_t *);
     64 
     65 /* other internal qcn routines */
     66 static void qcn_ioctl(queue_t *, mblk_t *);
     67 static void qcn_reioctl(void *);
     68 static void qcn_ack(mblk_t *, mblk_t *, uint_t);
     69 static void qcn_start(void);
     70 static int qcn_transmit_write(queue_t *, mblk_t *);
     71 static int qcn_transmit_putchr(queue_t *, mblk_t *);
     72 static void qcn_receive_read(void);
     73 static void qcn_receive_getchr(void);
     74 static void qcn_flush(void);
     75 static uint_t qcn_hi_intr(caddr_t arg);
     76 static uint_t qcn_soft_intr(caddr_t arg1, caddr_t arg2);
     77 
     78 /* functions required for polled io */
     79 static boolean_t qcn_polledio_ischar(cons_polledio_arg_t arg);
     80 static int qcn_polledio_getchar(cons_polledio_arg_t arg);
     81 static void qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c);
     82 static void qcn_polledio_enter(cons_polledio_arg_t arg);
     83 static void qcn_polledio_exit(cons_polledio_arg_t arg);
     84 
     85 
     86 static boolean_t abort_charseq_recognize(uchar_t);
     87 
     88 static qcn_t *qcn_state;
     89 static uchar_t qcn_stopped = B_FALSE;
     90 static int qcn_timeout_period = 20;	/* time out in seconds */
     91 size_t qcn_input_dropped;	/* dropped input character counter */
     92 
     93 #ifdef QCN_POLLING
     94 static void qcn_poll_handler(void *unused);
     95 static cyc_time_t qcn_poll_time;
     96 static cyc_handler_t qcn_poll_cychandler = {
     97 	qcn_poll_handler,
     98 	NULL,
     99 	CY_LOW_LEVEL		/* XXX need softint to make this high */
    100 };
    101 static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE;
    102 static uint64_t	qcn_poll_interval = 5;  /* milli sec */
    103 static uint64_t sb_interval = 0;
    104 uint_t qcn_force_polling = 0;
    105 #endif
    106 
    107 #define	QCN_MI_IDNUM		0xABCE
    108 #define	QCN_MI_HIWAT		8192
    109 #define	QCN_MI_LOWAT		128
    110 
    111 /* streams structures */
    112 static struct module_info minfo = {
    113 	QCN_MI_IDNUM,	/* mi_idnum		*/
    114 	"qcn",		/* mi_idname		*/
    115 	0,		/* mi_minpsz		*/
    116 	INFPSZ,		/* mi_maxpsz		*/
    117 	QCN_MI_HIWAT,	/* mi_hiwat		*/
    118 	QCN_MI_LOWAT	/* mi_lowat		*/
    119 };
    120 
    121 static struct qinit rinit = {
    122 	putq,		/* qi_putp		*/
    123 	qcn_rsrv,	/* qi_srvp		*/
    124 	qcn_open,	/* qi_qopen		*/
    125 	qcn_close,	/* qi_qclose		*/
    126 	NULL,		/* qi_qadmin		*/
    127 	&minfo,		/* qi_minfo		*/
    128 	NULL		/* qi_mstat		*/
    129 };
    130 
    131 static struct qinit winit = {
    132 	qcn_wput,	/* qi_putp		*/
    133 	qcn_wsrv,	/* qi_srvp		*/
    134 	qcn_open,	/* qi_qopen		*/
    135 	qcn_close,	/* qi_qclose		*/
    136 	NULL,		/* qi_qadmin		*/
    137 	&minfo,		/* qi_minfo		*/
    138 	NULL		/* qi_mstat		*/
    139 };
    140 
    141 static struct streamtab qcnstrinfo = {
    142 	&rinit,
    143 	&winit,
    144 	NULL,
    145 	NULL
    146 };
    147 
    148 /* standard device driver structures */
    149 static struct cb_ops qcn_cb_ops = {
    150 	nulldev,		/* open()		*/
    151 	nulldev,		/* close()		*/
    152 	nodev,			/* strategy()		*/
    153 	nodev,			/* print()		*/
    154 	nodev,			/* dump()		*/
    155 	nodev,			/* read()		*/
    156 	nodev,			/* write()		*/
    157 	nodev,			/* ioctl()		*/
    158 	nodev,			/* devmap()		*/
    159 	nodev,			/* mmap()		*/
    160 	nodev,			/* segmap()		*/
    161 	nochpoll,		/* poll()		*/
    162 	ddi_prop_op,		/* prop_op()		*/
    163 	&qcnstrinfo,		/* cb_str		*/
    164 	D_NEW | D_MP		/* cb_flag		*/
    165 };
    166 
    167 static struct dev_ops qcn_ops = {
    168 	DEVO_REV,
    169 	0,			/* refcnt		*/
    170 	qcn_getinfo,		/* getinfo()		*/
    171 	nulldev,		/* identify()		*/
    172 	nulldev,		/* probe()		*/
    173 	qcn_attach,		/* attach()		*/
    174 	qcn_detach,		/* detach()		*/
    175 	nodev,			/* reset()		*/
    176 	&qcn_cb_ops,		/* cb_ops		*/
    177 	(struct bus_ops *)NULL,	/* bus_ops		*/
    178 	NULL,			/* power()		*/
    179 	ddi_quiesce_not_needed,		/* quiesce()		*/
    180 };
    181 
    182 static struct modldrv modldrv = {
    183 	&mod_driverops,
    184 	"sun4v console driver",
    185 	&qcn_ops
    186 };
    187 
    188 static struct modlinkage modlinkage = {
    189 	MODREV_1,
    190 	(void*)&modldrv,
    191 	NULL
    192 };
    193 
    194 /* driver configuration routines */
    195 int
    196 _init(void)
    197 {
    198 	int error;
    199 	uint64_t	major, minor;
    200 
    201 	qcn_state = kmem_zalloc(sizeof (qcn_t), KM_SLEEP);
    202 	qcn_state->qcn_ring = contig_mem_alloc(RINGSIZE);
    203 	if (qcn_state->qcn_ring == NULL)
    204 		cmn_err(CE_PANIC, "console ring allocation failed");
    205 
    206 	error = mod_install(&modlinkage);
    207 	if (error != 0) {
    208 		contig_mem_free(qcn_state->qcn_ring, RINGSIZE);
    209 		kmem_free(qcn_state, sizeof (qcn_t));
    210 		return (error);
    211 	}
    212 	/*
    213 	 * check minor number to see if CONS_WRITE is supported
    214 	 * if so, set up real address of the buffers for hv calls.
    215 	 */
    216 
    217 	if (((hsvc_version(HSVC_GROUP_CORE, &major, &minor) == 0) &&
    218 	    (major == QCN_API_MAJOR) && (minor >= QCN_API_MINOR))) {
    219 		qcn_state->cons_write_buffer =
    220 		    contig_mem_alloc(CONS_WR_BUF_SIZE);
    221 		if (qcn_state->cons_write_buffer != NULL) {
    222 			qcn_state->cons_write_buf_ra =
    223 			    va_to_pa(qcn_state->cons_write_buffer);
    224 			qcn_state->cons_transmit = qcn_transmit_write;
    225 			qcn_state->cons_receive = qcn_receive_read;
    226 			qcn_state->cons_read_buf_ra =
    227 			    va_to_pa((char *)RING_ADDR(qcn_state));
    228 		}
    229 	}
    230 	if (qcn_state->cons_transmit == NULL) {
    231 		qcn_state->cons_transmit = qcn_transmit_putchr;
    232 		qcn_state->cons_receive = qcn_receive_getchr;
    233 	}
    234 	return (0);
    235 }
    236 
    237 int
    238 _fini(void)
    239 {
    240 	/* can't remove console driver */
    241 	return (EBUSY);
    242 }
    243 
    244 int
    245 _info(struct modinfo *modinfop)
    246 {
    247 	return (mod_info(&modlinkage, modinfop));
    248 }
    249 
    250 static int
    251 qcn_add_intrs(void)
    252 {
    253 	dev_info_t	*devinfo = qcn_state->qcn_dip;
    254 	int		actual, count = 0;
    255 	int 		x, y, rc, inum = 0;
    256 
    257 
    258 	/* get number of interrupts */
    259 	rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count);
    260 	if ((rc != DDI_SUCCESS) || (count == 0)) {
    261 		return (DDI_FAILURE);
    262 	}
    263 
    264 	/* Allocate an array of interrupt handles */
    265 	qcn_state->qcn_intr_size = count * sizeof (ddi_intr_handle_t);
    266 	qcn_state->qcn_htable = kmem_zalloc(qcn_state->qcn_intr_size, KM_SLEEP);
    267 
    268 	/* call ddi_intr_alloc() */
    269 	rc = ddi_intr_alloc(devinfo, qcn_state->qcn_htable,
    270 	    DDI_INTR_TYPE_FIXED, inum, count, &actual,
    271 	    DDI_INTR_ALLOC_STRICT);
    272 
    273 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
    274 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    275 		return (DDI_FAILURE);
    276 	}
    277 
    278 	if (actual < count) {
    279 		for (x = 0; x < actual; x++) {
    280 			(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    281 		}
    282 
    283 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    284 		return (DDI_FAILURE);
    285 	}
    286 
    287 	qcn_state->qcn_intr_cnt = actual;
    288 
    289 	/* Get intr priority */
    290 	if (ddi_intr_get_pri(qcn_state->qcn_htable[0],
    291 	    &qcn_state->qcn_intr_pri) != DDI_SUCCESS) {
    292 		for (x = 0; x < actual; x++) {
    293 			(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    294 		}
    295 
    296 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    297 		return (DDI_FAILURE);
    298 	}
    299 
    300 	/* Call ddi_intr_add_handler() */
    301 	for (x = 0; x < actual; x++) {
    302 		if (ddi_intr_add_handler(qcn_state->qcn_htable[x],
    303 		    (ddi_intr_handler_t *)qcn_hi_intr,
    304 		    (caddr_t)qcn_state, NULL) != DDI_SUCCESS) {
    305 
    306 			for (y = 0; y < x; y++) {
    307 				(void) ddi_intr_remove_handler(
    308 				    qcn_state->qcn_htable[y]);
    309 			}
    310 
    311 			for (y = 0; y < actual; y++) {
    312 				(void) ddi_intr_free(qcn_state->qcn_htable[y]);
    313 			}
    314 
    315 			kmem_free(qcn_state->qcn_htable,
    316 			    qcn_state->qcn_intr_size);
    317 			return (DDI_FAILURE);
    318 		}
    319 	}
    320 
    321 	return (DDI_SUCCESS);
    322 }
    323 
    324 static void
    325 qcn_remove_intrs(void)
    326 {
    327 	int x;
    328 	for (x = 0; x < qcn_state->qcn_intr_cnt; x++) {
    329 		(void) ddi_intr_disable(qcn_state->qcn_htable[x]);
    330 		(void) ddi_intr_remove_handler(qcn_state->qcn_htable[x]);
    331 		(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    332 	}
    333 	kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    334 }
    335 
    336 static void
    337 qcn_intr_enable(void)
    338 {
    339 	int x;
    340 
    341 	for (x = 0; x < qcn_state->qcn_intr_cnt; x++) {
    342 		(void) ddi_intr_enable(qcn_state->qcn_htable[x]);
    343 	}
    344 }
    345 
    346 /*
    347  * qcn_attach is called at startup time.
    348  * There is only once instance of this driver.
    349  */
    350 static int
    351 qcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    352 {
    353 	extern int ddi_create_internal_pathname(dev_info_t *, char *,
    354 	    int, minor_t);
    355 	uint_t soft_prip;
    356 
    357 #ifdef QCN_POLLING
    358 	char *binding_name;
    359 #endif
    360 	if (cmd != DDI_ATTACH)
    361 		return (DDI_FAILURE);
    362 
    363 	if (ddi_create_internal_pathname(dip, "qcn",
    364 	    S_IFCHR, 0) != DDI_SUCCESS)
    365 		return (DDI_FAILURE);
    366 
    367 	qcn_state->qcn_soft_pend = 0;
    368 	qcn_state->qcn_hangup = 0;
    369 	qcn_state->qcn_rbuf_overflow = 0;
    370 
    371 	/* prepare some data structures in soft state */
    372 
    373 	qcn_state->qcn_dip = dip;
    374 
    375 	qcn_state->qcn_polling = 0;
    376 
    377 #ifdef QCN_POLLING
    378 	/*
    379 	 * This test is for the sole purposes of allowing
    380 	 * the console to work on older firmware releases.
    381 	 */
    382 	binding_name = ddi_binding_name(qcn_state->qcn_dip);
    383 	if ((strcmp(binding_name, "qcn") == 0) ||
    384 	    (qcn_force_polling))
    385 		qcn_state->qcn_polling = 1;
    386 
    387 	if (qcn_state->qcn_polling) {
    388 		qcn_poll_time.cyt_when = 0ull;
    389 		qcn_poll_time.cyt_interval =
    390 		    qcn_poll_interval * 1000ull * 1000ull;
    391 		mutex_enter(&cpu_lock);
    392 		qcn_poll_cycid = cyclic_add(&qcn_poll_cychandler,
    393 		    &qcn_poll_time);
    394 		mutex_exit(&cpu_lock);
    395 	}
    396 #endif
    397 
    398 	if (!qcn_state->qcn_polling) {
    399 		if (qcn_add_intrs() != DDI_SUCCESS) {
    400 			cmn_err(CE_WARN, "qcn_attach: add_intr failed\n");
    401 			return (DDI_FAILURE);
    402 		}
    403 		if (ddi_intr_add_softint(dip, &qcn_state->qcn_softint_hdl,
    404 		    DDI_INTR_SOFTPRI_MAX, qcn_soft_intr,
    405 		    (caddr_t)qcn_state) != DDI_SUCCESS) {
    406 			cmn_err(CE_WARN, "qcn_attach: add_soft_intr failed\n");
    407 			qcn_remove_intrs();
    408 			return (DDI_FAILURE);
    409 		}
    410 		if (ddi_intr_get_softint_pri(qcn_state->qcn_softint_hdl,
    411 		    &soft_prip) != DDI_SUCCESS) {
    412 			cmn_err(CE_WARN, "qcn_attach: softint_pri failed\n");
    413 			(void) ddi_intr_remove_softint(
    414 			    qcn_state->qcn_softint_hdl);
    415 			qcn_remove_intrs();
    416 			return (DDI_FAILURE);
    417 		}
    418 
    419 	mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER,
    420 	    (void *)(uintptr_t)(qcn_state->qcn_intr_pri));
    421 	}
    422 
    423 	mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL);
    424 
    425 	/*
    426 	 * Fill in the polled I/O structure.
    427 	 */
    428 	qcn_state->qcn_polledio.cons_polledio_version = CONSPOLLEDIO_V1;
    429 	qcn_state->qcn_polledio.cons_polledio_argument =
    430 	    (cons_polledio_arg_t)qcn_state;
    431 	qcn_state->qcn_polledio.cons_polledio_putchar = qcn_polledio_putchar;
    432 	qcn_state->qcn_polledio.cons_polledio_getchar = qcn_polledio_getchar;
    433 	qcn_state->qcn_polledio.cons_polledio_ischar = qcn_polledio_ischar;
    434 	qcn_state->qcn_polledio.cons_polledio_enter = qcn_polledio_enter;
    435 	qcn_state->qcn_polledio.cons_polledio_exit = qcn_polledio_exit;
    436 
    437 	/*
    438 	 *  Enable  interrupts
    439 	 */
    440 	if (!qcn_state->qcn_polling) {
    441 		qcn_intr_enable();
    442 	}
    443 #ifdef QCN_DEBUG
    444 	prom_printf("qcn_attach(): qcn driver attached\n");
    445 #endif
    446 
    447 	return (DDI_SUCCESS);
    448 
    449 }
    450 
    451 /* ARGSUSED */
    452 static int
    453 qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    454 {
    455 
    456 	if (cmd != DDI_DETACH)
    457 		return (DDI_FAILURE);
    458 
    459 
    460 #ifdef QCN_DEBUG
    461 	prom_printf("qcn_detach(): QCN driver detached\n");
    462 #endif
    463 
    464 #ifdef QCN_POLLING
    465 	if (qcn_state->qcn_polling) {
    466 		mutex_enter(&cpu_lock);
    467 		if (qcn_poll_cycid != CYCLIC_NONE)
    468 			cyclic_remove(qcn_poll_cycid);
    469 		qcn_poll_cycid = CYCLIC_NONE;
    470 		mutex_exit(&cpu_lock);
    471 	}
    472 #endif
    473 
    474 	if (!qcn_state->qcn_polling)
    475 		qcn_remove_intrs();
    476 
    477 	return (DDI_SUCCESS);
    478 }
    479 
    480 /* ARGSUSED */
    481 static int
    482 qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
    483 {
    484 	int error = DDI_FAILURE;
    485 	int instance = 0;
    486 	switch (infocmd) {
    487 	case DDI_INFO_DEVT2DEVINFO:
    488 		if (qcn_state) {
    489 #ifdef QCN_DEBUG
    490 			prom_printf("qcn_getinfo(): devt2dip %lx\n", arg);
    491 #endif
    492 			*result = (void *)qcn_state->qcn_dip;
    493 			error = DDI_SUCCESS;
    494 		}
    495 		break;
    496 
    497 	case DDI_INFO_DEVT2INSTANCE:
    498 #ifdef QCN_DEBUG
    499 		prom_printf("qcn_getinfo(): devt2instance %lx\n", arg);
    500 #endif
    501 		if (getminor((dev_t)arg) == 0) {
    502 			*result = (void *)(uintptr_t)instance;
    503 			error = DDI_SUCCESS;
    504 		}
    505 		break;
    506 	}
    507 
    508 	return (error);
    509 }
    510 
    511 /* streams open & close */
    512 /* ARGSUSED */
    513 static int
    514 qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
    515 {
    516 	tty_common_t *tty;
    517 	int unit = getminor(*devp);
    518 
    519 #ifdef QCN_DEBUG
    520 	prom_printf("qcn_open(): minor %x\n", unit);
    521 #endif
    522 
    523 	if (unit != 0)
    524 		return (ENXIO);
    525 
    526 	/* stream already open */
    527 	if (q->q_ptr != NULL)
    528 		return (DDI_SUCCESS);
    529 
    530 	if (!qcn_state) {
    531 		cmn_err(CE_WARN, "qcn_open: console was not configured by "
    532 		    "autoconfig\n");
    533 		return (ENXIO);
    534 	}
    535 
    536 	mutex_enter(&qcn_state->qcn_lock);
    537 	tty = &(qcn_state->qcn_tty);
    538 
    539 	tty->t_readq = q;
    540 	tty->t_writeq = WR(q);
    541 
    542 	/* Link the RD and WR Q's */
    543 	q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state;
    544 	qcn_state->qcn_readq = RD(q);
    545 	qcn_state->qcn_writeq = WR(q);
    546 	qprocson(q);
    547 
    548 	mutex_exit(&qcn_state->qcn_lock);
    549 
    550 #ifdef QCN_DEBUG
    551 	prom_printf("qcn_open: opened as dev %lx\n", *devp);
    552 #endif
    553 
    554 	return (DDI_SUCCESS);
    555 }
    556 
    557 /* ARGSUSED */
    558 static int
    559 qcn_close(queue_t *q, int flag, cred_t *credp)
    560 {
    561 
    562 	ASSERT(qcn_state == q->q_ptr);
    563 
    564 	if (qcn_state->qcn_wbufcid != 0) {
    565 		unbufcall(qcn_state->qcn_wbufcid);
    566 	}
    567 	ttycommon_close(&qcn_state->qcn_tty);
    568 
    569 	qprocsoff(q);
    570 	q->q_ptr = WR(q)->q_ptr = NULL;
    571 	qcn_state->qcn_readq = NULL;
    572 	qcn_state->qcn_writeq = NULL;
    573 
    574 	return (DDI_SUCCESS);
    575 }
    576 
    577 /*
    578  * Put procedure for write queue.
    579  * Respond to M_IOCTL, M_DATA and M_FLUSH messages here;
    580  * It put's the data onto internal qcn_output_q.
    581  */
    582 static int
    583 qcn_wput(queue_t *q, mblk_t *mp)
    584 {
    585 
    586 #ifdef QCN_DEBUG
    587 	struct iocblk *iocp;
    588 	int i;
    589 #endif
    590 
    591 	ASSERT(qcn_state == q->q_ptr);
    592 
    593 	if (!mp->b_datap) {
    594 		cmn_err(CE_PANIC, "qcn_wput: null datap");
    595 	}
    596 
    597 #ifdef QCN_DEBUG
    598 	prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n",
    599 	    q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type);
    600 #endif
    601 
    602 	mutex_enter(&qcn_state->qcn_lock);
    603 
    604 	switch (mp->b_datap->db_type) {
    605 	case M_IOCTL:
    606 	case M_CTL:
    607 #ifdef QCN_DEBUG
    608 		iocp = (struct iocblk *)mp->b_rptr;
    609 		prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n",
    610 		    iocp->ioc_cmd, TIOC);
    611 #endif
    612 		switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
    613 		case TCSETSW:
    614 		case TCSETSF:
    615 		case TCSETAW:
    616 		case TCSETAF:
    617 		case TCSBRK:
    618 			/*
    619 			 * The change do not take effect until all
    620 			 * output queued before them is drained.
    621 			 * Put this message on the queue, so that
    622 			 * "qcn_start" will see it when it's done
    623 			 * with the output before it. Poke the start
    624 			 * routine, just in case.
    625 			 */
    626 			(void) putq(q, mp);
    627 			qcn_start();
    628 			break;
    629 		default:
    630 			mutex_exit(&qcn_state->qcn_lock);
    631 			qcn_ioctl(q, mp);
    632 			mutex_enter(&qcn_state->qcn_lock);
    633 		}
    634 		break;
    635 
    636 	case M_FLUSH:
    637 		if (*mp->b_rptr & FLUSHW) {
    638 			flushq(q, FLUSHDATA);
    639 			*mp->b_rptr &= ~FLUSHW;
    640 		}
    641 		if (*mp->b_rptr & FLUSHR) {
    642 			flushq(RD(q), FLUSHDATA);
    643 			qreply(q, mp);
    644 		} else {
    645 			freemsg(mp);
    646 		}
    647 		break;
    648 
    649 	case M_STOP:
    650 		qcn_stopped = B_TRUE;
    651 		freemsg(mp);
    652 		break;
    653 
    654 	case M_START:
    655 		qcn_stopped = B_FALSE;
    656 		freemsg(mp);
    657 		qenable(q);	/* Start up delayed messages */
    658 		break;
    659 
    660 	case M_DATA:
    661 		/*
    662 		 * Queue the message up to be transmitted,
    663 		 * and poke the start routine.
    664 		 */
    665 #ifdef QCN_DEBUG
    666 		if (mp->b_rptr < mp->b_wptr) {
    667 		prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n",
    668 		    q, mp, mp->b_rptr, mp->b_wptr);
    669 		prom_printf("qcn_wput(): [");
    670 		for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) {
    671 			prom_printf("%c", *(mp->b_rptr+i));
    672 		}
    673 		prom_printf("]\n");
    674 		}
    675 #endif /* QCN_DEBUG */
    676 		(void) putq(q, mp);
    677 		qcn_start();
    678 		break;
    679 
    680 	default:
    681 		freemsg(mp);
    682 	}
    683 
    684 	mutex_exit(&qcn_state->qcn_lock);
    685 
    686 	return (0);
    687 }
    688 
    689 /*
    690  * Process an "ioctl" message sent down to us.
    691  */
    692 static void
    693 qcn_ioctl(queue_t *q, mblk_t *mp)
    694 {
    695 	struct iocblk	*iocp;
    696 	tty_common_t	*tty;
    697 	mblk_t		*datamp;
    698 	int		data_size;
    699 	int		error = 0;
    700 
    701 #ifdef QCN_DEBUG
    702 	prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp);
    703 #endif
    704 
    705 	iocp = (struct iocblk *)mp->b_rptr;
    706 
    707 	tty = &(qcn_state->qcn_tty);
    708 
    709 	if (tty->t_iocpending != NULL) {
    710 		freemsg(tty->t_iocpending);
    711 		tty->t_iocpending = NULL;
    712 	}
    713 
    714 	/*
    715 	 * Handle the POLLEDIO ioctls now because ttycommon_ioctl
    716 	 * (below) frees up the message block (mp->b_cont) which
    717 	 * contains the pointer used to pass back results.
    718 	 */
    719 	switch (iocp->ioc_cmd) {
    720 	case CONSOPENPOLLEDIO:
    721 		error = miocpullup(mp, sizeof (struct cons_polledio *));
    722 		if (error != 0)
    723 			break;
    724 
    725 		*(struct cons_polledio **)mp->b_cont->b_rptr =
    726 		    &qcn_state->qcn_polledio;
    727 
    728 		mp->b_datap->db_type = M_IOCACK;
    729 		break;
    730 
    731 	case CONSCLOSEPOLLEDIO:
    732 		mp->b_datap->db_type = M_IOCACK;
    733 		iocp->ioc_error = 0;
    734 		iocp->ioc_rval = 0;
    735 		break;
    736 
    737 	default:
    738 		data_size = ttycommon_ioctl(tty, q, mp, &error);
    739 		if (data_size != 0) {
    740 			if (qcn_state->qcn_wbufcid)
    741 				unbufcall(qcn_state->qcn_wbufcid);
    742 			/* call qcn_reioctl() */
    743 			qcn_state->qcn_wbufcid =
    744 			    bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state);
    745 			return;
    746 		}
    747 	}
    748 
    749 	mutex_enter(&qcn_state->qcn_lock);
    750 
    751 	if (error < 0) {
    752 		iocp = (struct iocblk *)mp->b_rptr;
    753 		/*
    754 		 * "ttycommon_ioctl" didn't do anything; we process it here.
    755 		 */
    756 		error = 0;
    757 		switch (iocp->ioc_cmd) {
    758 		case TCSBRK:
    759 		case TIOCSBRK:
    760 		case TIOCCBRK:
    761 		case TIOCMSET:
    762 		case TIOCMBIS:
    763 		case TIOCMBIC:
    764 			if (iocp->ioc_count != TRANSPARENT)
    765 				qcn_ack(mp, NULL, 0);
    766 			else
    767 				mcopyin(mp, NULL, sizeof (int), NULL);
    768 			break;
    769 
    770 		case TIOCMGET:
    771 			datamp = allocb(sizeof (int), BPRI_MED);
    772 			if (datamp == NULL) {
    773 				error = EAGAIN;
    774 				break;
    775 			}
    776 
    777 			*(int *)datamp->b_rptr = 0;
    778 
    779 			if (iocp->ioc_count != TRANSPARENT)
    780 				qcn_ack(mp, datamp, sizeof (int));
    781 			else
    782 				mcopyout(mp, NULL, sizeof (int), NULL, datamp);
    783 			break;
    784 
    785 		default:
    786 			error = EINVAL;
    787 			break;
    788 		}
    789 	}
    790 	if (error != 0) {
    791 		iocp->ioc_count = 0;
    792 		iocp->ioc_error = error;
    793 		mp->b_datap->db_type = M_IOCNAK;
    794 	}
    795 	mutex_exit(&qcn_state->qcn_lock);
    796 	qreply(q, mp);
    797 }
    798 
    799 static void
    800 qcn_reioctl(void *unit)
    801 {
    802 	queue_t		*q;
    803 	mblk_t		*mp;
    804 	qcn_t		*qcnp = (qcn_t *)unit;
    805 
    806 	if (!qcnp->qcn_wbufcid)
    807 		return;
    808 
    809 	qcnp->qcn_wbufcid = 0;
    810 	if ((q = qcnp->qcn_tty.t_writeq) == NULL)
    811 		return;
    812 
    813 	if ((mp = qcnp->qcn_tty.t_iocpending) == NULL)
    814 		return;
    815 
    816 	qcnp->qcn_tty.t_iocpending = NULL;
    817 	qcn_ioctl(q, mp);
    818 }
    819 
    820 static void
    821 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size)
    822 {
    823 	struct iocblk  *iocp = (struct iocblk *)mp->b_rptr;
    824 
    825 	mp->b_datap->db_type = M_IOCACK;
    826 	iocp->ioc_count = size;
    827 	iocp->ioc_error = 0;
    828 	iocp->ioc_rval = 0;
    829 	if (mp->b_cont != NULL)
    830 		freeb(mp->b_cont);
    831 	if (dp != NULL) {
    832 		mp->b_cont = dp;
    833 		dp->b_wptr += size;
    834 	} else
    835 		mp->b_cont = NULL;
    836 }
    837 
    838 static void
    839 qcn_start(void)
    840 {
    841 
    842 	queue_t *q;
    843 	mblk_t *mp;
    844 	int rv;
    845 
    846 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
    847 
    848 	/*
    849 	 * read stream queue and remove data from the queue and
    850 	 * transmit them if possible
    851 	 */
    852 	q = qcn_state->qcn_writeq;
    853 	ASSERT(q != NULL);
    854 	while (mp = getq(q)) {
    855 		if (mp->b_datap->db_type == M_IOCTL) {
    856 			/*
    857 			 * These are those IOCTLs queued up
    858 			 * do it now
    859 			 */
    860 			mutex_exit(&qcn_state->qcn_lock);
    861 			qcn_ioctl(q, mp);
    862 			mutex_enter(&qcn_state->qcn_lock);
    863 			continue;
    864 		}
    865 		/*
    866 		 * M_DATA
    867 		 */
    868 		rv = qcn_state->cons_transmit(q, mp);
    869 		if (rv == EBUSY || rv == EAGAIN)
    870 			return;
    871 	}
    872 }
    873 
    874 static int
    875 qcn_transmit_write(queue_t *q, mblk_t *mp)
    876 {
    877 	mblk_t		*bp;
    878 	size_t		len;
    879 	uint64_t	i;
    880 	uint64_t	retval = 0;
    881 
    882 #ifdef QCN_DEBUG
    883 	prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp);
    884 #endif
    885 
    886 	while (mp) {
    887 		bp = mp;
    888 		len = bp->b_wptr - bp->b_rptr;
    889 		/*
    890 		 * Use the console write call to send a block of characters to
    891 		 * the console.
    892 		 */
    893 		i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len;
    894 		bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i);
    895 		retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i);
    896 
    897 		if (retval == H_EOK) {
    898 			len -= i;
    899 			bp->b_rptr += i;
    900 			/*
    901 			 * if we have finished with this buf, free
    902 			 * and get the next buf if present.
    903 			 */
    904 			if (len == 0) {
    905 				mp = bp->b_cont;
    906 				freeb(bp);
    907 			}
    908 		} else {
    909 			(void) putbq(q, mp);
    910 
    911 			switch (retval) {
    912 
    913 			case H_EWOULDBLOCK :
    914 				/*
    915 				 * hypervisor cannot process the request -
    916 				 * channel busy.  Try again later.
    917 				 */
    918 				return (EAGAIN);
    919 
    920 			case H_EIO :
    921 				return (EIO);
    922 			default :
    923 				return (ENXIO);
    924 			}
    925 		}
    926 	}
    927 	return (0);
    928 }
    929 
    930 static int
    931 qcn_transmit_putchr(queue_t *q, mblk_t *mp)
    932 {
    933 	caddr_t		buf;
    934 	mblk_t		*bp;
    935 	size_t		len;
    936 	uint64_t	i;
    937 
    938 #ifdef QCN_DEBUG
    939 	prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp);
    940 #endif
    941 	while (mp) {
    942 		bp = mp;
    943 		len = bp->b_wptr - bp->b_rptr;
    944 		buf = (caddr_t)bp->b_rptr;
    945 		for (i = 0; i < len; i++) {
    946 			if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK)
    947 				break;
    948 		}
    949 		if (i != len) {
    950 			bp->b_rptr += i;
    951 			(void) putbq(q, mp);
    952 			return (EAGAIN);
    953 		}
    954 		mp = bp->b_cont;
    955 		freeb(bp);
    956 	}
    957 	return (0);
    958 }
    959 
    960 /*
    961  * called when SC first establishes console connection
    962  * drop all the data on the output queue
    963  */
    964 static void
    965 qcn_flush(void)
    966 {
    967 	queue_t *q;
    968 	mblk_t *mp;
    969 
    970 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
    971 
    972 	q = qcn_state->qcn_writeq;
    973 
    974 	prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n",
    975 	    gethrestime_sec());
    976 	while (mp = getq(q))
    977 		freemsg(mp);
    978 }
    979 
    980 static void
    981 qcn_trigger_softint(void)
    982 {
    983 	/*
    984 	 * if we are not currently servicing a software interrupt
    985 	 * (qcn_soft_pend == 0), trigger the service routine to run.
    986 	 */
    987 	if (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_DO) ==
    988 	    QCN_SP_IDL) {
    989 		(void) ddi_intr_trigger_softint(
    990 		    qcn_state->qcn_softint_hdl, NULL);
    991 	}
    992 }
    993 
    994 /*ARGSUSED*/
    995 static uint_t
    996 qcn_soft_intr(caddr_t arg1, caddr_t arg2)
    997 {
    998 	mblk_t *mp;
    999 	int	cc;
   1000 	int	overflow_check;
   1001 
   1002 	do {
   1003 		(void) atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IP);
   1004 		mutex_enter(&qcn_state->qcn_hi_lock);
   1005 		cc = RING_CNT(qcn_state);
   1006 		mutex_exit(&qcn_state->qcn_hi_lock);
   1007 		if (cc <= 0) {
   1008 			goto out;
   1009 		}
   1010 
   1011 		if ((mp = allocb(cc, BPRI_MED)) == NULL) {
   1012 			mutex_enter(&qcn_state->qcn_hi_lock);
   1013 			qcn_input_dropped += cc;
   1014 			mutex_exit(&qcn_state->qcn_hi_lock);
   1015 			cmn_err(CE_WARN, "qcn_intr: allocb"
   1016 			    "failed (console input dropped)");
   1017 			goto out;
   1018 		}
   1019 
   1020 		mutex_enter(&qcn_state->qcn_hi_lock);
   1021 		do {
   1022 			/* put console input onto stream */
   1023 			*(char *)mp->b_wptr++ = RING_GET(qcn_state);
   1024 		} while (--cc);
   1025 
   1026 		if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) {
   1027 			qcn_state->qcn_rbuf_overflow = 0;
   1028 		}
   1029 		mutex_exit(&qcn_state->qcn_hi_lock);
   1030 
   1031 		if (overflow_check) {
   1032 			cmn_err(CE_WARN, "qcn: Ring buffer overflow\n");
   1033 		}
   1034 
   1035 		if (qcn_state->qcn_readq) {
   1036 			putnext(qcn_state->qcn_readq, mp);
   1037 		}
   1038 out:
   1039 		/*
   1040 		 * If there are pending transmits because hypervisor
   1041 		 * returned EWOULDBLOCK poke start now.
   1042 		 */
   1043 
   1044 		if (qcn_state->qcn_writeq != NULL) {
   1045 			if (qcn_state->qcn_hangup) {
   1046 				(void) putctl(qcn_state->qcn_readq, M_HANGUP);
   1047 				flushq(qcn_state->qcn_writeq, FLUSHDATA);
   1048 				qcn_state->qcn_hangup = 0;
   1049 			} else {
   1050 				mutex_enter(&qcn_state->qcn_lock);
   1051 				qcn_start();
   1052 				mutex_exit(&qcn_state->qcn_lock);
   1053 			}
   1054 		}
   1055 		/*
   1056 		 * now loop if another interrupt came in (qcn_trigger_softint
   1057 		 * called) while we were processing the loop
   1058 		 */
   1059 	} while (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IDL) ==
   1060 	    QCN_SP_DO);
   1061 	return (DDI_INTR_CLAIMED);
   1062 }
   1063 
   1064 /*ARGSUSED*/
   1065 static uint_t
   1066 qcn_hi_intr(caddr_t arg)
   1067 {
   1068 	mutex_enter(&qcn_state->qcn_hi_lock);
   1069 
   1070 	qcn_state->cons_receive();
   1071 
   1072 	mutex_exit(&qcn_state->qcn_hi_lock);
   1073 	qcn_trigger_softint();
   1074 
   1075 	return (DDI_INTR_CLAIMED);
   1076 }
   1077 
   1078 static void
   1079 qcn_receive_read(void)
   1080 {
   1081 	int64_t rv;
   1082 	uint8_t *bufp;
   1083 	int64_t	retcount = 0;
   1084 	int	i;
   1085 
   1086 	do {
   1087 		/*
   1088 		 * Maximize available buffer size
   1089 		 */
   1090 		if (RING_CNT(qcn_state) <= 0) {
   1091 			RING_INIT(qcn_state);
   1092 		}
   1093 		rv = hv_cnread(qcn_state->cons_read_buf_ra +
   1094 		    RING_POFF(qcn_state),
   1095 		    RING_LEFT(qcn_state),
   1096 		    &retcount);
   1097 		bufp = RING_ADDR(qcn_state);
   1098 		if (rv == H_EOK) {
   1099 			/*
   1100 			 * if the alternate break sequence is enabled, test
   1101 			 * the buffer for the sequence and if it is there,
   1102 			 * enter the debugger.
   1103 			 */
   1104 			if (abort_enable == KIOCABORTALTERNATE) {
   1105 				for (i = 0; i < retcount; i++) {
   1106 					if (abort_charseq_recognize(*bufp++)) {
   1107 						abort_sequence_enter(
   1108 						    (char *)NULL);
   1109 					}
   1110 				}
   1111 			}
   1112 
   1113 			/* put console input onto stream */
   1114 			if (retcount > 0) {
   1115 				/*
   1116 				 * the characters are already in the ring,
   1117 				 * just update the pointer so the characters
   1118 				 * can be retrieved.
   1119 				 */
   1120 				RING_UPD(qcn_state, retcount);
   1121 			}
   1122 		} else {
   1123 			switch (rv) {
   1124 
   1125 			case H_EWOULDBLOCK :
   1126 				/*
   1127 				 * hypervisor cannot handle the request.
   1128 				 * Try again later.
   1129 				 */
   1130 				break;
   1131 
   1132 
   1133 			case H_BREAK :
   1134 				/*
   1135 				 * on break enter the debugger
   1136 				 */
   1137 				abort_sequence_enter((char *)NULL);
   1138 				break;
   1139 
   1140 			case H_HUP :
   1141 				qcn_state->qcn_hangup = 1;
   1142 				break;
   1143 
   1144 			default :
   1145 				break;
   1146 			}
   1147 		}
   1148 	} while (rv == H_EOK);
   1149 }
   1150 
   1151 static void
   1152 qcn_receive_getchr(void)
   1153 {
   1154 	int64_t rv;
   1155 	uint8_t	buf;
   1156 
   1157 	do {
   1158 		rv = hv_cngetchar(&buf);
   1159 		if (rv == H_EOK) {
   1160 			if (abort_enable == KIOCABORTALTERNATE) {
   1161 				if (abort_charseq_recognize(buf)) {
   1162 					abort_sequence_enter((char *)NULL);
   1163 				}
   1164 			}
   1165 
   1166 			/* put console input onto stream */
   1167 			if (RING_POK(qcn_state, 1)) {
   1168 				RING_PUT(qcn_state, buf);
   1169 			} else {
   1170 				qcn_state->qcn_rbuf_overflow++;
   1171 			}
   1172 		} else {
   1173 			if (rv == H_BREAK) {
   1174 				abort_sequence_enter((char *)NULL);
   1175 			}
   1176 
   1177 			if (rv == H_HUP)  {
   1178 				qcn_state->qcn_hangup = 1;
   1179 			}
   1180 			return;
   1181 		}
   1182 	} while (rv == H_EOK);
   1183 }
   1184 
   1185 #ifdef QCN_POLLING
   1186 /*ARGSUSED*/
   1187 static void
   1188 qcn_poll_handler(void *unused)
   1189 {
   1190 	mblk_t *mp;
   1191 	int64_t rv;
   1192 	uint8_t buf;
   1193 	int qcn_writeq_flush = 0;
   1194 
   1195 	/* LINTED: E_CONSTANT_CONDITION */
   1196 	while (1) {
   1197 		rv = hv_cngetchar(&buf);
   1198 		if (rv == H_BREAK) {
   1199 			abort_sequence_enter((char *)NULL);
   1200 		}
   1201 
   1202 		if (rv == H_HUP)  {
   1203 			if (qcn_state->qcn_readq) {
   1204 				(void) putctl(qcn_state->qcn_readq, M_HANGUP);
   1205 				qcn_writeq_flush = 1;
   1206 			}
   1207 			goto out;
   1208 		}
   1209 
   1210 		if (rv != H_EOK)
   1211 			goto out;
   1212 
   1213 		if (abort_enable == KIOCABORTALTERNATE) {
   1214 			if (abort_charseq_recognize(buf)) {
   1215 				abort_sequence_enter((char *)NULL);
   1216 			}
   1217 		}
   1218 
   1219 		/* put console input onto stream */
   1220 		if (qcn_state->qcn_readq) {
   1221 			if ((mp = allocb(1, BPRI_MED)) == NULL) {
   1222 				qcn_input_dropped++;
   1223 				cmn_err(CE_WARN, "qcn_intr: allocb"
   1224 				    "failed (console input dropped)");
   1225 				return;
   1226 			}
   1227 			*(char *)mp->b_wptr++ = buf;
   1228 			putnext(qcn_state->qcn_readq, mp);
   1229 		}
   1230 	}
   1231 out:
   1232 /*
   1233  * If there are pending transmits because hypervisor
   1234  * returned EWOULDBLOCK poke start now.
   1235  */
   1236 
   1237 	mutex_enter(&qcn_state->qcn_lock);
   1238 	if (qcn_state->qcn_writeq != NULL) {
   1239 		if (qcn_writeq_flush) {
   1240 			flushq(qcn_state->qcn_writeq, FLUSHDATA);
   1241 		} else {
   1242 			qcn_start();
   1243 		}
   1244 	}
   1245 	mutex_exit(&qcn_state->qcn_lock);
   1246 }
   1247 #endif
   1248 
   1249 /*
   1250  * Check for abort character sequence, copied from zs_async.c
   1251  */
   1252 #define	CNTRL(c) ((c)&037)
   1253 
   1254 static boolean_t
   1255 abort_charseq_recognize(uchar_t ch)
   1256 {
   1257 	static int state = 0;
   1258 	static char sequence[] = { '\r', '~', CNTRL('b') };
   1259 
   1260 	if (ch == sequence[state]) {
   1261 		if (++state >= sizeof (sequence)) {
   1262 			state = 0;
   1263 			return (B_TRUE);
   1264 		}
   1265 	} else {
   1266 		state = (ch == sequence[0]) ? 1 : 0;
   1267 	}
   1268 	return (B_FALSE);
   1269 }
   1270 
   1271 
   1272 static int
   1273 qcn_rsrv(queue_t *q)
   1274 {
   1275 	mblk_t	*mp;
   1276 
   1277 	if (qcn_stopped == B_TRUE)
   1278 		return (0);
   1279 
   1280 	mutex_enter(&qcn_state->qcn_lock);
   1281 
   1282 	while ((mp = getq(q)) != NULL) {
   1283 		if (canputnext(q))
   1284 			putnext(q, mp);
   1285 		else if (mp->b_datap->db_type >= QPCTL)
   1286 			(void) putbq(q, mp);
   1287 	}
   1288 
   1289 	mutex_exit(&qcn_state->qcn_lock);
   1290 
   1291 	return (0);
   1292 }
   1293 
   1294 /* ARGSUSED */
   1295 static int
   1296 qcn_wsrv(queue_t *q)
   1297 {
   1298 	if (qcn_stopped == B_TRUE)
   1299 		return (0);
   1300 
   1301 	mutex_enter(&qcn_state->qcn_lock);
   1302 
   1303 	if (qcn_state->qcn_writeq != NULL)
   1304 		qcn_start();
   1305 
   1306 	mutex_exit(&qcn_state->qcn_lock);
   1307 
   1308 	return (0);
   1309 }
   1310 
   1311 static boolean_t
   1312 qcn_polledio_ischar(cons_polledio_arg_t arg)
   1313 {
   1314 	qcn_t *state = (qcn_t *)arg;
   1315 
   1316 	if (state->qcn_char_available)
   1317 		return (B_TRUE);
   1318 
   1319 	return (state->qcn_char_available =
   1320 	    (hv_cngetchar(&state->qcn_hold_char) == H_EOK));
   1321 }
   1322 
   1323 
   1324 static int
   1325 qcn_polledio_getchar(cons_polledio_arg_t arg)
   1326 {
   1327 	qcn_t *state = (qcn_t *)arg;
   1328 
   1329 	while (!qcn_polledio_ischar(arg))
   1330 		drv_usecwait(10);
   1331 
   1332 	state->qcn_char_available = B_FALSE;
   1333 
   1334 	return ((int)state->qcn_hold_char);
   1335 }
   1336 
   1337 static void
   1338 qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c)
   1339 {
   1340 	if (c == '\n')
   1341 		qcn_polledio_putchar(arg, '\r');
   1342 
   1343 	while (hv_cnputchar((uint8_t)c) == H_EWOULDBLOCK)
   1344 		drv_usecwait(10);
   1345 }
   1346 
   1347 static void
   1348 qcn_polledio_enter(cons_polledio_arg_t arg)
   1349 {
   1350 	qcn_t *state = (qcn_t *)arg;
   1351 
   1352 	state->qcn_char_available = B_FALSE;
   1353 }
   1354 
   1355 /* ARGSUSED */
   1356 static void
   1357 qcn_polledio_exit(cons_polledio_arg_t arg)
   1358 {
   1359 }
   1360