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 qcn_state->qcn_soft_pri = 410 (ddi_iblock_cookie_t)(uint64_t)soft_prip; 411 412 mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER, 413 (void *)(uintptr_t)(qcn_state->qcn_intr_pri)); 414 mutex_init(&qcn_state->qcn_softlock, NULL, MUTEX_DRIVER, 415 (void *)(qcn_state->qcn_soft_pri)); 416 } 417 418 mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL); 419 420 /* 421 * Enable interrupts 422 */ 423 if (!qcn_state->qcn_polling) { 424 qcn_intr_enable(); 425 } 426 #ifdef QCN_DEBUG 427 prom_printf("qcn_attach(): qcn driver attached\n"); 428 #endif 429 430 return (DDI_SUCCESS); 431 432 } 433 434 /* ARGSUSED */ 435 static int 436 qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 437 { 438 439 if (cmd != DDI_DETACH) 440 return (DDI_FAILURE); 441 442 443 #ifdef QCN_DEBUG 444 prom_printf("qcn_detach(): QCN driver detached\n"); 445 #endif 446 447 #ifdef QCN_POLLING 448 if (qcn_state->qcn_polling) { 449 mutex_enter(&cpu_lock); 450 if (qcn_poll_cycid != CYCLIC_NONE) 451 cyclic_remove(qcn_poll_cycid); 452 qcn_poll_cycid = CYCLIC_NONE; 453 mutex_exit(&cpu_lock); 454 } 455 #endif 456 457 if (!qcn_state->qcn_polling) 458 qcn_remove_intrs(); 459 460 return (DDI_SUCCESS); 461 } 462 463 /* ARGSUSED */ 464 static int 465 qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 466 { 467 int error = DDI_FAILURE; 468 int instance = 0; 469 switch (infocmd) { 470 case DDI_INFO_DEVT2DEVINFO: 471 if (qcn_state) { 472 #ifdef QCN_DEBUG 473 prom_printf("qcn_getinfo(): devt2dip %lx\n", arg); 474 #endif 475 *result = (void *)qcn_state->qcn_dip; 476 error = DDI_SUCCESS; 477 } 478 break; 479 480 case DDI_INFO_DEVT2INSTANCE: 481 #ifdef QCN_DEBUG 482 prom_printf("qcn_getinfo(): devt2instance %lx\n", arg); 483 #endif 484 if (getminor((dev_t)arg) == 0) { 485 *result = (void *)(uintptr_t)instance; 486 error = DDI_SUCCESS; 487 } 488 break; 489 } 490 491 return (error); 492 } 493 494 /* streams open & close */ 495 /* ARGSUSED */ 496 static int 497 qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 498 { 499 tty_common_t *tty; 500 int unit = getminor(*devp); 501 502 #ifdef QCN_DEBUG 503 prom_printf("qcn_open(): minor %x\n", unit); 504 #endif 505 506 if (unit != 0) 507 return (ENXIO); 508 509 /* stream already open */ 510 if (q->q_ptr != NULL) 511 return (DDI_SUCCESS); 512 513 if (!qcn_state) { 514 cmn_err(CE_WARN, "qcn_open: console was not configured by " 515 "autoconfig\n"); 516 return (ENXIO); 517 } 518 519 mutex_enter(&qcn_state->qcn_lock); 520 tty = &(qcn_state->qcn_tty); 521 522 tty->t_readq = q; 523 tty->t_writeq = WR(q); 524 525 /* Link the RD and WR Q's */ 526 q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state; 527 qcn_state->qcn_readq = RD(q); 528 qcn_state->qcn_writeq = WR(q); 529 qprocson(q); 530 531 mutex_exit(&qcn_state->qcn_lock); 532 533 #ifdef QCN_DEBUG 534 prom_printf("qcn_open: opened as dev %lx\n", *devp); 535 #endif 536 537 return (DDI_SUCCESS); 538 } 539 540 /* ARGSUSED */ 541 static int 542 qcn_close(queue_t *q, int flag, cred_t *credp) 543 { 544 545 ASSERT(qcn_state == q->q_ptr); 546 547 if (qcn_state->qcn_wbufcid != 0) { 548 unbufcall(qcn_state->qcn_wbufcid); 549 } 550 ttycommon_close(&qcn_state->qcn_tty); 551 552 qprocsoff(q); 553 q->q_ptr = WR(q)->q_ptr = NULL; 554 qcn_state->qcn_readq = NULL; 555 qcn_state->qcn_writeq = NULL; 556 557 return (DDI_SUCCESS); 558 } 559 560 /* 561 * Put procedure for write queue. 562 * Respond to M_IOCTL, M_DATA and M_FLUSH messages here; 563 * It put's the data onto internal qcn_output_q. 564 */ 565 static int 566 qcn_wput(queue_t *q, mblk_t *mp) 567 { 568 569 #ifdef QCN_DEBUG 570 struct iocblk *iocp; 571 int i; 572 #endif 573 574 ASSERT(qcn_state == q->q_ptr); 575 576 if (!mp->b_datap) { 577 cmn_err(CE_PANIC, "qcn_wput: null datap"); 578 } 579 580 #ifdef QCN_DEBUG 581 prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n", 582 q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type); 583 #endif 584 585 mutex_enter(&qcn_state->qcn_lock); 586 587 switch (mp->b_datap->db_type) { 588 case M_IOCTL: 589 case M_CTL: 590 #ifdef QCN_DEBUG 591 iocp = (struct iocblk *)mp->b_rptr; 592 prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n", 593 iocp->ioc_cmd, TIOC); 594 #endif 595 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 596 case TCSETSW: 597 case TCSETSF: 598 case TCSETAW: 599 case TCSETAF: 600 case TCSBRK: 601 /* 602 * The change do not take effect until all 603 * output queued before them is drained. 604 * Put this message on the queue, so that 605 * "qcn_start" will see it when it's done 606 * with the output before it. Poke the start 607 * routine, just in case. 608 */ 609 (void) putq(q, mp); 610 qcn_start(); 611 break; 612 default: 613 qcn_ioctl(q, mp); 614 } 615 break; 616 617 case M_FLUSH: 618 if (*mp->b_rptr & FLUSHW) { 619 flushq(q, FLUSHDATA); 620 *mp->b_rptr &= ~FLUSHW; 621 } 622 if (*mp->b_rptr & FLUSHR) { 623 flushq(RD(q), FLUSHDATA); 624 qreply(q, mp); 625 } else { 626 freemsg(mp); 627 } 628 break; 629 630 case M_STOP: 631 qcn_stopped = B_TRUE; 632 freemsg(mp); 633 break; 634 635 case M_START: 636 qcn_stopped = B_FALSE; 637 freemsg(mp); 638 qenable(q); /* Start up delayed messages */ 639 break; 640 641 case M_DATA: 642 /* 643 * Queue the message up to be transmitted, 644 * and poke the start routine. 645 */ 646 #ifdef QCN_DEBUG 647 if (mp->b_rptr < mp->b_wptr) { 648 prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 649 q, mp, mp->b_rptr, mp->b_wptr); 650 prom_printf("qcn_wput(): ["); 651 for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 652 prom_printf("%c", *(mp->b_rptr+i)); 653 } 654 prom_printf("]\n"); 655 } 656 #endif /* QCN_DEBUG */ 657 (void) putq(q, mp); 658 qcn_start(); 659 break; 660 661 default: 662 freemsg(mp); 663 } 664 665 mutex_exit(&qcn_state->qcn_lock); 666 return (0); 667 } 668 669 /* 670 * Process an "ioctl" message sent down to us. 671 */ 672 static void 673 qcn_ioctl(queue_t *q, mblk_t *mp) 674 { 675 struct iocblk *iocp; 676 tty_common_t *tty; 677 mblk_t *datamp; 678 int data_size; 679 int error = 0; 680 681 #ifdef QCN_DEBUG 682 prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp); 683 #endif 684 685 iocp = (struct iocblk *)mp->b_rptr; 686 tty = &(qcn_state->qcn_tty); 687 688 if (tty->t_iocpending != NULL) { 689 freemsg(tty->t_iocpending); 690 tty->t_iocpending = NULL; 691 } 692 data_size = ttycommon_ioctl(tty, q, mp, &error); 693 if (data_size != 0) { 694 if (qcn_state->qcn_wbufcid) 695 unbufcall(qcn_state->qcn_wbufcid); 696 /* call qcn_reioctl() */ 697 qcn_state->qcn_wbufcid = 698 bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state); 699 return; 700 } 701 702 if (error < 0) { 703 iocp = (struct iocblk *)mp->b_rptr; 704 /* 705 * "ttycommon_ioctl" didn't do anything; we process it here. 706 */ 707 error = 0; 708 switch (iocp->ioc_cmd) { 709 case TCSBRK: 710 case TIOCSBRK: 711 case TIOCCBRK: 712 case TIOCMSET: 713 case TIOCMBIS: 714 case TIOCMBIC: 715 if (iocp->ioc_count != TRANSPARENT) 716 qcn_ack(mp, NULL, 0); 717 else 718 mcopyin(mp, NULL, sizeof (int), NULL); 719 break; 720 721 case TIOCMGET: 722 datamp = allocb(sizeof (int), BPRI_MED); 723 if (datamp == NULL) { 724 error = EAGAIN; 725 break; 726 } 727 728 *(int *)datamp->b_rptr = 0; 729 730 if (iocp->ioc_count != TRANSPARENT) 731 qcn_ack(mp, datamp, sizeof (int)); 732 else 733 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 734 break; 735 736 default: 737 error = EINVAL; 738 break; 739 } 740 } 741 if (error != 0) { 742 iocp->ioc_count = 0; 743 iocp->ioc_error = error; 744 mp->b_datap->db_type = M_IOCNAK; 745 } 746 qreply(q, mp); 747 } 748 749 static void 750 qcn_reioctl(void *unit) 751 { 752 queue_t *q; 753 mblk_t *mp; 754 qcn_t *qcnp = (qcn_t *)unit; 755 756 if (!qcnp->qcn_wbufcid) 757 return; 758 759 qcnp->qcn_wbufcid = 0; 760 if ((q = qcnp->qcn_tty.t_writeq) == NULL) 761 return; 762 763 if ((mp = qcnp->qcn_tty.t_iocpending) == NULL) 764 return; 765 766 qcnp->qcn_tty.t_iocpending = NULL; 767 qcn_ioctl(q, mp); 768 } 769 770 static void 771 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size) 772 { 773 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 774 775 mp->b_datap->db_type = M_IOCACK; 776 iocp->ioc_count = size; 777 iocp->ioc_error = 0; 778 iocp->ioc_rval = 0; 779 if (mp->b_cont != NULL) 780 freeb(mp->b_cont); 781 if (dp != NULL) { 782 mp->b_cont = dp; 783 dp->b_wptr += size; 784 } else 785 mp->b_cont = NULL; 786 } 787 788 static void 789 qcn_start(void) 790 { 791 792 queue_t *q; 793 mblk_t *mp; 794 int rv; 795 796 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 797 798 /* 799 * read stream queue and remove data from the queue and 800 * transmit them if possible 801 */ 802 q = qcn_state->qcn_writeq; 803 ASSERT(q != NULL); 804 while (mp = getq(q)) { 805 if (mp->b_datap->db_type == M_IOCTL) { 806 /* 807 * These are those IOCTLs queued up 808 * do it now 809 */ 810 qcn_ioctl(q, mp); 811 continue; 812 } 813 /* 814 * M_DATA 815 */ 816 rv = qcn_state->cons_transmit(q, mp); 817 if (rv == EBUSY || rv == EAGAIN) 818 return; 819 } 820 } 821 822 static int 823 qcn_transmit_write(queue_t *q, mblk_t *mp) 824 { 825 mblk_t *bp; 826 size_t len; 827 uint64_t i; 828 uint64_t retval = 0; 829 830 #ifdef QCN_DEBUG 831 prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp); 832 #endif 833 834 while (mp) { 835 bp = mp; 836 len = bp->b_wptr - bp->b_rptr; 837 /* 838 * Use the console write call to send a block of characters to 839 * the console. 840 */ 841 i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len; 842 bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i); 843 retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i); 844 845 if (retval == H_EOK) { 846 len -= i; 847 bp->b_rptr += i; 848 /* 849 * if we have finished with this buf, free 850 * and get the next buf if present. 851 */ 852 if (len == 0) { 853 mp = bp->b_cont; 854 freeb(bp); 855 } 856 } else { 857 (void) putbq(q, mp); 858 859 switch (retval) { 860 861 case H_EWOULDBLOCK : 862 /* 863 * hypervisor cannot process the request - 864 * channel busy. Try again later. 865 */ 866 return (EAGAIN); 867 868 case H_EIO : 869 return (EIO); 870 default : 871 return (ENXIO); 872 } 873 } 874 } 875 return (0); 876 } 877 878 static int 879 qcn_transmit_putchr(queue_t *q, mblk_t *mp) 880 { 881 caddr_t buf; 882 mblk_t *bp; 883 size_t len; 884 uint64_t i; 885 886 #ifdef QCN_DEBUG 887 prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp); 888 #endif 889 while (mp) { 890 bp = mp; 891 len = bp->b_wptr - bp->b_rptr; 892 buf = (caddr_t)bp->b_rptr; 893 for (i = 0; i < len; i++) { 894 if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK) 895 break; 896 } 897 if (i != len) { 898 bp->b_rptr += i; 899 (void) putbq(q, mp); 900 return (EAGAIN); 901 } 902 mp = bp->b_cont; 903 freeb(bp); 904 } 905 return (0); 906 } 907 908 /* 909 * called when SC first establishes console connection 910 * drop all the data on the output queue 911 */ 912 static void 913 qcn_flush(void) 914 { 915 queue_t *q; 916 mblk_t *mp; 917 918 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 919 920 q = qcn_state->qcn_writeq; 921 922 prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n", 923 gethrestime_sec()); 924 while (mp = getq(q)) 925 freemsg(mp); 926 } 927 928 static void 929 qcn_trigger_softint(void) 930 { 931 /* 932 * get lock for software ints and see if we need to trigger a soft 933 * interrupt (no pending sofware ints). 934 */ 935 mutex_enter(&qcn_state->qcn_softlock); 936 /* 937 * if we are not currently servicing a software interrupt 938 * (qcn_soft_pend == 0), trigger the service routine to run. 939 */ 940 if (!qcn_state->qcn_soft_pend++) { 941 mutex_exit(&qcn_state->qcn_softlock); 942 (void) ddi_intr_trigger_softint( 943 qcn_state->qcn_softint_hdl, NULL); 944 } else { 945 mutex_exit(&qcn_state->qcn_softlock); 946 } 947 } 948 949 /*ARGSUSED*/ 950 static uint_t 951 qcn_soft_intr(caddr_t arg1, caddr_t arg2) 952 { 953 mblk_t *mp; 954 int cc; 955 int overflow_check; 956 957 /* 958 * grab the lock for the soft int pending. It is grabbed here so 959 * that the decrement at the end of the do loop is under lock 960 * protection. 961 */ 962 mutex_enter(&qcn_state->qcn_softlock); 963 do { 964 /* 965 * release the soft int lock so that the interrupt routine 966 * will not be held up. 967 */ 968 mutex_exit(&qcn_state->qcn_softlock); 969 mutex_enter(&qcn_state->qcn_hi_lock); 970 if ((cc = RING_CNT(qcn_state)) <= 0) { 971 mutex_exit(&qcn_state->qcn_hi_lock); 972 goto out; 973 } 974 975 if ((mp = allocb(cc, BPRI_MED)) == NULL) { 976 qcn_input_dropped += cc; 977 mutex_exit(&qcn_state->qcn_hi_lock); 978 cmn_err(CE_WARN, "qcn_intr: allocb" 979 "failed (console input dropped)"); 980 goto out; 981 } 982 983 do { 984 /* put console input onto stream */ 985 *(char *)mp->b_wptr++ = RING_GET(qcn_state); 986 } while (--cc); 987 988 if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) { 989 qcn_state->qcn_rbuf_overflow = 0; 990 } 991 mutex_exit(&qcn_state->qcn_hi_lock); 992 993 if (overflow_check) { 994 cmn_err(CE_WARN, "qcn: Ring buffer overflow\n"); 995 } 996 997 if (qcn_state->qcn_readq) { 998 putnext(qcn_state->qcn_readq, mp); 999 } 1000 out: 1001 /* 1002 * If there are pending transmits because hypervisor 1003 * returned EWOULDBLOCK poke start now. 1004 */ 1005 1006 if (qcn_state->qcn_writeq != NULL) { 1007 if (qcn_state->qcn_hangup) { 1008 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 1009 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1010 qcn_state->qcn_hangup = 0; 1011 } else { 1012 mutex_enter(&qcn_state->qcn_lock); 1013 qcn_start(); 1014 mutex_exit(&qcn_state->qcn_lock); 1015 } 1016 } 1017 mutex_enter(&qcn_state->qcn_softlock); 1018 } while (qcn_state->qcn_soft_pend-- > 1); 1019 mutex_exit(&qcn_state->qcn_softlock); 1020 return (DDI_INTR_CLAIMED); 1021 } 1022 1023 /*ARGSUSED*/ 1024 static uint_t 1025 qcn_hi_intr(caddr_t arg) 1026 { 1027 mutex_enter(&qcn_state->qcn_hi_lock); 1028 1029 qcn_state->cons_receive(); 1030 1031 mutex_exit(&qcn_state->qcn_hi_lock); 1032 qcn_trigger_softint(); 1033 1034 return (DDI_INTR_CLAIMED); 1035 } 1036 1037 static void 1038 qcn_receive_read(void) 1039 { 1040 int64_t rv; 1041 uint8_t *bufp; 1042 int64_t retcount = 0; 1043 int i; 1044 1045 do { 1046 /* 1047 * Maximize available buffer size 1048 */ 1049 if (RING_CNT(qcn_state) <= 0) { 1050 RING_INIT(qcn_state); 1051 } 1052 rv = hv_cnread(qcn_state->cons_read_buf_ra + 1053 RING_POFF(qcn_state), 1054 RING_LEFT(qcn_state), 1055 &retcount); 1056 bufp = RING_ADDR(qcn_state); 1057 if (rv == H_EOK) { 1058 /* 1059 * if the alternate break sequence is enabled, test 1060 * the buffer for the sequence and if it is there, 1061 * enter the debugger. 1062 */ 1063 if (abort_enable == KIOCABORTALTERNATE) { 1064 for (i = 0; i < retcount; i++) { 1065 if (abort_charseq_recognize(*bufp++)) { 1066 abort_sequence_enter( 1067 (char *)NULL); 1068 } 1069 } 1070 } 1071 1072 /* put console input onto stream */ 1073 if (retcount > 0) { 1074 /* 1075 * the characters are already in the ring, 1076 * just update the pointer so the characters 1077 * can be retrieved. 1078 */ 1079 RING_UPD(qcn_state, retcount); 1080 } 1081 } else { 1082 switch (rv) { 1083 1084 case H_EWOULDBLOCK : 1085 /* 1086 * hypervisor cannot handle the request. 1087 * Try again later. 1088 */ 1089 break; 1090 1091 1092 case H_BREAK : 1093 /* 1094 * on break, unless alternate break sequence is 1095 * enabled, enter the debugger 1096 */ 1097 if (abort_enable != KIOCABORTALTERNATE) 1098 abort_sequence_enter((char *)NULL); 1099 break; 1100 1101 case H_HUP : 1102 qcn_state->qcn_hangup = 1; 1103 break; 1104 1105 default : 1106 break; 1107 } 1108 } 1109 } while (rv == H_EOK); 1110 } 1111 1112 static void 1113 qcn_receive_getchr(void) 1114 { 1115 int64_t rv; 1116 uint8_t buf; 1117 1118 do { 1119 rv = hv_cngetchar(&buf); 1120 if (rv == H_EOK) { 1121 if (abort_enable == KIOCABORTALTERNATE) { 1122 if (abort_charseq_recognize(buf)) { 1123 abort_sequence_enter((char *)NULL); 1124 } 1125 } 1126 1127 /* put console input onto stream */ 1128 if (RING_POK(qcn_state, 1)) { 1129 RING_PUT(qcn_state, buf); 1130 } else { 1131 qcn_state->qcn_rbuf_overflow++; 1132 } 1133 } else { 1134 if (rv == H_BREAK) { 1135 if (abort_enable != KIOCABORTALTERNATE) 1136 abort_sequence_enter((char *)NULL); 1137 } 1138 1139 if (rv == H_HUP) { 1140 qcn_state->qcn_hangup = 1; 1141 } 1142 return; 1143 } 1144 } while (rv == H_EOK); 1145 } 1146 1147 #ifdef QCN_POLLING 1148 /*ARGSUSED*/ 1149 static void 1150 qcn_poll_handler(void *unused) 1151 { 1152 mblk_t *mp; 1153 int64_t rv; 1154 uint8_t buf; 1155 int qcn_writeq_flush = 0; 1156 1157 /* LINTED: E_CONSTANT_CONDITION */ 1158 while (1) { 1159 rv = hv_cngetchar(&buf); 1160 if (rv == H_BREAK) { 1161 if (abort_enable != KIOCABORTALTERNATE) 1162 abort_sequence_enter((char *)NULL); 1163 } 1164 1165 if (rv == H_HUP) { 1166 if (qcn_state->qcn_readq) { 1167 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 1168 qcn_writeq_flush = 1; 1169 } 1170 goto out; 1171 } 1172 1173 if (rv != H_EOK) 1174 goto out; 1175 1176 if (abort_enable == KIOCABORTALTERNATE) { 1177 if (abort_charseq_recognize(buf)) { 1178 abort_sequence_enter((char *)NULL); 1179 } 1180 } 1181 1182 /* put console input onto stream */ 1183 if (qcn_state->qcn_readq) { 1184 if ((mp = allocb(1, BPRI_MED)) == NULL) { 1185 qcn_input_dropped++; 1186 cmn_err(CE_WARN, "qcn_intr: allocb" 1187 "failed (console input dropped)"); 1188 return; 1189 } 1190 *(char *)mp->b_wptr++ = buf; 1191 putnext(qcn_state->qcn_readq, mp); 1192 } 1193 } 1194 out: 1195 /* 1196 * If there are pending transmits because hypervisor 1197 * returned EWOULDBLOCK poke start now. 1198 */ 1199 1200 mutex_enter(&qcn_state->qcn_lock); 1201 if (qcn_state->qcn_writeq != NULL) { 1202 if (qcn_writeq_flush) { 1203 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1204 } else { 1205 qcn_start(); 1206 } 1207 } 1208 mutex_exit(&qcn_state->qcn_lock); 1209 } 1210 #endif 1211 1212 /* 1213 * Check for abort character sequence, copied from zs_async.c 1214 */ 1215 #define CNTRL(c) ((c)&037) 1216 1217 static boolean_t 1218 abort_charseq_recognize(uchar_t ch) 1219 { 1220 static int state = 0; 1221 static char sequence[] = { '\r', '~', CNTRL('b') }; 1222 1223 if (ch == sequence[state]) { 1224 if (++state >= sizeof (sequence)) { 1225 state = 0; 1226 return (B_TRUE); 1227 } 1228 } else { 1229 state = (ch == sequence[0]) ? 1 : 0; 1230 } 1231 return (B_FALSE); 1232 } 1233 1234 1235 static int 1236 qcn_rsrv(queue_t *q) 1237 { 1238 mblk_t *mp; 1239 1240 if (qcn_stopped == B_TRUE) 1241 return (0); 1242 1243 mutex_enter(&qcn_state->qcn_lock); 1244 1245 while ((mp = getq(q)) != NULL) { 1246 if (canputnext(q)) 1247 putnext(q, mp); 1248 else if (mp->b_datap->db_type >= QPCTL) 1249 (void) putbq(q, mp); 1250 } 1251 1252 mutex_exit(&qcn_state->qcn_lock); 1253 1254 return (0); 1255 } 1256 1257 /* ARGSUSED */ 1258 static int 1259 qcn_wsrv(queue_t *q) 1260 { 1261 if (qcn_stopped == B_TRUE) 1262 return (0); 1263 1264 mutex_enter(&qcn_state->qcn_lock); 1265 1266 if (qcn_state->qcn_writeq != NULL) 1267 qcn_start(); 1268 1269 mutex_exit(&qcn_state->qcn_lock); 1270 1271 return (0); 1272 } 1273