xref: /illumos-gate/usr/src/uts/sun4v/io/qcn.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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