1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * sun4v console driver 31 */ 32 33 #include <sys/errno.h> 34 #include <sys/stat.h> 35 #include <sys/kmem.h> 36 #include <sys/conf.h> 37 #include <sys/termios.h> 38 #include <sys/modctl.h> 39 #include <sys/kbio.h> 40 #include <sys/stropts.h> 41 #include <sys/stream.h> 42 #include <sys/strsun.h> 43 #include <sys/sysmacros.h> 44 #include <sys/promif.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/cyclic.h> 48 #include <sys/intr.h> 49 #include <sys/spl.h> 50 #include <sys/qcn.h> 51 #include <sys/hypervisor_api.h> 52 53 /* dev_ops and cb_ops for device driver */ 54 static int qcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 55 static int qcn_attach(dev_info_t *, ddi_attach_cmd_t); 56 static int qcn_detach(dev_info_t *, ddi_detach_cmd_t); 57 static int qcn_open(queue_t *, dev_t *, int, int, cred_t *); 58 static int qcn_close(queue_t *, int, cred_t *); 59 static int qcn_wput(queue_t *, mblk_t *); 60 static int qcn_wsrv(queue_t *); 61 static int qcn_rsrv(queue_t *); 62 63 /* other internal qcn routines */ 64 static void qcn_ioctl(queue_t *, mblk_t *); 65 static void qcn_reioctl(void *); 66 static void qcn_ack(mblk_t *, mblk_t *, uint_t); 67 static void qcn_start(void); 68 static int qcn_transmit(queue_t *, mblk_t *); 69 static void qcn_flush(void); 70 static uint_t qcn_hi_intr(caddr_t arg); 71 static uint_t qcn_soft_intr(caddr_t arg1, caddr_t arg2); 72 73 static boolean_t abort_charseq_recognize(uchar_t); 74 75 static qcn_t *qcn_state; 76 static uchar_t qcn_stopped = B_FALSE; 77 static int qcn_timeout_period = 20; /* time out in seconds */ 78 size_t qcn_input_dropped; /* dropped input character counter */ 79 80 #ifdef QCN_POLLING 81 static void qcn_poll_handler(void *unused); 82 static cyc_time_t qcn_poll_time; 83 static cyc_handler_t qcn_poll_cychandler = { 84 qcn_poll_handler, 85 NULL, 86 CY_LOW_LEVEL /* XXX need softint to make this high */ 87 }; 88 static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE; 89 static uint64_t qcn_poll_interval = 5; /* milli sec */ 90 static uint64_t sb_interval = 0; 91 uint_t qcn_force_polling = 0; 92 #endif 93 94 #define QCN_MI_IDNUM 0xABCE 95 #define QCN_MI_HIWAT 8192 96 #define QCN_MI_LOWAT 128 97 98 /* streams structures */ 99 static struct module_info minfo = { 100 QCN_MI_IDNUM, /* mi_idnum */ 101 "qcn", /* mi_idname */ 102 0, /* mi_minpsz */ 103 INFPSZ, /* mi_maxpsz */ 104 QCN_MI_HIWAT, /* mi_hiwat */ 105 QCN_MI_LOWAT /* mi_lowat */ 106 }; 107 108 static struct qinit rinit = { 109 putq, /* qi_putp */ 110 qcn_rsrv, /* qi_srvp */ 111 qcn_open, /* qi_qopen */ 112 qcn_close, /* qi_qclose */ 113 NULL, /* qi_qadmin */ 114 &minfo, /* qi_minfo */ 115 NULL /* qi_mstat */ 116 }; 117 118 static struct qinit winit = { 119 qcn_wput, /* qi_putp */ 120 qcn_wsrv, /* qi_srvp */ 121 qcn_open, /* qi_qopen */ 122 qcn_close, /* qi_qclose */ 123 NULL, /* qi_qadmin */ 124 &minfo, /* qi_minfo */ 125 NULL /* qi_mstat */ 126 }; 127 128 static struct streamtab qcnstrinfo = { 129 &rinit, 130 &winit, 131 NULL, 132 NULL 133 }; 134 135 /* standard device driver structures */ 136 static struct cb_ops qcn_cb_ops = { 137 nulldev, /* open() */ 138 nulldev, /* close() */ 139 nodev, /* strategy() */ 140 nodev, /* print() */ 141 nodev, /* dump() */ 142 nodev, /* read() */ 143 nodev, /* write() */ 144 nodev, /* ioctl() */ 145 nodev, /* devmap() */ 146 nodev, /* mmap() */ 147 nodev, /* segmap() */ 148 nochpoll, /* poll() */ 149 ddi_prop_op, /* prop_op() */ 150 &qcnstrinfo, /* cb_str */ 151 D_NEW | D_MP /* cb_flag */ 152 }; 153 154 static struct dev_ops qcn_ops = { 155 DEVO_REV, 156 0, /* refcnt */ 157 qcn_getinfo, /* getinfo() */ 158 nulldev, /* identify() */ 159 nulldev, /* probe() */ 160 qcn_attach, /* attach() */ 161 qcn_detach, /* detach() */ 162 nodev, /* reset() */ 163 &qcn_cb_ops, /* cb_ops */ 164 (struct bus_ops *)NULL, /* bus_ops */ 165 NULL /* power() */ 166 }; 167 168 static struct modldrv modldrv = { 169 &mod_driverops, 170 "sun4v console driver v%I%", 171 &qcn_ops 172 }; 173 174 static struct modlinkage modlinkage = { 175 MODREV_1, 176 (void*)&modldrv, 177 NULL 178 }; 179 180 181 /* driver configuration routines */ 182 int 183 _init(void) 184 { 185 int error; 186 187 qcn_state = kmem_zalloc(sizeof (qcn_t), KM_SLEEP); 188 189 error = mod_install(&modlinkage); 190 if (error != 0) 191 kmem_free(qcn_state, sizeof (qcn_t)); 192 193 return (error); 194 } 195 196 int 197 _fini(void) 198 { 199 /* can't remove console driver */ 200 return (EBUSY); 201 } 202 203 int 204 _info(struct modinfo *modinfop) 205 { 206 return (mod_info(&modlinkage, modinfop)); 207 } 208 209 static int 210 qcn_add_intrs(void) 211 { 212 dev_info_t *devinfo = qcn_state->qcn_dip; 213 int actual, count = 0; 214 int x, y, rc, inum = 0; 215 216 217 /* get number of interrupts */ 218 rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count); 219 if ((rc != DDI_SUCCESS) || (count == 0)) { 220 return (DDI_FAILURE); 221 } 222 223 /* Allocate an array of interrupt handles */ 224 qcn_state->qcn_intr_size = count * sizeof (ddi_intr_handle_t); 225 qcn_state->qcn_htable = kmem_zalloc(qcn_state->qcn_intr_size, KM_SLEEP); 226 227 /* call ddi_intr_alloc() */ 228 rc = ddi_intr_alloc(devinfo, qcn_state->qcn_htable, 229 DDI_INTR_TYPE_FIXED, inum, count, &actual, 230 DDI_INTR_ALLOC_STRICT); 231 232 if ((rc != DDI_SUCCESS) || (actual == 0)) { 233 kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 234 return (DDI_FAILURE); 235 } 236 237 if (actual < count) { 238 for (x = 0; x < actual; x++) { 239 (void) ddi_intr_free(qcn_state->qcn_htable[x]); 240 } 241 242 kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 243 return (DDI_FAILURE); 244 } 245 246 qcn_state->qcn_intr_cnt = actual; 247 248 /* Get intr priority */ 249 if (ddi_intr_get_pri(qcn_state->qcn_htable[0], 250 &qcn_state->qcn_intr_pri) != DDI_SUCCESS) { 251 for (x = 0; x < actual; x++) { 252 (void) ddi_intr_free(qcn_state->qcn_htable[x]); 253 } 254 255 kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 256 return (DDI_FAILURE); 257 } 258 259 /* Call ddi_intr_add_handler() */ 260 for (x = 0; x < actual; x++) { 261 if (ddi_intr_add_handler(qcn_state->qcn_htable[x], 262 (ddi_intr_handler_t *)qcn_hi_intr, 263 (caddr_t)qcn_state, NULL) != DDI_SUCCESS) { 264 265 for (y = 0; y < x; y++) { 266 (void) ddi_intr_remove_handler( 267 qcn_state->qcn_htable[y]); 268 } 269 270 for (y = 0; y < actual; y++) { 271 (void) ddi_intr_free(qcn_state->qcn_htable[y]); 272 } 273 274 kmem_free(qcn_state->qcn_htable, 275 qcn_state->qcn_intr_size); 276 return (DDI_FAILURE); 277 } 278 } 279 280 return (DDI_SUCCESS); 281 } 282 283 static void 284 qcn_remove_intrs(void) 285 { 286 int x; 287 for (x = 0; x < qcn_state->qcn_intr_cnt; x++) { 288 (void) ddi_intr_disable(qcn_state->qcn_htable[x]); 289 (void) ddi_intr_remove_handler(qcn_state->qcn_htable[x]); 290 (void) ddi_intr_free(qcn_state->qcn_htable[x]); 291 } 292 kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 293 } 294 295 static void 296 qcn_intr_enable(void) 297 { 298 int x; 299 300 for (x = 0; x < qcn_state->qcn_intr_cnt; x++) { 301 (void) ddi_intr_enable(qcn_state->qcn_htable[x]); 302 } 303 } 304 305 /* 306 * qcn_attach is called at startup time. 307 * There is only once instance of this driver. 308 */ 309 static int 310 qcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 311 { 312 extern int ddi_create_internal_pathname(dev_info_t *, char *, 313 int, minor_t); 314 uint_t soft_prip; 315 316 #ifdef QCN_POLLING 317 char *binding_name; 318 #endif 319 if (cmd != DDI_ATTACH) 320 return (DDI_FAILURE); 321 322 if (ddi_create_internal_pathname(dip, "qcn", 323 S_IFCHR, 0) != DDI_SUCCESS) 324 return (DDI_FAILURE); 325 326 qcn_state->qcn_soft_pend = 0; 327 qcn_state->qcn_hangup = 0; 328 qcn_state->qcn_rbuf_overflow = 0; 329 330 /* prepare some data structures in soft state */ 331 332 qcn_state->qcn_dip = dip; 333 334 qcn_state->qcn_polling = 0; 335 336 #ifdef QCN_POLLING 337 /* 338 * This test is for the sole purposes of allowing 339 * the console to work on older firmware releases. 340 */ 341 binding_name = ddi_binding_name(qcn_state->qcn_dip); 342 if ((strcmp(binding_name, "qcn") == 0) || 343 (qcn_force_polling)) 344 qcn_state->qcn_polling = 1; 345 346 if (qcn_state->qcn_polling) { 347 qcn_poll_time.cyt_when = 0ull; 348 qcn_poll_time.cyt_interval = 349 qcn_poll_interval * 1000ull * 1000ull; 350 mutex_enter(&cpu_lock); 351 qcn_poll_cycid = cyclic_add(&qcn_poll_cychandler, 352 &qcn_poll_time); 353 mutex_exit(&cpu_lock); 354 } 355 #endif 356 357 if (!qcn_state->qcn_polling) { 358 if (qcn_add_intrs() != DDI_SUCCESS) { 359 cmn_err(CE_WARN, "qcn_attach: add_intr failed\n"); 360 return (DDI_FAILURE); 361 } 362 if (ddi_intr_add_softint(dip, &qcn_state->qcn_softint_hdl, 363 DDI_INTR_SOFTPRI_MAX, qcn_soft_intr, 364 (caddr_t)qcn_state) != DDI_SUCCESS) { 365 cmn_err(CE_WARN, "qcn_attach: add_soft_intr failed\n"); 366 qcn_remove_intrs(); 367 return (DDI_FAILURE); 368 } 369 if (ddi_intr_get_softint_pri(qcn_state->qcn_softint_hdl, 370 &soft_prip) != DDI_SUCCESS) { 371 cmn_err(CE_WARN, "qcn_attach: softint_pri failed\n"); 372 (void) ddi_intr_remove_softint( 373 qcn_state->qcn_softint_hdl); 374 qcn_remove_intrs(); 375 return (DDI_FAILURE); 376 } 377 qcn_state->qcn_soft_pri = 378 (ddi_iblock_cookie_t)(uint64_t)soft_prip; 379 380 mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER, 381 (void *)(uintptr_t)(qcn_state->qcn_intr_pri)); 382 mutex_init(&qcn_state->qcn_softlock, NULL, MUTEX_DRIVER, 383 (void *)(qcn_state->qcn_soft_pri)); 384 } 385 386 mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL); 387 388 /* 389 * Enable interrupts 390 */ 391 if (!qcn_state->qcn_polling) { 392 qcn_intr_enable(); 393 } 394 #ifdef QCN_DEBUG 395 prom_printf("qcn_attach(): qcn driver attached\n"); 396 #endif 397 398 return (DDI_SUCCESS); 399 400 } 401 402 /* ARGSUSED */ 403 static int 404 qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 405 { 406 407 if (cmd != DDI_DETACH) 408 return (DDI_FAILURE); 409 410 411 #ifdef QCN_DEBUG 412 prom_printf("qcn_detach(): QCN driver detached\n"); 413 #endif 414 415 #ifdef QCN_POLLING 416 if (qcn_state->qcn_polling) { 417 mutex_enter(&cpu_lock); 418 if (qcn_poll_cycid != CYCLIC_NONE) 419 cyclic_remove(qcn_poll_cycid); 420 qcn_poll_cycid = CYCLIC_NONE; 421 mutex_exit(&cpu_lock); 422 } 423 #endif 424 425 if (!qcn_state->qcn_polling) 426 qcn_remove_intrs(); 427 428 return (DDI_SUCCESS); 429 } 430 431 /* ARGSUSED */ 432 static int 433 qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 434 { 435 int error = DDI_FAILURE; 436 int instance = 0; 437 switch (infocmd) { 438 case DDI_INFO_DEVT2DEVINFO: 439 if (qcn_state) { 440 #ifdef QCN_DEBUG 441 prom_printf("qcn_getinfo(): devt2dip %lx\n", arg); 442 #endif 443 *result = (void *)qcn_state->qcn_dip; 444 error = DDI_SUCCESS; 445 } 446 break; 447 448 case DDI_INFO_DEVT2INSTANCE: 449 #ifdef QCN_DEBUG 450 prom_printf("qcn_getinfo(): devt2instance %lx\n", arg); 451 #endif 452 if (getminor((dev_t)arg) == 0) { 453 *result = (void *)(uintptr_t)instance; 454 error = DDI_SUCCESS; 455 } 456 break; 457 } 458 459 return (error); 460 } 461 462 /* streams open & close */ 463 /* ARGSUSED */ 464 static int 465 qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 466 { 467 tty_common_t *tty; 468 int unit = getminor(*devp); 469 470 #ifdef QCN_DEBUG 471 prom_printf("qcn_open(): minor %x\n", unit); 472 #endif 473 474 if (unit != 0) 475 return (ENXIO); 476 477 /* stream already open */ 478 if (q->q_ptr != NULL) 479 return (DDI_SUCCESS); 480 481 if (!qcn_state) { 482 cmn_err(CE_WARN, "qcn_open: console was not configured by " 483 "autoconfig\n"); 484 return (ENXIO); 485 } 486 487 mutex_enter(&qcn_state->qcn_lock); 488 tty = &(qcn_state->qcn_tty); 489 490 tty->t_readq = q; 491 tty->t_writeq = WR(q); 492 493 /* Link the RD and WR Q's */ 494 q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state; 495 qcn_state->qcn_readq = RD(q); 496 qcn_state->qcn_writeq = WR(q); 497 qprocson(q); 498 499 mutex_exit(&qcn_state->qcn_lock); 500 501 #ifdef QCN_DEBUG 502 prom_printf("qcn_open: opened as dev %lx\n", *devp); 503 #endif 504 505 return (DDI_SUCCESS); 506 } 507 508 /* ARGSUSED */ 509 static int 510 qcn_close(queue_t *q, int flag, cred_t *credp) 511 { 512 513 ASSERT(qcn_state == q->q_ptr); 514 515 if (qcn_state->qcn_wbufcid != 0) { 516 unbufcall(qcn_state->qcn_wbufcid); 517 } 518 ttycommon_close(&qcn_state->qcn_tty); 519 520 qprocsoff(q); 521 q->q_ptr = WR(q)->q_ptr = NULL; 522 qcn_state->qcn_readq = NULL; 523 qcn_state->qcn_writeq = NULL; 524 525 return (DDI_SUCCESS); 526 } 527 528 /* 529 * Put procedure for write queue. 530 * Respond to M_IOCTL, M_DATA and M_FLUSH messages here; 531 * It put's the data onto internal qcn_output_q. 532 */ 533 static int 534 qcn_wput(queue_t *q, mblk_t *mp) 535 { 536 537 #ifdef QCN_DEBUG 538 struct iocblk *iocp; 539 int i; 540 #endif 541 542 ASSERT(qcn_state == q->q_ptr); 543 544 if (!mp->b_datap) { 545 cmn_err(CE_PANIC, "qcn_wput: null datap"); 546 } 547 548 #ifdef QCN_DEBUG 549 prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n", 550 q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type); 551 #endif 552 553 mutex_enter(&qcn_state->qcn_lock); 554 555 switch (mp->b_datap->db_type) { 556 case M_IOCTL: 557 case M_CTL: 558 #ifdef QCN_DEBUG 559 iocp = (struct iocblk *)mp->b_rptr; 560 prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n", 561 iocp->ioc_cmd, TIOC); 562 #endif 563 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 564 case TCSETSW: 565 case TCSETSF: 566 case TCSETAW: 567 case TCSETAF: 568 case TCSBRK: 569 /* 570 * The change do not take effect until all 571 * output queued before them is drained. 572 * Put this message on the queue, so that 573 * "qcn_start" will see it when it's done 574 * with the output before it. Poke the start 575 * routine, just in case. 576 */ 577 (void) putq(q, mp); 578 qcn_start(); 579 break; 580 default: 581 qcn_ioctl(q, mp); 582 } 583 break; 584 585 case M_FLUSH: 586 if (*mp->b_rptr & FLUSHW) { 587 flushq(q, FLUSHDATA); 588 *mp->b_rptr &= ~FLUSHW; 589 } 590 if (*mp->b_rptr & FLUSHR) { 591 flushq(RD(q), FLUSHDATA); 592 qreply(q, mp); 593 } else { 594 freemsg(mp); 595 } 596 break; 597 598 case M_STOP: 599 qcn_stopped = B_TRUE; 600 freemsg(mp); 601 break; 602 603 case M_START: 604 qcn_stopped = B_FALSE; 605 freemsg(mp); 606 qenable(q); /* Start up delayed messages */ 607 break; 608 609 case M_DATA: 610 /* 611 * Queue the message up to be transmitted, 612 * and poke the start routine. 613 */ 614 #ifdef QCN_DEBUG 615 if (mp->b_rptr < mp->b_wptr) { 616 prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 617 q, mp, mp->b_rptr, mp->b_wptr); 618 prom_printf("qcn_wput(): ["); 619 for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 620 prom_printf("%c", *(mp->b_rptr+i)); 621 } 622 prom_printf("]\n"); 623 } 624 #endif /* QCN_DEBUG */ 625 (void) putq(q, mp); 626 qcn_start(); 627 break; 628 629 default: 630 freemsg(mp); 631 } 632 633 mutex_exit(&qcn_state->qcn_lock); 634 return (0); 635 } 636 637 /* 638 * Process an "ioctl" message sent down to us. 639 */ 640 static void 641 qcn_ioctl(queue_t *q, mblk_t *mp) 642 { 643 struct iocblk *iocp; 644 tty_common_t *tty; 645 mblk_t *datamp; 646 int data_size; 647 int error = 0; 648 649 #ifdef QCN_DEBUG 650 prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp); 651 #endif 652 653 iocp = (struct iocblk *)mp->b_rptr; 654 tty = &(qcn_state->qcn_tty); 655 656 if (tty->t_iocpending != NULL) { 657 freemsg(tty->t_iocpending); 658 tty->t_iocpending = NULL; 659 } 660 data_size = ttycommon_ioctl(tty, q, mp, &error); 661 if (data_size != 0) { 662 if (qcn_state->qcn_wbufcid) 663 unbufcall(qcn_state->qcn_wbufcid); 664 /* call qcn_reioctl() */ 665 qcn_state->qcn_wbufcid = 666 bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state); 667 return; 668 } 669 670 if (error < 0) { 671 iocp = (struct iocblk *)mp->b_rptr; 672 /* 673 * "ttycommon_ioctl" didn't do anything; we process it here. 674 */ 675 error = 0; 676 switch (iocp->ioc_cmd) { 677 case TCSBRK: 678 case TIOCSBRK: 679 case TIOCCBRK: 680 case TIOCMSET: 681 case TIOCMBIS: 682 case TIOCMBIC: 683 if (iocp->ioc_count != TRANSPARENT) 684 qcn_ack(mp, NULL, 0); 685 else 686 mcopyin(mp, NULL, sizeof (int), NULL); 687 break; 688 689 case TIOCMGET: 690 datamp = allocb(sizeof (int), BPRI_MED); 691 if (datamp == NULL) { 692 error = EAGAIN; 693 break; 694 } 695 696 *(int *)datamp->b_rptr = 0; 697 698 if (iocp->ioc_count != TRANSPARENT) 699 qcn_ack(mp, datamp, sizeof (int)); 700 else 701 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 702 break; 703 704 default: 705 error = EINVAL; 706 break; 707 } 708 } 709 if (error != 0) { 710 iocp->ioc_count = 0; 711 iocp->ioc_error = error; 712 mp->b_datap->db_type = M_IOCNAK; 713 } 714 qreply(q, mp); 715 } 716 717 static void 718 qcn_reioctl(void *unit) 719 { 720 queue_t *q; 721 mblk_t *mp; 722 qcn_t *qcnp = (qcn_t *)unit; 723 724 if (!qcnp->qcn_wbufcid) 725 return; 726 727 qcnp->qcn_wbufcid = 0; 728 if ((q = qcnp->qcn_tty.t_writeq) == NULL) 729 return; 730 731 if ((mp = qcnp->qcn_tty.t_iocpending) == NULL) 732 return; 733 734 qcnp->qcn_tty.t_iocpending = NULL; 735 qcn_ioctl(q, mp); 736 } 737 738 static void 739 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size) 740 { 741 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 742 743 mp->b_datap->db_type = M_IOCACK; 744 iocp->ioc_count = size; 745 iocp->ioc_error = 0; 746 iocp->ioc_rval = 0; 747 if (mp->b_cont != NULL) 748 freeb(mp->b_cont); 749 if (dp != NULL) { 750 mp->b_cont = dp; 751 dp->b_wptr += size; 752 } else 753 mp->b_cont = NULL; 754 } 755 756 static void 757 qcn_start(void) 758 { 759 760 queue_t *q; 761 mblk_t *mp; 762 int rv; 763 764 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 765 766 /* 767 * read stream queue and remove data from the queue and 768 * transmit them if possible 769 */ 770 q = qcn_state->qcn_writeq; 771 ASSERT(q != NULL); 772 while (mp = getq(q)) { 773 if (mp->b_datap->db_type == M_IOCTL) { 774 /* 775 * These are those IOCTLs queued up 776 * do it now 777 */ 778 qcn_ioctl(q, mp); 779 continue; 780 } 781 /* 782 * M_DATA 783 */ 784 rv = qcn_transmit(q, mp); 785 if (rv == EBUSY || rv == EAGAIN) 786 return; 787 } 788 } 789 790 static int 791 qcn_transmit(queue_t *q, mblk_t *mp) 792 { 793 caddr_t buf; 794 mblk_t *bp; 795 size_t len; 796 long i; 797 798 #ifdef QCN_DEBUG 799 prom_printf("qcn_transmit(): q=%X mp=%X\n", q, mp); 800 #endif 801 do { 802 bp = mp; 803 len = bp->b_wptr - bp->b_rptr; 804 buf = (caddr_t)bp->b_rptr; 805 806 for (i = 0; i < len; i++) { 807 if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK) 808 break; 809 } 810 if (i != len) { 811 bp->b_rptr += i; 812 (void) putbq(q, mp); 813 return (EAGAIN); 814 } 815 mp = bp->b_cont; 816 freeb(bp); 817 } while (mp != NULL); 818 819 return (0); 820 } 821 822 /* 823 * called when SC first establishes console connection 824 * drop all the data on the output queue 825 */ 826 static void 827 qcn_flush(void) 828 { 829 queue_t *q; 830 mblk_t *mp; 831 832 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 833 834 q = qcn_state->qcn_writeq; 835 836 prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n", 837 gethrestime_sec()); 838 while (mp = getq(q)) 839 freemsg(mp); 840 } 841 842 static void 843 qcn_trigger_softint(void) 844 { 845 846 if (mutex_tryenter(&qcn_state->qcn_softlock)) { 847 if (!qcn_state->qcn_soft_pend) { 848 qcn_state->qcn_soft_pend = 1; 849 mutex_exit(&qcn_state->qcn_softlock); 850 (void) ddi_intr_trigger_softint( 851 qcn_state->qcn_softint_hdl, NULL); 852 } else 853 mutex_exit(&qcn_state->qcn_softlock); 854 } 855 } 856 857 /*ARGSUSED*/ 858 static uint_t 859 qcn_soft_intr(caddr_t arg1, caddr_t arg2) 860 { 861 mblk_t *mp; 862 int cc; 863 864 mutex_enter(&qcn_state->qcn_softlock); 865 mutex_enter(&qcn_state->qcn_hi_lock); 866 if ((cc = RING_CNT(qcn_state)) <= 0) { 867 mutex_exit(&qcn_state->qcn_hi_lock); 868 goto out; 869 } 870 871 if ((mp = allocb(cc, BPRI_MED)) == NULL) { 872 qcn_input_dropped += cc; 873 cmn_err(CE_WARN, "qcn_intr: allocb" 874 "failed (console input dropped)"); 875 mutex_exit(&qcn_state->qcn_hi_lock); 876 goto out; 877 } 878 879 do { 880 /* put console input onto stream */ 881 *(char *)mp->b_wptr++ = RING_GET(qcn_state); 882 } while (--cc); 883 884 if (qcn_state->qcn_rbuf_overflow) { 885 mutex_exit(&qcn_state->qcn_hi_lock); 886 cmn_err(CE_WARN, "qcn: Ring buffer overflow\n"); 887 mutex_enter(&qcn_state->qcn_hi_lock); 888 qcn_state->qcn_rbuf_overflow = 0; 889 } 890 891 mutex_exit(&qcn_state->qcn_hi_lock); 892 if (qcn_state->qcn_readq) { 893 putnext(qcn_state->qcn_readq, mp); 894 } 895 out: 896 /* 897 * If there are pending transmits because hypervisor 898 * returned EWOULDBLOCK poke start now. 899 */ 900 901 if (qcn_state->qcn_writeq != NULL) { 902 if (qcn_state->qcn_hangup) { 903 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 904 flushq(qcn_state->qcn_writeq, FLUSHDATA); 905 qcn_state->qcn_hangup = 0; 906 } else { 907 mutex_enter(&qcn_state->qcn_lock); 908 qcn_start(); 909 mutex_exit(&qcn_state->qcn_lock); 910 } 911 } 912 qcn_state->qcn_soft_pend = 0; 913 mutex_exit(&qcn_state->qcn_softlock); 914 return (DDI_INTR_CLAIMED); 915 } 916 917 /*ARGSUSED*/ 918 static uint_t 919 qcn_hi_intr(caddr_t arg) 920 { 921 int64_t rv; 922 uint8_t buf; 923 924 mutex_enter(&qcn_state->qcn_hi_lock); 925 /* LINTED: E_CONSTANT_CONDITION */ 926 while (1) { 927 rv = hv_cngetchar(&buf); 928 if (rv == H_BREAK) { 929 if (abort_enable != KIOCABORTALTERNATE) 930 abort_sequence_enter((char *)NULL); 931 } 932 933 if (rv == H_HUP) { 934 qcn_state->qcn_hangup = 1; 935 } 936 937 if (rv != H_EOK) 938 goto out; 939 940 if (abort_enable == KIOCABORTALTERNATE) { 941 if (abort_charseq_recognize(buf)) { 942 abort_sequence_enter((char *)NULL); 943 } 944 } 945 946 /* put console input onto stream */ 947 if (RING_POK(qcn_state, 1)) { 948 RING_PUT(qcn_state, buf); 949 } else { 950 qcn_state->qcn_rbuf_overflow++; 951 } 952 } 953 out: 954 mutex_exit(&qcn_state->qcn_hi_lock); 955 qcn_trigger_softint(); 956 957 return (DDI_INTR_CLAIMED); 958 } 959 960 #ifdef QCN_POLLING 961 /*ARGSUSED*/ 962 static void 963 qcn_poll_handler(void *unused) 964 { 965 mblk_t *mp; 966 int64_t rv; 967 uint8_t buf; 968 int qcn_writeq_flush = 0; 969 970 /* LINTED: E_CONSTANT_CONDITION */ 971 while (1) { 972 rv = hv_cngetchar(&buf); 973 if (rv == H_BREAK) { 974 if (abort_enable != KIOCABORTALTERNATE) 975 abort_sequence_enter((char *)NULL); 976 } 977 978 if (rv == H_HUP) { 979 if (qcn_state->qcn_readq) { 980 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 981 qcn_writeq_flush = 1; 982 } 983 goto out; 984 } 985 986 if (rv != H_EOK) 987 goto out; 988 989 if (abort_enable == KIOCABORTALTERNATE) { 990 if (abort_charseq_recognize(buf)) { 991 abort_sequence_enter((char *)NULL); 992 } 993 } 994 995 /* put console input onto stream */ 996 if (qcn_state->qcn_readq) { 997 if ((mp = allocb(1, BPRI_MED)) == NULL) { 998 qcn_input_dropped++; 999 cmn_err(CE_WARN, "qcn_intr: allocb" 1000 "failed (console input dropped)"); 1001 return; 1002 } 1003 *(char *)mp->b_wptr++ = buf; 1004 putnext(qcn_state->qcn_readq, mp); 1005 } 1006 } 1007 out: 1008 /* 1009 * If there are pending transmits because hypervisor 1010 * returned EWOULDBLOCK poke start now. 1011 */ 1012 1013 mutex_enter(&qcn_state->qcn_lock); 1014 if (qcn_state->qcn_writeq != NULL) { 1015 if (qcn_writeq_flush) { 1016 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1017 } else { 1018 qcn_start(); 1019 } 1020 } 1021 mutex_exit(&qcn_state->qcn_lock); 1022 } 1023 #endif 1024 1025 /* 1026 * Check for abort character sequence, copied from zs_async.c 1027 */ 1028 #define CNTRL(c) ((c)&037) 1029 1030 static boolean_t 1031 abort_charseq_recognize(uchar_t ch) 1032 { 1033 static int state = 0; 1034 static char sequence[] = { '\r', '~', CNTRL('b') }; 1035 1036 if (ch == sequence[state]) { 1037 if (++state >= sizeof (sequence)) { 1038 state = 0; 1039 return (B_TRUE); 1040 } 1041 } else { 1042 state = (ch == sequence[0]) ? 1 : 0; 1043 } 1044 return (B_FALSE); 1045 } 1046 1047 1048 static int 1049 qcn_rsrv(queue_t *q) 1050 { 1051 mblk_t *mp; 1052 1053 if (qcn_stopped == B_TRUE) 1054 return (0); 1055 1056 mutex_enter(&qcn_state->qcn_lock); 1057 1058 while ((mp = getq(q)) != NULL) { 1059 if (canputnext(q)) 1060 putnext(q, mp); 1061 else if (mp->b_datap->db_type >= QPCTL) 1062 (void) putbq(q, mp); 1063 } 1064 1065 mutex_exit(&qcn_state->qcn_lock); 1066 1067 return (0); 1068 } 1069 1070 /* ARGSUSED */ 1071 static int 1072 qcn_wsrv(queue_t *q) 1073 { 1074 if (qcn_stopped == B_TRUE) 1075 return (0); 1076 1077 mutex_enter(&qcn_state->qcn_lock); 1078 1079 if (qcn_state->qcn_writeq != NULL) 1080 qcn_start(); 1081 1082 mutex_exit(&qcn_state->qcn_lock); 1083 1084 return (0); 1085 } 1086