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