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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * sun4v console driver 30 */ 31 32 #include <sys/errno.h> 33 #include <sys/stat.h> 34 #include <sys/kmem.h> 35 #include <sys/conf.h> 36 #include <sys/termios.h> 37 #include <sys/modctl.h> 38 #include <sys/kbio.h> 39 #include <sys/stropts.h> 40 #include <sys/stream.h> 41 #include <sys/strsun.h> 42 #include <sys/sysmacros.h> 43 #include <sys/promif.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/cyclic.h> 47 #include <sys/intr.h> 48 #include <sys/spl.h> 49 #include <sys/qcn.h> 50 #include <sys/hypervisor_api.h> 51 #include <sys/hsvc.h> 52 #include <sys/machsystm.h> 53 #include <sys/consdev.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 /* functions required for polled io */ 79 static boolean_t qcn_polledio_ischar(cons_polledio_arg_t arg); 80 static int qcn_polledio_getchar(cons_polledio_arg_t arg); 81 static void qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c); 82 static void qcn_polledio_enter(cons_polledio_arg_t arg); 83 static void qcn_polledio_exit(cons_polledio_arg_t arg); 84 85 86 static boolean_t abort_charseq_recognize(uchar_t); 87 88 static qcn_t *qcn_state; 89 static uchar_t qcn_stopped = B_FALSE; 90 static int qcn_timeout_period = 20; /* time out in seconds */ 91 size_t qcn_input_dropped; /* dropped input character counter */ 92 93 #ifdef QCN_POLLING 94 static void qcn_poll_handler(void *unused); 95 static cyc_time_t qcn_poll_time; 96 static cyc_handler_t qcn_poll_cychandler = { 97 qcn_poll_handler, 98 NULL, 99 CY_LOW_LEVEL /* XXX need softint to make this high */ 100 }; 101 static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE; 102 static uint64_t qcn_poll_interval = 5; /* milli sec */ 103 static uint64_t sb_interval = 0; 104 uint_t qcn_force_polling = 0; 105 #endif 106 107 #define QCN_MI_IDNUM 0xABCE 108 #define QCN_MI_HIWAT 8192 109 #define QCN_MI_LOWAT 128 110 111 /* streams structures */ 112 static struct module_info minfo = { 113 QCN_MI_IDNUM, /* mi_idnum */ 114 "qcn", /* mi_idname */ 115 0, /* mi_minpsz */ 116 INFPSZ, /* mi_maxpsz */ 117 QCN_MI_HIWAT, /* mi_hiwat */ 118 QCN_MI_LOWAT /* mi_lowat */ 119 }; 120 121 static struct qinit rinit = { 122 putq, /* qi_putp */ 123 qcn_rsrv, /* qi_srvp */ 124 qcn_open, /* qi_qopen */ 125 qcn_close, /* qi_qclose */ 126 NULL, /* qi_qadmin */ 127 &minfo, /* qi_minfo */ 128 NULL /* qi_mstat */ 129 }; 130 131 static struct qinit winit = { 132 qcn_wput, /* qi_putp */ 133 qcn_wsrv, /* qi_srvp */ 134 qcn_open, /* qi_qopen */ 135 qcn_close, /* qi_qclose */ 136 NULL, /* qi_qadmin */ 137 &minfo, /* qi_minfo */ 138 NULL /* qi_mstat */ 139 }; 140 141 static struct streamtab qcnstrinfo = { 142 &rinit, 143 &winit, 144 NULL, 145 NULL 146 }; 147 148 /* standard device driver structures */ 149 static struct cb_ops qcn_cb_ops = { 150 nulldev, /* open() */ 151 nulldev, /* close() */ 152 nodev, /* strategy() */ 153 nodev, /* print() */ 154 nodev, /* dump() */ 155 nodev, /* read() */ 156 nodev, /* write() */ 157 nodev, /* ioctl() */ 158 nodev, /* devmap() */ 159 nodev, /* mmap() */ 160 nodev, /* segmap() */ 161 nochpoll, /* poll() */ 162 ddi_prop_op, /* prop_op() */ 163 &qcnstrinfo, /* cb_str */ 164 D_NEW | D_MP /* cb_flag */ 165 }; 166 167 static struct dev_ops qcn_ops = { 168 DEVO_REV, 169 0, /* refcnt */ 170 qcn_getinfo, /* getinfo() */ 171 nulldev, /* identify() */ 172 nulldev, /* probe() */ 173 qcn_attach, /* attach() */ 174 qcn_detach, /* detach() */ 175 nodev, /* reset() */ 176 &qcn_cb_ops, /* cb_ops */ 177 (struct bus_ops *)NULL, /* bus_ops */ 178 NULL, /* power() */ 179 ddi_quiesce_not_needed, /* quiesce() */ 180 }; 181 182 static struct modldrv modldrv = { 183 &mod_driverops, 184 "sun4v console driver", 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 mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER, 420 (void *)(uintptr_t)(qcn_state->qcn_intr_pri)); 421 } 422 423 mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL); 424 425 /* 426 * Fill in the polled I/O structure. 427 */ 428 qcn_state->qcn_polledio.cons_polledio_version = CONSPOLLEDIO_V1; 429 qcn_state->qcn_polledio.cons_polledio_argument = 430 (cons_polledio_arg_t)qcn_state; 431 qcn_state->qcn_polledio.cons_polledio_putchar = qcn_polledio_putchar; 432 qcn_state->qcn_polledio.cons_polledio_getchar = qcn_polledio_getchar; 433 qcn_state->qcn_polledio.cons_polledio_ischar = qcn_polledio_ischar; 434 qcn_state->qcn_polledio.cons_polledio_enter = qcn_polledio_enter; 435 qcn_state->qcn_polledio.cons_polledio_exit = qcn_polledio_exit; 436 437 /* 438 * Enable interrupts 439 */ 440 if (!qcn_state->qcn_polling) { 441 qcn_intr_enable(); 442 } 443 #ifdef QCN_DEBUG 444 prom_printf("qcn_attach(): qcn driver attached\n"); 445 #endif 446 447 return (DDI_SUCCESS); 448 449 } 450 451 /* ARGSUSED */ 452 static int 453 qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 454 { 455 456 if (cmd != DDI_DETACH) 457 return (DDI_FAILURE); 458 459 460 #ifdef QCN_DEBUG 461 prom_printf("qcn_detach(): QCN driver detached\n"); 462 #endif 463 464 #ifdef QCN_POLLING 465 if (qcn_state->qcn_polling) { 466 mutex_enter(&cpu_lock); 467 if (qcn_poll_cycid != CYCLIC_NONE) 468 cyclic_remove(qcn_poll_cycid); 469 qcn_poll_cycid = CYCLIC_NONE; 470 mutex_exit(&cpu_lock); 471 } 472 #endif 473 474 if (!qcn_state->qcn_polling) 475 qcn_remove_intrs(); 476 477 return (DDI_SUCCESS); 478 } 479 480 /* ARGSUSED */ 481 static int 482 qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 483 { 484 int error = DDI_FAILURE; 485 int instance = 0; 486 switch (infocmd) { 487 case DDI_INFO_DEVT2DEVINFO: 488 if (qcn_state) { 489 #ifdef QCN_DEBUG 490 prom_printf("qcn_getinfo(): devt2dip %lx\n", arg); 491 #endif 492 *result = (void *)qcn_state->qcn_dip; 493 error = DDI_SUCCESS; 494 } 495 break; 496 497 case DDI_INFO_DEVT2INSTANCE: 498 #ifdef QCN_DEBUG 499 prom_printf("qcn_getinfo(): devt2instance %lx\n", arg); 500 #endif 501 if (getminor((dev_t)arg) == 0) { 502 *result = (void *)(uintptr_t)instance; 503 error = DDI_SUCCESS; 504 } 505 break; 506 } 507 508 return (error); 509 } 510 511 /* streams open & close */ 512 /* ARGSUSED */ 513 static int 514 qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 515 { 516 tty_common_t *tty; 517 int unit = getminor(*devp); 518 519 #ifdef QCN_DEBUG 520 prom_printf("qcn_open(): minor %x\n", unit); 521 #endif 522 523 if (unit != 0) 524 return (ENXIO); 525 526 /* stream already open */ 527 if (q->q_ptr != NULL) 528 return (DDI_SUCCESS); 529 530 if (!qcn_state) { 531 cmn_err(CE_WARN, "qcn_open: console was not configured by " 532 "autoconfig\n"); 533 return (ENXIO); 534 } 535 536 mutex_enter(&qcn_state->qcn_lock); 537 tty = &(qcn_state->qcn_tty); 538 539 tty->t_readq = q; 540 tty->t_writeq = WR(q); 541 542 /* Link the RD and WR Q's */ 543 q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state; 544 qcn_state->qcn_readq = RD(q); 545 qcn_state->qcn_writeq = WR(q); 546 qprocson(q); 547 548 mutex_exit(&qcn_state->qcn_lock); 549 550 #ifdef QCN_DEBUG 551 prom_printf("qcn_open: opened as dev %lx\n", *devp); 552 #endif 553 554 return (DDI_SUCCESS); 555 } 556 557 /* ARGSUSED */ 558 static int 559 qcn_close(queue_t *q, int flag, cred_t *credp) 560 { 561 562 ASSERT(qcn_state == q->q_ptr); 563 564 if (qcn_state->qcn_wbufcid != 0) { 565 unbufcall(qcn_state->qcn_wbufcid); 566 } 567 ttycommon_close(&qcn_state->qcn_tty); 568 569 qprocsoff(q); 570 q->q_ptr = WR(q)->q_ptr = NULL; 571 qcn_state->qcn_readq = NULL; 572 qcn_state->qcn_writeq = NULL; 573 574 return (DDI_SUCCESS); 575 } 576 577 /* 578 * Put procedure for write queue. 579 * Respond to M_IOCTL, M_DATA and M_FLUSH messages here; 580 * It put's the data onto internal qcn_output_q. 581 */ 582 static int 583 qcn_wput(queue_t *q, mblk_t *mp) 584 { 585 586 #ifdef QCN_DEBUG 587 struct iocblk *iocp; 588 int i; 589 #endif 590 591 ASSERT(qcn_state == q->q_ptr); 592 593 if (!mp->b_datap) { 594 cmn_err(CE_PANIC, "qcn_wput: null datap"); 595 } 596 597 #ifdef QCN_DEBUG 598 prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n", 599 q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type); 600 #endif 601 602 mutex_enter(&qcn_state->qcn_lock); 603 604 switch (mp->b_datap->db_type) { 605 case M_IOCTL: 606 case M_CTL: 607 #ifdef QCN_DEBUG 608 iocp = (struct iocblk *)mp->b_rptr; 609 prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n", 610 iocp->ioc_cmd, TIOC); 611 #endif 612 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 613 case TCSETSW: 614 case TCSETSF: 615 case TCSETAW: 616 case TCSETAF: 617 case TCSBRK: 618 /* 619 * The change do not take effect until all 620 * output queued before them is drained. 621 * Put this message on the queue, so that 622 * "qcn_start" will see it when it's done 623 * with the output before it. Poke the start 624 * routine, just in case. 625 */ 626 (void) putq(q, mp); 627 qcn_start(); 628 break; 629 default: 630 mutex_exit(&qcn_state->qcn_lock); 631 qcn_ioctl(q, mp); 632 mutex_enter(&qcn_state->qcn_lock); 633 } 634 break; 635 636 case M_FLUSH: 637 if (*mp->b_rptr & FLUSHW) { 638 flushq(q, FLUSHDATA); 639 *mp->b_rptr &= ~FLUSHW; 640 } 641 if (*mp->b_rptr & FLUSHR) { 642 flushq(RD(q), FLUSHDATA); 643 qreply(q, mp); 644 } else { 645 freemsg(mp); 646 } 647 break; 648 649 case M_STOP: 650 qcn_stopped = B_TRUE; 651 freemsg(mp); 652 break; 653 654 case M_START: 655 qcn_stopped = B_FALSE; 656 freemsg(mp); 657 qenable(q); /* Start up delayed messages */ 658 break; 659 660 case M_DATA: 661 /* 662 * Queue the message up to be transmitted, 663 * and poke the start routine. 664 */ 665 #ifdef QCN_DEBUG 666 if (mp->b_rptr < mp->b_wptr) { 667 prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 668 q, mp, mp->b_rptr, mp->b_wptr); 669 prom_printf("qcn_wput(): ["); 670 for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 671 prom_printf("%c", *(mp->b_rptr+i)); 672 } 673 prom_printf("]\n"); 674 } 675 #endif /* QCN_DEBUG */ 676 (void) putq(q, mp); 677 qcn_start(); 678 break; 679 680 default: 681 freemsg(mp); 682 } 683 684 mutex_exit(&qcn_state->qcn_lock); 685 686 return (0); 687 } 688 689 /* 690 * Process an "ioctl" message sent down to us. 691 */ 692 static void 693 qcn_ioctl(queue_t *q, mblk_t *mp) 694 { 695 struct iocblk *iocp; 696 tty_common_t *tty; 697 mblk_t *datamp; 698 int data_size; 699 int error = 0; 700 701 #ifdef QCN_DEBUG 702 prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp); 703 #endif 704 705 iocp = (struct iocblk *)mp->b_rptr; 706 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 714 /* 715 * Handle the POLLEDIO ioctls now because ttycommon_ioctl 716 * (below) frees up the message block (mp->b_cont) which 717 * contains the pointer used to pass back results. 718 */ 719 switch (iocp->ioc_cmd) { 720 case CONSOPENPOLLEDIO: 721 error = miocpullup(mp, sizeof (struct cons_polledio *)); 722 if (error != 0) 723 break; 724 725 *(struct cons_polledio **)mp->b_cont->b_rptr = 726 &qcn_state->qcn_polledio; 727 728 mp->b_datap->db_type = M_IOCACK; 729 break; 730 731 case CONSCLOSEPOLLEDIO: 732 mp->b_datap->db_type = M_IOCACK; 733 iocp->ioc_error = 0; 734 iocp->ioc_rval = 0; 735 break; 736 737 default: 738 data_size = ttycommon_ioctl(tty, q, mp, &error); 739 if (data_size != 0) { 740 if (qcn_state->qcn_wbufcid) 741 unbufcall(qcn_state->qcn_wbufcid); 742 /* call qcn_reioctl() */ 743 qcn_state->qcn_wbufcid = 744 bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state); 745 return; 746 } 747 } 748 749 mutex_enter(&qcn_state->qcn_lock); 750 751 if (error < 0) { 752 iocp = (struct iocblk *)mp->b_rptr; 753 /* 754 * "ttycommon_ioctl" didn't do anything; we process it here. 755 */ 756 error = 0; 757 switch (iocp->ioc_cmd) { 758 case TCSBRK: 759 case TIOCSBRK: 760 case TIOCCBRK: 761 case TIOCMSET: 762 case TIOCMBIS: 763 case TIOCMBIC: 764 if (iocp->ioc_count != TRANSPARENT) 765 qcn_ack(mp, NULL, 0); 766 else 767 mcopyin(mp, NULL, sizeof (int), NULL); 768 break; 769 770 case TIOCMGET: 771 datamp = allocb(sizeof (int), BPRI_MED); 772 if (datamp == NULL) { 773 error = EAGAIN; 774 break; 775 } 776 777 *(int *)datamp->b_rptr = 0; 778 779 if (iocp->ioc_count != TRANSPARENT) 780 qcn_ack(mp, datamp, sizeof (int)); 781 else 782 mcopyout(mp, NULL, sizeof (int), NULL, datamp); 783 break; 784 785 default: 786 error = EINVAL; 787 break; 788 } 789 } 790 if (error != 0) { 791 iocp->ioc_count = 0; 792 iocp->ioc_error = error; 793 mp->b_datap->db_type = M_IOCNAK; 794 } 795 mutex_exit(&qcn_state->qcn_lock); 796 qreply(q, mp); 797 } 798 799 static void 800 qcn_reioctl(void *unit) 801 { 802 queue_t *q; 803 mblk_t *mp; 804 qcn_t *qcnp = (qcn_t *)unit; 805 806 if (!qcnp->qcn_wbufcid) 807 return; 808 809 qcnp->qcn_wbufcid = 0; 810 if ((q = qcnp->qcn_tty.t_writeq) == NULL) 811 return; 812 813 if ((mp = qcnp->qcn_tty.t_iocpending) == NULL) 814 return; 815 816 qcnp->qcn_tty.t_iocpending = NULL; 817 qcn_ioctl(q, mp); 818 } 819 820 static void 821 qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size) 822 { 823 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 824 825 mp->b_datap->db_type = M_IOCACK; 826 iocp->ioc_count = size; 827 iocp->ioc_error = 0; 828 iocp->ioc_rval = 0; 829 if (mp->b_cont != NULL) 830 freeb(mp->b_cont); 831 if (dp != NULL) { 832 mp->b_cont = dp; 833 dp->b_wptr += size; 834 } else 835 mp->b_cont = NULL; 836 } 837 838 static void 839 qcn_start(void) 840 { 841 842 queue_t *q; 843 mblk_t *mp; 844 int rv; 845 846 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 847 848 /* 849 * read stream queue and remove data from the queue and 850 * transmit them if possible 851 */ 852 q = qcn_state->qcn_writeq; 853 ASSERT(q != NULL); 854 while (mp = getq(q)) { 855 if (mp->b_datap->db_type == M_IOCTL) { 856 /* 857 * These are those IOCTLs queued up 858 * do it now 859 */ 860 mutex_exit(&qcn_state->qcn_lock); 861 qcn_ioctl(q, mp); 862 mutex_enter(&qcn_state->qcn_lock); 863 continue; 864 } 865 /* 866 * M_DATA 867 */ 868 rv = qcn_state->cons_transmit(q, mp); 869 if (rv == EBUSY || rv == EAGAIN) 870 return; 871 } 872 } 873 874 static int 875 qcn_transmit_write(queue_t *q, mblk_t *mp) 876 { 877 mblk_t *bp; 878 size_t len; 879 uint64_t i; 880 uint64_t retval = 0; 881 882 #ifdef QCN_DEBUG 883 prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp); 884 #endif 885 886 while (mp) { 887 bp = mp; 888 len = bp->b_wptr - bp->b_rptr; 889 /* 890 * Use the console write call to send a block of characters to 891 * the console. 892 */ 893 i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len; 894 bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i); 895 retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i); 896 897 if (retval == H_EOK) { 898 len -= i; 899 bp->b_rptr += i; 900 /* 901 * if we have finished with this buf, free 902 * and get the next buf if present. 903 */ 904 if (len == 0) { 905 mp = bp->b_cont; 906 freeb(bp); 907 } 908 } else { 909 (void) putbq(q, mp); 910 911 switch (retval) { 912 913 case H_EWOULDBLOCK : 914 /* 915 * hypervisor cannot process the request - 916 * channel busy. Try again later. 917 */ 918 return (EAGAIN); 919 920 case H_EIO : 921 return (EIO); 922 default : 923 return (ENXIO); 924 } 925 } 926 } 927 return (0); 928 } 929 930 static int 931 qcn_transmit_putchr(queue_t *q, mblk_t *mp) 932 { 933 caddr_t buf; 934 mblk_t *bp; 935 size_t len; 936 uint64_t i; 937 938 #ifdef QCN_DEBUG 939 prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp); 940 #endif 941 while (mp) { 942 bp = mp; 943 len = bp->b_wptr - bp->b_rptr; 944 buf = (caddr_t)bp->b_rptr; 945 for (i = 0; i < len; i++) { 946 if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK) 947 break; 948 } 949 if (i != len) { 950 bp->b_rptr += i; 951 (void) putbq(q, mp); 952 return (EAGAIN); 953 } 954 mp = bp->b_cont; 955 freeb(bp); 956 } 957 return (0); 958 } 959 960 /* 961 * called when SC first establishes console connection 962 * drop all the data on the output queue 963 */ 964 static void 965 qcn_flush(void) 966 { 967 queue_t *q; 968 mblk_t *mp; 969 970 ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 971 972 q = qcn_state->qcn_writeq; 973 974 prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n", 975 gethrestime_sec()); 976 while (mp = getq(q)) 977 freemsg(mp); 978 } 979 980 static void 981 qcn_trigger_softint(void) 982 { 983 /* 984 * if we are not currently servicing a software interrupt 985 * (qcn_soft_pend == 0), trigger the service routine to run. 986 */ 987 if (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_DO) == 988 QCN_SP_IDL) { 989 (void) ddi_intr_trigger_softint( 990 qcn_state->qcn_softint_hdl, NULL); 991 } 992 } 993 994 /*ARGSUSED*/ 995 static uint_t 996 qcn_soft_intr(caddr_t arg1, caddr_t arg2) 997 { 998 mblk_t *mp; 999 int cc; 1000 int overflow_check; 1001 1002 do { 1003 (void) atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IP); 1004 mutex_enter(&qcn_state->qcn_hi_lock); 1005 cc = RING_CNT(qcn_state); 1006 mutex_exit(&qcn_state->qcn_hi_lock); 1007 if (cc <= 0) { 1008 goto out; 1009 } 1010 1011 if ((mp = allocb(cc, BPRI_MED)) == NULL) { 1012 mutex_enter(&qcn_state->qcn_hi_lock); 1013 qcn_input_dropped += cc; 1014 mutex_exit(&qcn_state->qcn_hi_lock); 1015 cmn_err(CE_WARN, "qcn_intr: allocb" 1016 "failed (console input dropped)"); 1017 goto out; 1018 } 1019 1020 mutex_enter(&qcn_state->qcn_hi_lock); 1021 do { 1022 /* put console input onto stream */ 1023 *(char *)mp->b_wptr++ = RING_GET(qcn_state); 1024 } while (--cc); 1025 1026 if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) { 1027 qcn_state->qcn_rbuf_overflow = 0; 1028 } 1029 mutex_exit(&qcn_state->qcn_hi_lock); 1030 1031 if (overflow_check) { 1032 cmn_err(CE_WARN, "qcn: Ring buffer overflow\n"); 1033 } 1034 1035 if (qcn_state->qcn_readq) { 1036 putnext(qcn_state->qcn_readq, mp); 1037 } 1038 out: 1039 /* 1040 * If there are pending transmits because hypervisor 1041 * returned EWOULDBLOCK poke start now. 1042 */ 1043 1044 if (qcn_state->qcn_writeq != NULL) { 1045 if (qcn_state->qcn_hangup) { 1046 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 1047 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1048 qcn_state->qcn_hangup = 0; 1049 } else { 1050 mutex_enter(&qcn_state->qcn_lock); 1051 qcn_start(); 1052 mutex_exit(&qcn_state->qcn_lock); 1053 } 1054 } 1055 /* 1056 * now loop if another interrupt came in (qcn_trigger_softint 1057 * called) while we were processing the loop 1058 */ 1059 } while (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IDL) == 1060 QCN_SP_DO); 1061 return (DDI_INTR_CLAIMED); 1062 } 1063 1064 /*ARGSUSED*/ 1065 static uint_t 1066 qcn_hi_intr(caddr_t arg) 1067 { 1068 mutex_enter(&qcn_state->qcn_hi_lock); 1069 1070 qcn_state->cons_receive(); 1071 1072 mutex_exit(&qcn_state->qcn_hi_lock); 1073 qcn_trigger_softint(); 1074 1075 return (DDI_INTR_CLAIMED); 1076 } 1077 1078 static void 1079 qcn_receive_read(void) 1080 { 1081 int64_t rv; 1082 uint8_t *bufp; 1083 int64_t retcount = 0; 1084 int i; 1085 1086 do { 1087 /* 1088 * Maximize available buffer size 1089 */ 1090 if (RING_CNT(qcn_state) <= 0) { 1091 RING_INIT(qcn_state); 1092 } 1093 rv = hv_cnread(qcn_state->cons_read_buf_ra + 1094 RING_POFF(qcn_state), 1095 RING_LEFT(qcn_state), 1096 &retcount); 1097 bufp = RING_ADDR(qcn_state); 1098 if (rv == H_EOK) { 1099 /* 1100 * if the alternate break sequence is enabled, test 1101 * the buffer for the sequence and if it is there, 1102 * enter the debugger. 1103 */ 1104 if (abort_enable == KIOCABORTALTERNATE) { 1105 for (i = 0; i < retcount; i++) { 1106 if (abort_charseq_recognize(*bufp++)) { 1107 abort_sequence_enter( 1108 (char *)NULL); 1109 } 1110 } 1111 } 1112 1113 /* put console input onto stream */ 1114 if (retcount > 0) { 1115 /* 1116 * the characters are already in the ring, 1117 * just update the pointer so the characters 1118 * can be retrieved. 1119 */ 1120 RING_UPD(qcn_state, retcount); 1121 } 1122 } else { 1123 switch (rv) { 1124 1125 case H_EWOULDBLOCK : 1126 /* 1127 * hypervisor cannot handle the request. 1128 * Try again later. 1129 */ 1130 break; 1131 1132 1133 case H_BREAK : 1134 /* 1135 * on break, unless alternate break sequence is 1136 * enabled, enter the debugger 1137 */ 1138 if (abort_enable != KIOCABORTALTERNATE) 1139 abort_sequence_enter((char *)NULL); 1140 break; 1141 1142 case H_HUP : 1143 qcn_state->qcn_hangup = 1; 1144 break; 1145 1146 default : 1147 break; 1148 } 1149 } 1150 } while (rv == H_EOK); 1151 } 1152 1153 static void 1154 qcn_receive_getchr(void) 1155 { 1156 int64_t rv; 1157 uint8_t buf; 1158 1159 do { 1160 rv = hv_cngetchar(&buf); 1161 if (rv == H_EOK) { 1162 if (abort_enable == KIOCABORTALTERNATE) { 1163 if (abort_charseq_recognize(buf)) { 1164 abort_sequence_enter((char *)NULL); 1165 } 1166 } 1167 1168 /* put console input onto stream */ 1169 if (RING_POK(qcn_state, 1)) { 1170 RING_PUT(qcn_state, buf); 1171 } else { 1172 qcn_state->qcn_rbuf_overflow++; 1173 } 1174 } else { 1175 if (rv == H_BREAK) { 1176 if (abort_enable != KIOCABORTALTERNATE) 1177 abort_sequence_enter((char *)NULL); 1178 } 1179 1180 if (rv == H_HUP) { 1181 qcn_state->qcn_hangup = 1; 1182 } 1183 return; 1184 } 1185 } while (rv == H_EOK); 1186 } 1187 1188 #ifdef QCN_POLLING 1189 /*ARGSUSED*/ 1190 static void 1191 qcn_poll_handler(void *unused) 1192 { 1193 mblk_t *mp; 1194 int64_t rv; 1195 uint8_t buf; 1196 int qcn_writeq_flush = 0; 1197 1198 /* LINTED: E_CONSTANT_CONDITION */ 1199 while (1) { 1200 rv = hv_cngetchar(&buf); 1201 if (rv == H_BREAK) { 1202 if (abort_enable != KIOCABORTALTERNATE) 1203 abort_sequence_enter((char *)NULL); 1204 } 1205 1206 if (rv == H_HUP) { 1207 if (qcn_state->qcn_readq) { 1208 (void) putctl(qcn_state->qcn_readq, M_HANGUP); 1209 qcn_writeq_flush = 1; 1210 } 1211 goto out; 1212 } 1213 1214 if (rv != H_EOK) 1215 goto out; 1216 1217 if (abort_enable == KIOCABORTALTERNATE) { 1218 if (abort_charseq_recognize(buf)) { 1219 abort_sequence_enter((char *)NULL); 1220 } 1221 } 1222 1223 /* put console input onto stream */ 1224 if (qcn_state->qcn_readq) { 1225 if ((mp = allocb(1, BPRI_MED)) == NULL) { 1226 qcn_input_dropped++; 1227 cmn_err(CE_WARN, "qcn_intr: allocb" 1228 "failed (console input dropped)"); 1229 return; 1230 } 1231 *(char *)mp->b_wptr++ = buf; 1232 putnext(qcn_state->qcn_readq, mp); 1233 } 1234 } 1235 out: 1236 /* 1237 * If there are pending transmits because hypervisor 1238 * returned EWOULDBLOCK poke start now. 1239 */ 1240 1241 mutex_enter(&qcn_state->qcn_lock); 1242 if (qcn_state->qcn_writeq != NULL) { 1243 if (qcn_writeq_flush) { 1244 flushq(qcn_state->qcn_writeq, FLUSHDATA); 1245 } else { 1246 qcn_start(); 1247 } 1248 } 1249 mutex_exit(&qcn_state->qcn_lock); 1250 } 1251 #endif 1252 1253 /* 1254 * Check for abort character sequence, copied from zs_async.c 1255 */ 1256 #define CNTRL(c) ((c)&037) 1257 1258 static boolean_t 1259 abort_charseq_recognize(uchar_t ch) 1260 { 1261 static int state = 0; 1262 static char sequence[] = { '\r', '~', CNTRL('b') }; 1263 1264 if (ch == sequence[state]) { 1265 if (++state >= sizeof (sequence)) { 1266 state = 0; 1267 return (B_TRUE); 1268 } 1269 } else { 1270 state = (ch == sequence[0]) ? 1 : 0; 1271 } 1272 return (B_FALSE); 1273 } 1274 1275 1276 static int 1277 qcn_rsrv(queue_t *q) 1278 { 1279 mblk_t *mp; 1280 1281 if (qcn_stopped == B_TRUE) 1282 return (0); 1283 1284 mutex_enter(&qcn_state->qcn_lock); 1285 1286 while ((mp = getq(q)) != NULL) { 1287 if (canputnext(q)) 1288 putnext(q, mp); 1289 else if (mp->b_datap->db_type >= QPCTL) 1290 (void) putbq(q, mp); 1291 } 1292 1293 mutex_exit(&qcn_state->qcn_lock); 1294 1295 return (0); 1296 } 1297 1298 /* ARGSUSED */ 1299 static int 1300 qcn_wsrv(queue_t *q) 1301 { 1302 if (qcn_stopped == B_TRUE) 1303 return (0); 1304 1305 mutex_enter(&qcn_state->qcn_lock); 1306 1307 if (qcn_state->qcn_writeq != NULL) 1308 qcn_start(); 1309 1310 mutex_exit(&qcn_state->qcn_lock); 1311 1312 return (0); 1313 } 1314 1315 static boolean_t 1316 qcn_polledio_ischar(cons_polledio_arg_t arg) 1317 { 1318 qcn_t *state = (qcn_t *)arg; 1319 1320 if (state->qcn_char_available) 1321 return (B_TRUE); 1322 1323 return (state->qcn_char_available = 1324 (hv_cngetchar(&state->qcn_hold_char) == H_EOK)); 1325 } 1326 1327 1328 static int 1329 qcn_polledio_getchar(cons_polledio_arg_t arg) 1330 { 1331 qcn_t *state = (qcn_t *)arg; 1332 1333 while (!qcn_polledio_ischar(arg)) 1334 drv_usecwait(10); 1335 1336 state->qcn_char_available = B_FALSE; 1337 1338 return ((int)state->qcn_hold_char); 1339 } 1340 1341 static void 1342 qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c) 1343 { 1344 if (c == '\n') 1345 qcn_polledio_putchar(arg, '\r'); 1346 1347 while (hv_cnputchar((uint8_t)c) == H_EWOULDBLOCK) 1348 drv_usecwait(10); 1349 } 1350 1351 static void 1352 qcn_polledio_enter(cons_polledio_arg_t arg) 1353 { 1354 qcn_t *state = (qcn_t *)arg; 1355 1356 state->qcn_char_available = B_FALSE; 1357 } 1358 1359 /* ARGSUSED */ 1360 static void 1361 qcn_polledio_exit(cons_polledio_arg_t arg) 1362 { 1363 } 1364