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