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 2007 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 mutex_exit(&qcn_state->qcn_lock); 610 qcn_ioctl(q, mp); 611 mutex_enter(&qcn_state->qcn_lock); 612 } 613 break; 614 615 case M_FLUSH: 616 if (*mp->b_rptr & FLUSHW) { 617 flushq(q, FLUSHDATA); 618 *mp->b_rptr &= ~FLUSHW; 619 } 620 if (*mp->b_rptr & FLUSHR) { 621 flushq(RD(q), FLUSHDATA); 622 qreply(q, mp); 623 } else { 624 freemsg(mp); 625 } 626 break; 627 628 case M_STOP: 629 qcn_stopped = B_TRUE; 630 freemsg(mp); 631 break; 632 633 case M_START: 634 qcn_stopped = B_FALSE; 635 freemsg(mp); 636 qenable(q); /* Start up delayed messages */ 637 break; 638 639 case M_DATA: 640 /* 641 * Queue the message up to be transmitted, 642 * and poke the start routine. 643 */ 644 #ifdef QCN_DEBUG 645 if (mp->b_rptr < mp->b_wptr) { 646 prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 647 q, mp, mp->b_rptr, mp->b_wptr); 648 prom_printf("qcn_wput(): ["); 649 for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 650 prom_printf("%c", *(mp->b_rptr+i)); 651 } 652 prom_printf("]\n"); 653 } 654 #endif /* QCN_DEBUG */ 655 (void) putq(q, mp); 656 qcn_start(); 657 break; 658 659 default: 660 freemsg(mp); 661 } 662 663 mutex_exit(&qcn_state->qcn_lock); 664 665 return (0); 666 } 667 668 /* 669 * Process an "ioctl" message sent down to us. 670 */ 671 static void 672 qcn_ioctl(queue_t *q, mblk_t *mp) 673 { 674 struct iocblk *iocp; 675 tty_common_t *tty; 676 mblk_t *datamp; 677 int data_size; 678 int error = 0; 679 680 #ifdef QCN_DEBUG 681 prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp); 682 #endif 683 684 iocp = (struct iocblk *)mp->b_rptr; 685 tty = &(qcn_state->qcn_tty); 686 687 if (tty->t_iocpending != NULL) { 688 freemsg(tty->t_iocpending); 689 tty->t_iocpending = NULL; 690 } 691 data_size = ttycommon_ioctl(tty, q, mp, &error); 692 if (data_size != 0) { 693 if (qcn_state->qcn_wbufcid) 694 unbufcall(qcn_state->qcn_wbufcid); 695 /* call qcn_reioctl() */ 696 qcn_state->qcn_wbufcid = 697 bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state); 698 return; 699 } 700 701 mutex_enter(&qcn_state->qcn_lock); 702 703 if (error < 0) { 704 iocp = (struct iocblk *)mp->b_rptr; 705 /* 706 * "ttycommon_ioctl" didn't do anything; we process it here. 707 */ 708 error = 0; 709 switch (iocp->ioc_cmd) { 710 case TCSBRK: 711 case TIOCSBRK: 712 case TIOCCBRK: 713 case TIOCMSET: 714 case TIOCMBIS: 715 case TIOCMBIC: 716 if (iocp->ioc_count != TRANSPARENT) 717 qcn_ack(mp, NULL, 0); 718 else 719 mcopyin(mp, NULL, sizeof (int), NULL); 720 break; 721 722 case TIOCMGET: 723 datamp = allocb(sizeof (int), BPRI_MED); 724 if (datamp == NULL) { 725 error = EAGAIN; 726 break; 727 } 728 729 *(int *)datamp->b_rptr = 0; 730 731 if (iocp->ioc_count != TRANSPARENT) 732 qcn_ack(mp, datamp, sizeof (int)); 733 else 734 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 735 break; 736 737 default: 738 error = EINVAL; 739 break; 740 } 741 } 742 if (error != 0) { 743 iocp->ioc_count = 0; 744 iocp->ioc_error = error; 745 mp->b_datap->db_type = M_IOCNAK; 746 } 747 mutex_exit(&qcn_state->qcn_lock); 748 qreply(q, mp); 749 } 750 751 static void 752 qcn_reioctl(void *unit) 753 { 754 queue_t *q; 755 mblk_t *mp; 756 qcn_t *qcnp = (qcn_t *)unit; 757 758 if (!qcnp->qcn_wbufcid) 759 return; 760 761 qcnp->qcn_wbufcid = 0; 762 if ((q = qcnp->qcn_tty.t_writeq) == NULL) 763 return; 764 765 if ((mp = qcnp->qcn_tty.t_iocpending) == NULL) 766 return; 767 768 qcnp->qcn_tty.t_iocpending = NULL; 769 qcn_ioctl(q, mp); 770 } 771 772 static void 773 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size) 774 { 775 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 776 777 mp->b_datap->db_type = M_IOCACK; 778 iocp->ioc_count = size; 779 iocp->ioc_error = 0; 780 iocp->ioc_rval = 0; 781 if (mp->b_cont != NULL) 782 freeb(mp->b_cont); 783 if (dp != NULL) { 784 mp->b_cont = dp; 785 dp->b_wptr += size; 786 } else 787 mp->b_cont = NULL; 788 } 789 790 static void 791 qcn_start(void) 792 { 793 794 queue_t *q; 795 mblk_t *mp; 796 int rv; 797 798 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 799 800 /* 801 * read stream queue and remove data from the queue and 802 * transmit them if possible 803 */ 804 q = qcn_state->qcn_writeq; 805 ASSERT(q != NULL); 806 while (mp = getq(q)) { 807 if (mp->b_datap->db_type == M_IOCTL) { 808 /* 809 * These are those IOCTLs queued up 810 * do it now 811 */ 812 mutex_exit(&qcn_state->qcn_lock); 813 qcn_ioctl(q, mp); 814 mutex_enter(&qcn_state->qcn_lock); 815 continue; 816 } 817 /* 818 * M_DATA 819 */ 820 rv = qcn_state->cons_transmit(q, mp); 821 if (rv == EBUSY || rv == EAGAIN) 822 return; 823 } 824 } 825 826 static int 827 qcn_transmit_write(queue_t *q, mblk_t *mp) 828 { 829 mblk_t *bp; 830 size_t len; 831 uint64_t i; 832 uint64_t retval = 0; 833 834 #ifdef QCN_DEBUG 835 prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp); 836 #endif 837 838 while (mp) { 839 bp = mp; 840 len = bp->b_wptr - bp->b_rptr; 841 /* 842 * Use the console write call to send a block of characters to 843 * the console. 844 */ 845 i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len; 846 bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i); 847 retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i); 848 849 if (retval == H_EOK) { 850 len -= i; 851 bp->b_rptr += i; 852 /* 853 * if we have finished with this buf, free 854 * and get the next buf if present. 855 */ 856 if (len == 0) { 857 mp = bp->b_cont; 858 freeb(bp); 859 } 860 } else { 861 (void) putbq(q, mp); 862 863 switch (retval) { 864 865 case H_EWOULDBLOCK : 866 /* 867 * hypervisor cannot process the request - 868 * channel busy. Try again later. 869 */ 870 return (EAGAIN); 871 872 case H_EIO : 873 return (EIO); 874 default : 875 return (ENXIO); 876 } 877 } 878 } 879 return (0); 880 } 881 882 static int 883 qcn_transmit_putchr(queue_t *q, mblk_t *mp) 884 { 885 caddr_t buf; 886 mblk_t *bp; 887 size_t len; 888 uint64_t i; 889 890 #ifdef QCN_DEBUG 891 prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp); 892 #endif 893 while (mp) { 894 bp = mp; 895 len = bp->b_wptr - bp->b_rptr; 896 buf = (caddr_t)bp->b_rptr; 897 for (i = 0; i < len; i++) { 898 if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK) 899 break; 900 } 901 if (i != len) { 902 bp->b_rptr += i; 903 (void) putbq(q, mp); 904 return (EAGAIN); 905 } 906 mp = bp->b_cont; 907 freeb(bp); 908 } 909 return (0); 910 } 911 912 /* 913 * called when SC first establishes console connection 914 * drop all the data on the output queue 915 */ 916 static void 917 qcn_flush(void) 918 { 919 queue_t *q; 920 mblk_t *mp; 921 922 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 923 924 q = qcn_state->qcn_writeq; 925 926 prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n", 927 gethrestime_sec()); 928 while (mp = getq(q)) 929 freemsg(mp); 930 } 931 932 static void 933 qcn_trigger_softint(void) 934 { 935 /* 936 * if we are not currently servicing a software interrupt 937 * (qcn_soft_pend == 0), trigger the service routine to run. 938 */ 939 if (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_DO) == 940 QCN_SP_IDL) { 941 (void) ddi_intr_trigger_softint( 942 qcn_state->qcn_softint_hdl, NULL); 943 } 944 } 945 946 /*ARGSUSED*/ 947 static uint_t 948 qcn_soft_intr(caddr_t arg1, caddr_t arg2) 949 { 950 mblk_t *mp; 951 int cc; 952 int overflow_check; 953 954 do { 955 (void) atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IP); 956 mutex_enter(&qcn_state->qcn_hi_lock); 957 cc = RING_CNT(qcn_state); 958 mutex_exit(&qcn_state->qcn_hi_lock); 959 if (cc <= 0) { 960 goto out; 961 } 962 963 if ((mp = allocb(cc, BPRI_MED)) == NULL) { 964 mutex_enter(&qcn_state->qcn_hi_lock); 965 qcn_input_dropped += cc; 966 mutex_exit(&qcn_state->qcn_hi_lock); 967 cmn_err(CE_WARN, "qcn_intr: allocb" 968 "failed (console input dropped)"); 969 goto out; 970 } 971 972 mutex_enter(&qcn_state->qcn_hi_lock); 973 do { 974 /* put console input onto stream */ 975 *(char *)mp->b_wptr++ = RING_GET(qcn_state); 976 } while (--cc); 977 978 if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) { 979 qcn_state->qcn_rbuf_overflow = 0; 980 } 981 mutex_exit(&qcn_state->qcn_hi_lock); 982 983 if (overflow_check) { 984 cmn_err(CE_WARN, "qcn: Ring buffer overflow\n"); 985 } 986 987 if (qcn_state->qcn_readq) { 988 putnext(qcn_state->qcn_readq, mp); 989 } 990 out: 991 /* 992 * If there are pending transmits because hypervisor 993 * returned EWOULDBLOCK poke start now. 994 */ 995 996 if (qcn_state->qcn_writeq != NULL) { 997 if (qcn_state->qcn_hangup) { 998 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 999 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1000 qcn_state->qcn_hangup = 0; 1001 } else { 1002 mutex_enter(&qcn_state->qcn_lock); 1003 qcn_start(); 1004 mutex_exit(&qcn_state->qcn_lock); 1005 } 1006 } 1007 /* 1008 * now loop if another interrupt came in (qcn_trigger_softint 1009 * called) while we were processing the loop 1010 */ 1011 } while (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IDL) == 1012 QCN_SP_DO); 1013 return (DDI_INTR_CLAIMED); 1014 } 1015 1016 /*ARGSUSED*/ 1017 static uint_t 1018 qcn_hi_intr(caddr_t arg) 1019 { 1020 mutex_enter(&qcn_state->qcn_hi_lock); 1021 1022 qcn_state->cons_receive(); 1023 1024 mutex_exit(&qcn_state->qcn_hi_lock); 1025 qcn_trigger_softint(); 1026 1027 return (DDI_INTR_CLAIMED); 1028 } 1029 1030 static void 1031 qcn_receive_read(void) 1032 { 1033 int64_t rv; 1034 uint8_t *bufp; 1035 int64_t retcount = 0; 1036 int i; 1037 1038 do { 1039 /* 1040 * Maximize available buffer size 1041 */ 1042 if (RING_CNT(qcn_state) <= 0) { 1043 RING_INIT(qcn_state); 1044 } 1045 rv = hv_cnread(qcn_state->cons_read_buf_ra + 1046 RING_POFF(qcn_state), 1047 RING_LEFT(qcn_state), 1048 &retcount); 1049 bufp = RING_ADDR(qcn_state); 1050 if (rv == H_EOK) { 1051 /* 1052 * if the alternate break sequence is enabled, test 1053 * the buffer for the sequence and if it is there, 1054 * enter the debugger. 1055 */ 1056 if (abort_enable == KIOCABORTALTERNATE) { 1057 for (i = 0; i < retcount; i++) { 1058 if (abort_charseq_recognize(*bufp++)) { 1059 abort_sequence_enter( 1060 (char *)NULL); 1061 } 1062 } 1063 } 1064 1065 /* put console input onto stream */ 1066 if (retcount > 0) { 1067 /* 1068 * the characters are already in the ring, 1069 * just update the pointer so the characters 1070 * can be retrieved. 1071 */ 1072 RING_UPD(qcn_state, retcount); 1073 } 1074 } else { 1075 switch (rv) { 1076 1077 case H_EWOULDBLOCK : 1078 /* 1079 * hypervisor cannot handle the request. 1080 * Try again later. 1081 */ 1082 break; 1083 1084 1085 case H_BREAK : 1086 /* 1087 * on break, unless alternate break sequence is 1088 * enabled, enter the debugger 1089 */ 1090 if (abort_enable != KIOCABORTALTERNATE) 1091 abort_sequence_enter((char *)NULL); 1092 break; 1093 1094 case H_HUP : 1095 qcn_state->qcn_hangup = 1; 1096 break; 1097 1098 default : 1099 break; 1100 } 1101 } 1102 } while (rv == H_EOK); 1103 } 1104 1105 static void 1106 qcn_receive_getchr(void) 1107 { 1108 int64_t rv; 1109 uint8_t buf; 1110 1111 do { 1112 rv = hv_cngetchar(&buf); 1113 if (rv == H_EOK) { 1114 if (abort_enable == KIOCABORTALTERNATE) { 1115 if (abort_charseq_recognize(buf)) { 1116 abort_sequence_enter((char *)NULL); 1117 } 1118 } 1119 1120 /* put console input onto stream */ 1121 if (RING_POK(qcn_state, 1)) { 1122 RING_PUT(qcn_state, buf); 1123 } else { 1124 qcn_state->qcn_rbuf_overflow++; 1125 } 1126 } else { 1127 if (rv == H_BREAK) { 1128 if (abort_enable != KIOCABORTALTERNATE) 1129 abort_sequence_enter((char *)NULL); 1130 } 1131 1132 if (rv == H_HUP) { 1133 qcn_state->qcn_hangup = 1; 1134 } 1135 return; 1136 } 1137 } while (rv == H_EOK); 1138 } 1139 1140 #ifdef QCN_POLLING 1141 /*ARGSUSED*/ 1142 static void 1143 qcn_poll_handler(void *unused) 1144 { 1145 mblk_t *mp; 1146 int64_t rv; 1147 uint8_t buf; 1148 int qcn_writeq_flush = 0; 1149 1150 /* LINTED: E_CONSTANT_CONDITION */ 1151 while (1) { 1152 rv = hv_cngetchar(&buf); 1153 if (rv == H_BREAK) { 1154 if (abort_enable != KIOCABORTALTERNATE) 1155 abort_sequence_enter((char *)NULL); 1156 } 1157 1158 if (rv == H_HUP) { 1159 if (qcn_state->qcn_readq) { 1160 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 1161 qcn_writeq_flush = 1; 1162 } 1163 goto out; 1164 } 1165 1166 if (rv != H_EOK) 1167 goto out; 1168 1169 if (abort_enable == KIOCABORTALTERNATE) { 1170 if (abort_charseq_recognize(buf)) { 1171 abort_sequence_enter((char *)NULL); 1172 } 1173 } 1174 1175 /* put console input onto stream */ 1176 if (qcn_state->qcn_readq) { 1177 if ((mp = allocb(1, BPRI_MED)) == NULL) { 1178 qcn_input_dropped++; 1179 cmn_err(CE_WARN, "qcn_intr: allocb" 1180 "failed (console input dropped)"); 1181 return; 1182 } 1183 *(char *)mp->b_wptr++ = buf; 1184 putnext(qcn_state->qcn_readq, mp); 1185 } 1186 } 1187 out: 1188 /* 1189 * If there are pending transmits because hypervisor 1190 * returned EWOULDBLOCK poke start now. 1191 */ 1192 1193 mutex_enter(&qcn_state->qcn_lock); 1194 if (qcn_state->qcn_writeq != NULL) { 1195 if (qcn_writeq_flush) { 1196 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1197 } else { 1198 qcn_start(); 1199 } 1200 } 1201 mutex_exit(&qcn_state->qcn_lock); 1202 } 1203 #endif 1204 1205 /* 1206 * Check for abort character sequence, copied from zs_async.c 1207 */ 1208 #define CNTRL(c) ((c)&037) 1209 1210 static boolean_t 1211 abort_charseq_recognize(uchar_t ch) 1212 { 1213 static int state = 0; 1214 static char sequence[] = { '\r', '~', CNTRL('b') }; 1215 1216 if (ch == sequence[state]) { 1217 if (++state >= sizeof (sequence)) { 1218 state = 0; 1219 return (B_TRUE); 1220 } 1221 } else { 1222 state = (ch == sequence[0]) ? 1 : 0; 1223 } 1224 return (B_FALSE); 1225 } 1226 1227 1228 static int 1229 qcn_rsrv(queue_t *q) 1230 { 1231 mblk_t *mp; 1232 1233 if (qcn_stopped == B_TRUE) 1234 return (0); 1235 1236 mutex_enter(&qcn_state->qcn_lock); 1237 1238 while ((mp = getq(q)) != NULL) { 1239 if (canputnext(q)) 1240 putnext(q, mp); 1241 else if (mp->b_datap->db_type >= QPCTL) 1242 (void) putbq(q, mp); 1243 } 1244 1245 mutex_exit(&qcn_state->qcn_lock); 1246 1247 return (0); 1248 } 1249 1250 /* ARGSUSED */ 1251 static int 1252 qcn_wsrv(queue_t *q) 1253 { 1254 if (qcn_stopped == B_TRUE) 1255 return (0); 1256 1257 mutex_enter(&qcn_state->qcn_lock); 1258 1259 if (qcn_state->qcn_writeq != NULL) 1260 qcn_start(); 1261 1262 mutex_exit(&qcn_state->qcn_lock); 1263 1264 return (0); 1265 } 1266