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