xref: /illumos-gate/usr/src/uts/sun4v/io/qcn.c (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * sun4v console driver
31  */
32 
33 #include <sys/errno.h>
34 #include <sys/stat.h>
35 #include <sys/kmem.h>
36 #include <sys/conf.h>
37 #include <sys/termios.h>
38 #include <sys/modctl.h>
39 #include <sys/kbio.h>
40 #include <sys/stropts.h>
41 #include <sys/stream.h>
42 #include <sys/strsun.h>
43 #include <sys/sysmacros.h>
44 #include <sys/promif.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/cyclic.h>
48 #include <sys/intr.h>
49 #include <sys/spl.h>
50 #include <sys/qcn.h>
51 #include <sys/hypervisor_api.h>
52 #include <sys/hsvc.h>
53 #include <sys/machsystm.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 static boolean_t abort_charseq_recognize(uchar_t);
79 
80 static qcn_t *qcn_state;
81 static uchar_t qcn_stopped = B_FALSE;
82 static int qcn_timeout_period = 20;	/* time out in seconds */
83 size_t qcn_input_dropped;	/* dropped input character counter */
84 
85 static cyc_time_t qcn_poll_time;
86 static uint64_t	qcn_poll_interval = 5;  /* milli sec */
87 static void qcn_tx_block_handler(void *unused);
88 static cyc_handler_t qcn_tx_block_cychandler = {
89 	qcn_tx_block_handler,
90 	NULL,
91 	CY_LOW_LEVEL
92 };
93 static cyclic_id_t qcn_tx_block_cycid = CYCLIC_NONE;
94 
95 #ifdef QCN_POLLING
96 static void qcn_poll_handler(void *unused);
97 static cyc_handler_t qcn_poll_cychandler = {
98 	qcn_poll_handler,
99 	NULL,
100 	CY_LOW_LEVEL		/* XXX need softint to make this high */
101 };
102 static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE;
103 static uint64_t sb_interval = 0;
104 uint_t qcn_force_polling = 0;
105 #endif
106 
107 
108 #define	QCN_MI_IDNUM		0xABCE
109 #define	QCN_MI_HIWAT		8192
110 #define	QCN_MI_LOWAT		128
111 
112 /* streams structures */
113 static struct module_info minfo = {
114 	QCN_MI_IDNUM,	/* mi_idnum		*/
115 	"qcn",		/* mi_idname		*/
116 	0,		/* mi_minpsz		*/
117 	INFPSZ,		/* mi_maxpsz		*/
118 	QCN_MI_HIWAT,	/* mi_hiwat		*/
119 	QCN_MI_LOWAT	/* mi_lowat		*/
120 };
121 
122 static struct qinit rinit = {
123 	putq,		/* qi_putp		*/
124 	qcn_rsrv,	/* qi_srvp		*/
125 	qcn_open,	/* qi_qopen		*/
126 	qcn_close,	/* qi_qclose		*/
127 	NULL,		/* qi_qadmin		*/
128 	&minfo,		/* qi_minfo		*/
129 	NULL		/* qi_mstat		*/
130 };
131 
132 static struct qinit winit = {
133 	qcn_wput,	/* qi_putp		*/
134 	qcn_wsrv,	/* qi_srvp		*/
135 	qcn_open,	/* qi_qopen		*/
136 	qcn_close,	/* qi_qclose		*/
137 	NULL,		/* qi_qadmin		*/
138 	&minfo,		/* qi_minfo		*/
139 	NULL		/* qi_mstat		*/
140 };
141 
142 static struct streamtab qcnstrinfo = {
143 	&rinit,
144 	&winit,
145 	NULL,
146 	NULL
147 };
148 
149 /* standard device driver structures */
150 static struct cb_ops qcn_cb_ops = {
151 	nulldev,		/* open()		*/
152 	nulldev,		/* close()		*/
153 	nodev,			/* strategy()		*/
154 	nodev,			/* print()		*/
155 	nodev,			/* dump()		*/
156 	nodev,			/* read()		*/
157 	nodev,			/* write()		*/
158 	nodev,			/* ioctl()		*/
159 	nodev,			/* devmap()		*/
160 	nodev,			/* mmap()		*/
161 	nodev,			/* segmap()		*/
162 	nochpoll,		/* poll()		*/
163 	ddi_prop_op,		/* prop_op()		*/
164 	&qcnstrinfo,		/* cb_str		*/
165 	D_NEW | D_MP		/* cb_flag		*/
166 };
167 
168 static struct dev_ops qcn_ops = {
169 	DEVO_REV,
170 	0,			/* refcnt		*/
171 	qcn_getinfo,		/* getinfo()		*/
172 	nulldev,		/* identify()		*/
173 	nulldev,		/* probe()		*/
174 	qcn_attach,		/* attach()		*/
175 	qcn_detach,		/* detach()		*/
176 	nodev,			/* reset()		*/
177 	&qcn_cb_ops,		/* cb_ops		*/
178 	(struct bus_ops *)NULL,	/* bus_ops		*/
179 	NULL			/* power()		*/
180 };
181 
182 static struct modldrv modldrv = {
183 	&mod_driverops,
184 	"sun4v console driver v%I%",
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 		qcn_poll_time.cyt_when = 0ull;
420 		qcn_poll_time.cyt_interval =
421 		    qcn_poll_interval * 1000ull * 1000ull;
422 		mutex_enter(&cpu_lock);
423 		qcn_tx_block_cycid = cyclic_add(&qcn_tx_block_cychandler,
424 		    &qcn_poll_time);
425 		mutex_exit(&cpu_lock);
426 
427 		qcn_state->qcn_tx_blocked = B_FALSE;
428 
429 		mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER,
430 		    (void *)(uintptr_t)(qcn_state->qcn_intr_pri));
431 	}
432 
433 	mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL);
434 
435 	/*
436 	 *  Enable  interrupts
437 	 */
438 	if (!qcn_state->qcn_polling) {
439 		qcn_intr_enable();
440 	}
441 #ifdef QCN_DEBUG
442 	prom_printf("qcn_attach(): qcn driver attached\n");
443 #endif
444 
445 	return (DDI_SUCCESS);
446 
447 }
448 
449 /* ARGSUSED */
450 static int
451 qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
452 {
453 
454 	if (cmd != DDI_DETACH)
455 		return (DDI_FAILURE);
456 
457 
458 #ifdef QCN_DEBUG
459 	prom_printf("qcn_detach(): QCN driver detached\n");
460 #endif
461 
462 #ifdef QCN_POLLING
463 	if (qcn_state->qcn_polling) {
464 		mutex_enter(&cpu_lock);
465 		if (qcn_poll_cycid != CYCLIC_NONE)
466 			cyclic_remove(qcn_poll_cycid);
467 		qcn_poll_cycid = CYCLIC_NONE;
468 		mutex_exit(&cpu_lock);
469 	}
470 #endif
471 
472 	if (!qcn_state->qcn_polling) {
473 		qcn_remove_intrs();
474 
475 		mutex_enter(&cpu_lock);
476 		if (qcn_tx_block_cycid != CYCLIC_NONE)
477 			cyclic_remove(qcn_tx_block_cycid);
478 		qcn_tx_block_cycid = CYCLIC_NONE;
479 		mutex_exit(&cpu_lock);
480 	}
481 	return (DDI_SUCCESS);
482 }
483 
484 /* ARGSUSED */
485 static int
486 qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
487 {
488 	int error = DDI_FAILURE;
489 	int instance = 0;
490 	switch (infocmd) {
491 	case DDI_INFO_DEVT2DEVINFO:
492 		if (qcn_state) {
493 #ifdef QCN_DEBUG
494 			prom_printf("qcn_getinfo(): devt2dip %lx\n", arg);
495 #endif
496 			*result = (void *)qcn_state->qcn_dip;
497 			error = DDI_SUCCESS;
498 		}
499 		break;
500 
501 	case DDI_INFO_DEVT2INSTANCE:
502 #ifdef QCN_DEBUG
503 		prom_printf("qcn_getinfo(): devt2instance %lx\n", arg);
504 #endif
505 		if (getminor((dev_t)arg) == 0) {
506 			*result = (void *)(uintptr_t)instance;
507 			error = DDI_SUCCESS;
508 		}
509 		break;
510 	}
511 
512 	return (error);
513 }
514 
515 /* streams open & close */
516 /* ARGSUSED */
517 static int
518 qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
519 {
520 	tty_common_t *tty;
521 	int unit = getminor(*devp);
522 
523 #ifdef QCN_DEBUG
524 	prom_printf("qcn_open(): minor %x\n", unit);
525 #endif
526 
527 	if (unit != 0)
528 		return (ENXIO);
529 
530 	/* stream already open */
531 	if (q->q_ptr != NULL)
532 		return (DDI_SUCCESS);
533 
534 	if (!qcn_state) {
535 		cmn_err(CE_WARN, "qcn_open: console was not configured by "
536 		    "autoconfig\n");
537 		return (ENXIO);
538 	}
539 
540 	mutex_enter(&qcn_state->qcn_lock);
541 	tty = &(qcn_state->qcn_tty);
542 
543 	tty->t_readq = q;
544 	tty->t_writeq = WR(q);
545 
546 	/* Link the RD and WR Q's */
547 	q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state;
548 	qcn_state->qcn_readq = RD(q);
549 	qcn_state->qcn_writeq = WR(q);
550 	qprocson(q);
551 
552 	mutex_exit(&qcn_state->qcn_lock);
553 
554 #ifdef QCN_DEBUG
555 	prom_printf("qcn_open: opened as dev %lx\n", *devp);
556 #endif
557 
558 	return (DDI_SUCCESS);
559 }
560 
561 /* ARGSUSED */
562 static int
563 qcn_close(queue_t *q, int flag, cred_t *credp)
564 {
565 
566 	ASSERT(qcn_state == q->q_ptr);
567 
568 	if (qcn_state->qcn_wbufcid != 0) {
569 		unbufcall(qcn_state->qcn_wbufcid);
570 	}
571 	ttycommon_close(&qcn_state->qcn_tty);
572 
573 	qprocsoff(q);
574 	q->q_ptr = WR(q)->q_ptr = NULL;
575 	qcn_state->qcn_readq = NULL;
576 	qcn_state->qcn_writeq = NULL;
577 
578 	return (DDI_SUCCESS);
579 }
580 
581 /*
582  * Put procedure for write queue.
583  * Respond to M_IOCTL, M_DATA and M_FLUSH messages here;
584  * It put's the data onto internal qcn_output_q.
585  */
586 static int
587 qcn_wput(queue_t *q, mblk_t *mp)
588 {
589 
590 #ifdef QCN_DEBUG
591 	struct iocblk *iocp;
592 	int i;
593 #endif
594 
595 	ASSERT(qcn_state == q->q_ptr);
596 
597 	if (!mp->b_datap) {
598 		cmn_err(CE_PANIC, "qcn_wput: null datap");
599 	}
600 
601 #ifdef QCN_DEBUG
602 	prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n",
603 		q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type);
604 #endif
605 
606 	mutex_enter(&qcn_state->qcn_lock);
607 
608 	switch (mp->b_datap->db_type) {
609 	case M_IOCTL:
610 	case M_CTL:
611 #ifdef QCN_DEBUG
612 		iocp = (struct iocblk *)mp->b_rptr;
613 		prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n",
614 		    iocp->ioc_cmd, TIOC);
615 #endif
616 		switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
617 		case TCSETSW:
618 		case TCSETSF:
619 		case TCSETAW:
620 		case TCSETAF:
621 		case TCSBRK:
622 			/*
623 			 * The change do not take effect until all
624 			 * output queued before them is drained.
625 			 * Put this message on the queue, so that
626 			 * "qcn_start" will see it when it's done
627 			 * with the output before it. Poke the start
628 			 * routine, just in case.
629 			 */
630 			(void) putq(q, mp);
631 			qcn_start();
632 			break;
633 		default:
634 			qcn_ioctl(q, mp);
635 		}
636 		break;
637 
638 	case M_FLUSH:
639 		if (*mp->b_rptr & FLUSHW) {
640 			flushq(q, FLUSHDATA);
641 			*mp->b_rptr &= ~FLUSHW;
642 		}
643 		if (*mp->b_rptr & FLUSHR) {
644 			flushq(RD(q), FLUSHDATA);
645 			qreply(q, mp);
646 		} else {
647 			freemsg(mp);
648 		}
649 		break;
650 
651 	case M_STOP:
652 		qcn_stopped = B_TRUE;
653 		freemsg(mp);
654 		break;
655 
656 	case M_START:
657 		qcn_stopped = B_FALSE;
658 		freemsg(mp);
659 		qenable(q);	/* Start up delayed messages */
660 		break;
661 
662 	case M_DATA:
663 		/*
664 		 * Queue the message up to be transmitted,
665 		 * and poke the start routine.
666 		 */
667 #ifdef QCN_DEBUG
668 		if (mp->b_rptr < mp->b_wptr) {
669 		prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n",
670 			q, mp, mp->b_rptr, mp->b_wptr);
671 		prom_printf("qcn_wput(): [");
672 		for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) {
673 			prom_printf("%c", *(mp->b_rptr+i));
674 		}
675 		prom_printf("]\n");
676 		}
677 #endif /* QCN_DEBUG */
678 		(void) putq(q, mp);
679 		qcn_start();
680 		break;
681 
682 	default:
683 		freemsg(mp);
684 	}
685 
686 	mutex_exit(&qcn_state->qcn_lock);
687 	return (0);
688 }
689 
690 /*
691  * Process an "ioctl" message sent down to us.
692  */
693 static void
694 qcn_ioctl(queue_t *q, mblk_t *mp)
695 {
696 	struct iocblk	*iocp;
697 	tty_common_t	*tty;
698 	mblk_t		*datamp;
699 	int		data_size;
700 	int		error = 0;
701 
702 #ifdef QCN_DEBUG
703 	prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp);
704 #endif
705 
706 	iocp = (struct iocblk *)mp->b_rptr;
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 	data_size = ttycommon_ioctl(tty, q, mp, &error);
714 	if (data_size != 0) {
715 		if (qcn_state->qcn_wbufcid)
716 			unbufcall(qcn_state->qcn_wbufcid);
717 		/* call qcn_reioctl() */
718 		qcn_state->qcn_wbufcid =
719 		    bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state);
720 		return;
721 	}
722 
723 	if (error < 0) {
724 		iocp = (struct iocblk *)mp->b_rptr;
725 		/*
726 		 * "ttycommon_ioctl" didn't do anything; we process it here.
727 		 */
728 		error = 0;
729 		switch (iocp->ioc_cmd) {
730 		case TCSBRK:
731 		case TIOCSBRK:
732 		case TIOCCBRK:
733 		case TIOCMSET:
734 		case TIOCMBIS:
735 		case TIOCMBIC:
736 			if (iocp->ioc_count != TRANSPARENT)
737 				qcn_ack(mp, NULL, 0);
738 			else
739 				mcopyin(mp, NULL, sizeof (int), NULL);
740 			break;
741 
742 		case TIOCMGET:
743 			datamp = allocb(sizeof (int), BPRI_MED);
744 			if (datamp == NULL) {
745 				error = EAGAIN;
746 				break;
747 			}
748 
749 			*(int *)datamp->b_rptr = 0;
750 
751 			if (iocp->ioc_count != TRANSPARENT)
752 				qcn_ack(mp, datamp, sizeof (int));
753 			else
754 				mcopyout(mp, NULL, sizeof (int), NULL, datamp);
755 			break;
756 
757 		default:
758 			error = EINVAL;
759 			break;
760 		}
761 	}
762 	if (error != 0) {
763 		iocp->ioc_count = 0;
764 		iocp->ioc_error = error;
765 		mp->b_datap->db_type = M_IOCNAK;
766 	}
767 	qreply(q, mp);
768 }
769 
770 static void
771 qcn_reioctl(void *unit)
772 {
773 	queue_t		*q;
774 	mblk_t		*mp;
775 	qcn_t		*qcnp = (qcn_t *)unit;
776 
777 	if (!qcnp->qcn_wbufcid)
778 		return;
779 
780 	qcnp->qcn_wbufcid = 0;
781 	if ((q = qcnp->qcn_tty.t_writeq) == NULL)
782 		return;
783 
784 	if ((mp = qcnp->qcn_tty.t_iocpending) == NULL)
785 		return;
786 
787 	qcnp->qcn_tty.t_iocpending = NULL;
788 	qcn_ioctl(q, mp);
789 }
790 
791 static void
792 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size)
793 {
794 	struct iocblk  *iocp = (struct iocblk *)mp->b_rptr;
795 
796 	mp->b_datap->db_type = M_IOCACK;
797 	iocp->ioc_count = size;
798 	iocp->ioc_error = 0;
799 	iocp->ioc_rval = 0;
800 	if (mp->b_cont != NULL)
801 		freeb(mp->b_cont);
802 	if (dp != NULL) {
803 		mp->b_cont = dp;
804 		dp->b_wptr += size;
805 	} else
806 		mp->b_cont = NULL;
807 }
808 
809 static void
810 qcn_start(void)
811 {
812 
813 	queue_t *q;
814 	mblk_t *mp;
815 	int rv;
816 
817 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
818 
819 	/*
820 	 * read stream queue and remove data from the queue and
821 	 * transmit them if possible
822 	 */
823 	q = qcn_state->qcn_writeq;
824 	ASSERT(q != NULL);
825 	while (mp = getq(q)) {
826 		if (mp->b_datap->db_type == M_IOCTL) {
827 			/*
828 			 * These are those IOCTLs queued up
829 			 * do it now
830 			 */
831 			qcn_ioctl(q, mp);
832 			continue;
833 		}
834 		/*
835 		 * M_DATA
836 		 */
837 		rv = qcn_state->cons_transmit(q, mp);
838 		if (rv == EBUSY || rv == EAGAIN)
839 			return;
840 	}
841 }
842 
843 static int
844 qcn_transmit_write(queue_t *q, mblk_t *mp)
845 {
846 	mblk_t		*bp;
847 	size_t		len;
848 	uint64_t	i;
849 	uint64_t	retval = 0;
850 
851 #ifdef QCN_DEBUG
852 	prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp);
853 #endif
854 
855 	while (mp) {
856 		bp = mp;
857 		len = bp->b_wptr - bp->b_rptr;
858 		/*
859 		 * Use the console write call to send a block of characters to
860 		 * the console.
861 		 */
862 		i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len;
863 		bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i);
864 		retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i);
865 
866 		if (retval == H_EOK) {
867 			len -= i;
868 			bp->b_rptr += i;
869 			/*
870 			 * if we have finished with this buf, free
871 			 * and get the next buf if present.
872 			 */
873 			if (len == 0) {
874 				mp = bp->b_cont;
875 				freeb(bp);
876 			}
877 		} else {
878 			(void) putbq(q, mp);
879 
880 			switch (retval) {
881 
882 			case H_EWOULDBLOCK :
883 				/*
884 				 * hypervisor cannot process the request -
885 				 * channel busy.  Try again later.
886 				 */
887 				qcn_state->qcn_tx_blocked = B_TRUE;
888 				return (EAGAIN);
889 
890 			case H_EIO :
891 				return (EIO);
892 			default :
893 				return (ENXIO);
894 			}
895 		}
896 	}
897 	return (0);
898 }
899 
900 static int
901 qcn_transmit_putchr(queue_t *q, mblk_t *mp)
902 {
903 	caddr_t		buf;
904 	mblk_t		*bp;
905 	size_t		len;
906 	uint64_t	i;
907 
908 #ifdef QCN_DEBUG
909 	prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp);
910 #endif
911 	while (mp) {
912 		bp = mp;
913 		len = bp->b_wptr - bp->b_rptr;
914 		buf = (caddr_t)bp->b_rptr;
915 		for (i = 0; i < len; i++) {
916 			if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK) {
917 				qcn_state->qcn_tx_blocked = B_TRUE;
918 				break;
919 			}
920 		}
921 		if (i != len) {
922 			bp->b_rptr += i;
923 			(void) putbq(q, mp);
924 			return (EAGAIN);
925 		}
926 		mp = bp->b_cont;
927 		freeb(bp);
928 	}
929 	return (0);
930 }
931 
932 /*
933  * called when SC first establishes console connection
934  * drop all the data on the output queue
935  */
936 static void
937 qcn_flush(void)
938 {
939 	queue_t *q;
940 	mblk_t *mp;
941 
942 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
943 
944 	q = qcn_state->qcn_writeq;
945 
946 	prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n",
947 	    gethrestime_sec());
948 	while (mp = getq(q))
949 		freemsg(mp);
950 }
951 
952 static void
953 qcn_trigger_softint(void)
954 {
955 	/*
956 	 * if we are not currently servicing a software interrupt
957 	 * (qcn_soft_pend == 0), trigger the service routine to run.
958 	 */
959 	if (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_DO) ==
960 				QCN_SP_IDL) {
961 		(void) ddi_intr_trigger_softint(
962 			    qcn_state->qcn_softint_hdl, NULL);
963 	}
964 }
965 
966 /*ARGSUSED*/
967 static uint_t
968 qcn_soft_intr(caddr_t arg1, caddr_t arg2)
969 {
970 	mblk_t *mp;
971 	int	cc;
972 	int	overflow_check;
973 
974 	do {
975 		(void) atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IP);
976 		mutex_enter(&qcn_state->qcn_hi_lock);
977 		if ((cc = RING_CNT(qcn_state)) <= 0) {
978 			mutex_exit(&qcn_state->qcn_hi_lock);
979 			goto out;
980 		}
981 
982 		if ((mp = allocb(cc, BPRI_MED)) == NULL) {
983 			qcn_input_dropped += cc;
984 			mutex_exit(&qcn_state->qcn_hi_lock);
985 			cmn_err(CE_WARN, "qcn_intr: allocb"
986 			    "failed (console input dropped)");
987 			goto out;
988 		}
989 
990 		do {
991 			/* put console input onto stream */
992 			*(char *)mp->b_wptr++ = RING_GET(qcn_state);
993 		} while (--cc);
994 
995 		if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) {
996 			qcn_state->qcn_rbuf_overflow = 0;
997 		}
998 		mutex_exit(&qcn_state->qcn_hi_lock);
999 
1000 		if (overflow_check) {
1001 			cmn_err(CE_WARN, "qcn: Ring buffer overflow\n");
1002 		}
1003 
1004 		if (qcn_state->qcn_readq) {
1005 			putnext(qcn_state->qcn_readq, mp);
1006 		}
1007 out:
1008 		if (qcn_state->qcn_hangup) {
1009 			(void) putctl(qcn_state->qcn_readq, M_HANGUP);
1010 			if (qcn_state->qcn_writeq != NULL) {
1011 				flushq(qcn_state->qcn_writeq, FLUSHDATA);
1012 				qcn_state->qcn_tx_blocked = B_FALSE;
1013 			}
1014 			qcn_state->qcn_hangup = 0;
1015 		}
1016 		/*
1017 		 * now loop if another interrupt came in (qcn_trigger_softint
1018 		 * called) while we were processing the loop
1019 		 */
1020 	} while (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IDL) ==
1021 								QCN_SP_DO);
1022 	return (DDI_INTR_CLAIMED);
1023 }
1024 
1025 /*ARGSUSED*/
1026 static uint_t
1027 qcn_hi_intr(caddr_t arg)
1028 {
1029 	mutex_enter(&qcn_state->qcn_hi_lock);
1030 
1031 	qcn_state->cons_receive();
1032 
1033 	mutex_exit(&qcn_state->qcn_hi_lock);
1034 	qcn_trigger_softint();
1035 
1036 	return (DDI_INTR_CLAIMED);
1037 }
1038 
1039 static void
1040 qcn_receive_read(void)
1041 {
1042 	int64_t rv;
1043 	uint8_t *bufp;
1044 	int64_t	retcount = 0;
1045 	int	i;
1046 
1047 	do {
1048 		/*
1049 		 * Maximize available buffer size
1050 		 */
1051 		if (RING_CNT(qcn_state) <= 0) {
1052 			RING_INIT(qcn_state);
1053 		}
1054 		rv = hv_cnread(qcn_state->cons_read_buf_ra +
1055 				RING_POFF(qcn_state),
1056 				RING_LEFT(qcn_state),
1057 				&retcount);
1058 		bufp = RING_ADDR(qcn_state);
1059 		if (rv == H_EOK) {
1060 			/*
1061 			 * if the alternate break sequence is enabled, test
1062 			 * the buffer for the sequence and if it is there,
1063 			 * enter the debugger.
1064 			 */
1065 			if (abort_enable == KIOCABORTALTERNATE) {
1066 				for (i = 0; i < retcount; i++) {
1067 					if (abort_charseq_recognize(*bufp++)) {
1068 						abort_sequence_enter(
1069 								(char *)NULL);
1070 					}
1071 				}
1072 			}
1073 
1074 			/* put console input onto stream */
1075 			if (retcount > 0) {
1076 				/*
1077 				 * the characters are already in the ring,
1078 				 * just update the pointer so the characters
1079 				 * can be retrieved.
1080 				 */
1081 				RING_UPD(qcn_state, retcount);
1082 			}
1083 		} else {
1084 			switch (rv) {
1085 
1086 			case H_EWOULDBLOCK :
1087 				/*
1088 				 * hypervisor cannot handle the request.
1089 				 * Try again later.
1090 				 */
1091 				break;
1092 
1093 
1094 			case H_BREAK :
1095 				/*
1096 				 * on break, unless alternate break sequence is
1097 				 * enabled, enter the debugger
1098 				 */
1099 				if (abort_enable != KIOCABORTALTERNATE)
1100 					abort_sequence_enter((char *)NULL);
1101 				break;
1102 
1103 			case H_HUP :
1104 				qcn_state->qcn_hangup = 1;
1105 				break;
1106 
1107 			default :
1108 				break;
1109 			}
1110 		}
1111 	} while (rv == H_EOK);
1112 }
1113 
1114 static void
1115 qcn_receive_getchr(void)
1116 {
1117 	int64_t rv;
1118 	uint8_t	buf;
1119 
1120 	do {
1121 		rv = hv_cngetchar(&buf);
1122 		if (rv == H_EOK) {
1123 			if (abort_enable == KIOCABORTALTERNATE) {
1124 				if (abort_charseq_recognize(buf)) {
1125 					abort_sequence_enter((char *)NULL);
1126 				}
1127 			}
1128 
1129 			/* put console input onto stream */
1130 			if (RING_POK(qcn_state, 1)) {
1131 				RING_PUT(qcn_state, buf);
1132 			} else {
1133 				qcn_state->qcn_rbuf_overflow++;
1134 			}
1135 		} else {
1136 			if (rv == H_BREAK) {
1137 				if (abort_enable != KIOCABORTALTERNATE)
1138 					abort_sequence_enter((char *)NULL);
1139 			}
1140 
1141 			if (rv == H_HUP)  {
1142 				qcn_state->qcn_hangup = 1;
1143 			}
1144 			return;
1145 		}
1146 	} while (rv == H_EOK);
1147 }
1148 
1149 #ifdef QCN_POLLING
1150 /*ARGSUSED*/
1151 static void
1152 qcn_poll_handler(void *unused)
1153 {
1154 	mblk_t *mp;
1155 	int64_t rv;
1156 	uint8_t buf;
1157 	int qcn_writeq_flush = 0;
1158 
1159 	/* LINTED: E_CONSTANT_CONDITION */
1160 	while (1) {
1161 		rv = hv_cngetchar(&buf);
1162 		if (rv == H_BREAK) {
1163 			if (abort_enable != KIOCABORTALTERNATE)
1164 				abort_sequence_enter((char *)NULL);
1165 		}
1166 
1167 		if (rv == H_HUP)  {
1168 			if (qcn_state->qcn_readq) {
1169 				(void) putctl(qcn_state->qcn_readq, M_HANGUP);
1170 				qcn_writeq_flush = 1;
1171 			}
1172 			goto out;
1173 		}
1174 
1175 		if (rv != H_EOK)
1176 			goto out;
1177 
1178 		if (abort_enable == KIOCABORTALTERNATE) {
1179 			if (abort_charseq_recognize(buf)) {
1180 				abort_sequence_enter((char *)NULL);
1181 			}
1182 		}
1183 
1184 		/* put console input onto stream */
1185 		if (qcn_state->qcn_readq) {
1186 			if ((mp = allocb(1, BPRI_MED)) == NULL) {
1187 				qcn_input_dropped++;
1188 				cmn_err(CE_WARN, "qcn_intr: allocb"
1189 				    "failed (console input dropped)");
1190 				return;
1191 			}
1192 			*(char *)mp->b_wptr++ = buf;
1193 			putnext(qcn_state->qcn_readq, mp);
1194 		}
1195 	}
1196 out:
1197 /*
1198  * If there are pending transmits because hypervisor
1199  * returned EWOULDBLOCK poke start now.
1200  */
1201 
1202 	mutex_enter(&qcn_state->qcn_lock);
1203 	if (qcn_state->qcn_writeq != NULL) {
1204 		if (qcn_writeq_flush) {
1205 			flushq(qcn_state->qcn_writeq, FLUSHDATA);
1206 		} else {
1207 			qcn_start();
1208 		}
1209 	}
1210 	mutex_exit(&qcn_state->qcn_lock);
1211 }
1212 #endif
1213 
1214 /*ARGSUSED*/
1215 static void
1216 qcn_tx_block_handler(void *unused)
1217 {
1218 	mutex_enter(&qcn_state->qcn_lock);
1219 	/*
1220 	 * If the hypervisor returned EWOULDBLOCK on the transmit,
1221 	 * re-transmit now.
1222 	 */
1223 	if (qcn_state->qcn_tx_blocked && qcn_state->qcn_writeq != NULL) {
1224 		qcn_state->qcn_tx_blocked = B_FALSE;
1225 		qcn_start();
1226 	}
1227 	mutex_exit(&qcn_state->qcn_lock);
1228 }
1229 /*
1230  * Check for abort character sequence, copied from zs_async.c
1231  */
1232 #define	CNTRL(c) ((c)&037)
1233 
1234 static boolean_t
1235 abort_charseq_recognize(uchar_t ch)
1236 {
1237 	static int state = 0;
1238 	static char sequence[] = { '\r', '~', CNTRL('b') };
1239 
1240 	if (ch == sequence[state]) {
1241 		if (++state >= sizeof (sequence)) {
1242 			state = 0;
1243 			return (B_TRUE);
1244 		}
1245 	} else {
1246 		state = (ch == sequence[0]) ? 1 : 0;
1247 	}
1248 	return (B_FALSE);
1249 }
1250 
1251 
1252 static int
1253 qcn_rsrv(queue_t *q)
1254 {
1255 	mblk_t	*mp;
1256 
1257 	if (qcn_stopped == B_TRUE)
1258 		return (0);
1259 
1260 	mutex_enter(&qcn_state->qcn_lock);
1261 
1262 	while ((mp = getq(q)) != NULL) {
1263 		if (canputnext(q))
1264 			putnext(q, mp);
1265 		else if (mp->b_datap->db_type >= QPCTL)
1266 			(void) putbq(q, mp);
1267 	}
1268 
1269 	mutex_exit(&qcn_state->qcn_lock);
1270 
1271 	return (0);
1272 }
1273 
1274 /* ARGSUSED */
1275 static int
1276 qcn_wsrv(queue_t *q)
1277 {
1278 	if (qcn_stopped == B_TRUE)
1279 		return (0);
1280 
1281 	mutex_enter(&qcn_state->qcn_lock);
1282 
1283 	if (qcn_state->qcn_writeq != NULL)
1284 		qcn_start();
1285 
1286 	mutex_exit(&qcn_state->qcn_lock);
1287 
1288 	return (0);
1289 }
1290