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