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