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 */
55 static int qcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
56 static int qcn_attach(dev_info_t *, ddi_attach_cmd_t);
57 static int qcn_detach(dev_info_t *, ddi_detach_cmd_t);
58 static int qcn_open(queue_t *, dev_t *, int, int, cred_t *);
59 static int qcn_close(queue_t *, int, cred_t *);
60 static int qcn_wput(queue_t *, mblk_t *);
61 static int qcn_wsrv(queue_t *);
62 static int qcn_rsrv(queue_t *);
63
64 /* other internal qcn routines */
65 static void qcn_ioctl(queue_t *, mblk_t *);
66 static void qcn_reioctl(void *);
67 static void qcn_ack(mblk_t *, mblk_t *, uint_t);
68 static void qcn_start(void);
69 static int qcn_transmit_write(queue_t *, mblk_t *);
70 static int qcn_transmit_putchr(queue_t *, mblk_t *);
71 static void qcn_receive_read(void);
72 static void qcn_receive_getchr(void);
73 static void qcn_flush(void);
74 static uint_t qcn_hi_intr(caddr_t arg);
75 static uint_t qcn_soft_intr(caddr_t arg1, caddr_t arg2);
76
77 /* functions required for polled io */
78 static boolean_t qcn_polledio_ischar(cons_polledio_arg_t arg);
79 static int qcn_polledio_getchar(cons_polledio_arg_t arg);
80 static void qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c);
81 static void qcn_polledio_enter(cons_polledio_arg_t arg);
82 static void qcn_polledio_exit(cons_polledio_arg_t arg);
83
84
85 static boolean_t abort_charseq_recognize(uchar_t);
86
87 static qcn_t *qcn_state;
88 static uchar_t qcn_stopped = B_FALSE;
89 static int qcn_timeout_period = 20; /* time out in seconds */
90 size_t qcn_input_dropped; /* dropped input character counter */
91
92 #ifdef QCN_POLLING
93 static void qcn_poll_handler(void *unused);
94 static cyc_time_t qcn_poll_time;
95 static cyc_handler_t qcn_poll_cychandler = {
96 qcn_poll_handler,
97 NULL,
98 CY_LOW_LEVEL /* XXX need softint to make this high */
99 };
100 static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE;
101 static uint64_t qcn_poll_interval = 5; /* milli sec */
102 static uint64_t sb_interval = 0;
103 uint_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 */
111 static 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
120 static 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
130 static 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
140 static struct streamtab qcnstrinfo = {
141 &rinit,
142 &winit,
143 NULL,
144 NULL
145 };
146
147 /* standard device driver structures */
148 static 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
166 static 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
181 static struct modldrv modldrv = {
182 &mod_driverops,
183 "sun4v console driver",
184 &qcn_ops
185 };
186
187 static struct modlinkage modlinkage = {
188 MODREV_1,
189 (void*)&modldrv,
190 NULL
191 };
192
193 /* driver configuration routines */
194 int
_init(void)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
236 int
_fini(void)237 _fini(void)
238 {
239 /* can't remove console driver */
240 return (EBUSY);
241 }
242
243 int
_info(struct modinfo * modinfop)244 _info(struct modinfo *modinfop)
245 {
246 return (mod_info(&modlinkage, modinfop));
247 }
248
249 static int
qcn_add_intrs(void)250 qcn_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
323 static void
qcn_remove_intrs(void)324 qcn_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
335 static void
qcn_intr_enable(void)336 qcn_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 */
349 static int
qcn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)350 qcn_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 */
451 static int
qcn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)452 qcn_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 */
480 static int
qcn_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)481 qcn_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 */
512 static int
qcn_open(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)513 qcn_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 */
557 static int
qcn_close(queue_t * q,int flag,cred_t * credp)558 qcn_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 */
581 static int
qcn_wput(queue_t * q,mblk_t * mp)582 qcn_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 */
691 static void
qcn_ioctl(queue_t * q,mblk_t * mp)692 qcn_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
798 static void
qcn_reioctl(void * unit)799 qcn_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
819 static void
qcn_ack(mblk_t * mp,mblk_t * dp,uint_t size)820 qcn_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
837 static void
qcn_start(void)838 qcn_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
873 static int
qcn_transmit_write(queue_t * q,mblk_t * mp)874 qcn_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
929 static int
qcn_transmit_putchr(queue_t * q,mblk_t * mp)930 qcn_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 */
963 static void
qcn_flush(void)964 qcn_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
979 static void
qcn_trigger_softint(void)980 qcn_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*/
994 static uint_t
qcn_soft_intr(caddr_t arg1,caddr_t arg2)995 qcn_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 }
1037 out:
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*/
1064 static uint_t
qcn_hi_intr(caddr_t arg)1065 qcn_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
1077 static void
qcn_receive_read(void)1078 qcn_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
1151 static void
qcn_receive_getchr(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 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*/
1188 static void
qcn_poll_handler(void * unused)1189 qcn_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 }
1233 out:
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
1256 static boolean_t
abort_charseq_recognize(uchar_t ch)1257 abort_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
1274 static int
qcn_rsrv(queue_t * q)1275 qcn_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 */
1297 static int
qcn_wsrv(queue_t * q)1298 qcn_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
1313 static boolean_t
qcn_polledio_ischar(cons_polledio_arg_t arg)1314 qcn_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
1326 static int
qcn_polledio_getchar(cons_polledio_arg_t arg)1327 qcn_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
1339 static void
qcn_polledio_putchar(cons_polledio_arg_t arg,uchar_t c)1340 qcn_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
1349 static void
qcn_polledio_enter(cons_polledio_arg_t arg)1350 qcn_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 */
1358 static void
qcn_polledio_exit(cons_polledio_arg_t arg)1359 qcn_polledio_exit(cons_polledio_arg_t arg)
1360 {
1361 }
1362