1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * sun4v console driver 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/intr.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/spl.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/qcn.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h> 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* dev_ops and cb_ops for device driver */ 54*7c478bd9Sstevel@tonic-gate static int qcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 55*7c478bd9Sstevel@tonic-gate static int qcn_attach(dev_info_t *, ddi_attach_cmd_t); 56*7c478bd9Sstevel@tonic-gate static int qcn_detach(dev_info_t *, ddi_detach_cmd_t); 57*7c478bd9Sstevel@tonic-gate static int qcn_open(queue_t *, dev_t *, int, int, cred_t *); 58*7c478bd9Sstevel@tonic-gate static int qcn_close(queue_t *, int, cred_t *); 59*7c478bd9Sstevel@tonic-gate static int qcn_wput(queue_t *, mblk_t *); 60*7c478bd9Sstevel@tonic-gate static int qcn_wsrv(queue_t *); 61*7c478bd9Sstevel@tonic-gate static int qcn_rsrv(queue_t *); 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* other internal qcn routines */ 64*7c478bd9Sstevel@tonic-gate static void qcn_ioctl(queue_t *, mblk_t *); 65*7c478bd9Sstevel@tonic-gate static void qcn_reioctl(void *); 66*7c478bd9Sstevel@tonic-gate static void qcn_ack(mblk_t *, mblk_t *, uint_t); 67*7c478bd9Sstevel@tonic-gate static void qcn_start(void); 68*7c478bd9Sstevel@tonic-gate static int qcn_transmit(queue_t *, mblk_t *); 69*7c478bd9Sstevel@tonic-gate static void qcn_flush(void); 70*7c478bd9Sstevel@tonic-gate static uint_t qcn_hi_intr(caddr_t arg); 71*7c478bd9Sstevel@tonic-gate static uint_t qcn_soft_intr(caddr_t arg1, caddr_t arg2); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t); 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static qcn_t *qcn_state; 76*7c478bd9Sstevel@tonic-gate static uchar_t qcn_stopped = B_FALSE; 77*7c478bd9Sstevel@tonic-gate static int qcn_timeout_period = 20; /* time out in seconds */ 78*7c478bd9Sstevel@tonic-gate size_t qcn_input_dropped; /* dropped input character counter */ 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate #ifdef QCN_POLLING 81*7c478bd9Sstevel@tonic-gate static void qcn_poll_handler(void *unused); 82*7c478bd9Sstevel@tonic-gate static cyc_time_t qcn_poll_time; 83*7c478bd9Sstevel@tonic-gate static cyc_handler_t qcn_poll_cychandler = { 84*7c478bd9Sstevel@tonic-gate qcn_poll_handler, 85*7c478bd9Sstevel@tonic-gate NULL, 86*7c478bd9Sstevel@tonic-gate CY_LOW_LEVEL /* XXX need softint to make this high */ 87*7c478bd9Sstevel@tonic-gate }; 88*7c478bd9Sstevel@tonic-gate static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE; 89*7c478bd9Sstevel@tonic-gate static uint64_t qcn_poll_interval = 5; /* milli sec */ 90*7c478bd9Sstevel@tonic-gate static uint64_t sb_interval = 0; 91*7c478bd9Sstevel@tonic-gate #endif 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate #define QCN_MI_IDNUM 0xABCE 94*7c478bd9Sstevel@tonic-gate #define QCN_MI_HIWAT 8192 95*7c478bd9Sstevel@tonic-gate #define QCN_MI_LOWAT 128 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* streams structures */ 98*7c478bd9Sstevel@tonic-gate static struct module_info minfo = { 99*7c478bd9Sstevel@tonic-gate QCN_MI_IDNUM, /* mi_idnum */ 100*7c478bd9Sstevel@tonic-gate "qcn", /* mi_idname */ 101*7c478bd9Sstevel@tonic-gate 0, /* mi_minpsz */ 102*7c478bd9Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 103*7c478bd9Sstevel@tonic-gate QCN_MI_HIWAT, /* mi_hiwat */ 104*7c478bd9Sstevel@tonic-gate QCN_MI_LOWAT /* mi_lowat */ 105*7c478bd9Sstevel@tonic-gate }; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate static struct qinit rinit = { 108*7c478bd9Sstevel@tonic-gate putq, /* qi_putp */ 109*7c478bd9Sstevel@tonic-gate qcn_rsrv, /* qi_srvp */ 110*7c478bd9Sstevel@tonic-gate qcn_open, /* qi_qopen */ 111*7c478bd9Sstevel@tonic-gate qcn_close, /* qi_qclose */ 112*7c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 113*7c478bd9Sstevel@tonic-gate &minfo, /* qi_minfo */ 114*7c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 115*7c478bd9Sstevel@tonic-gate }; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate static struct qinit winit = { 118*7c478bd9Sstevel@tonic-gate qcn_wput, /* qi_putp */ 119*7c478bd9Sstevel@tonic-gate qcn_wsrv, /* qi_srvp */ 120*7c478bd9Sstevel@tonic-gate qcn_open, /* qi_qopen */ 121*7c478bd9Sstevel@tonic-gate qcn_close, /* qi_qclose */ 122*7c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 123*7c478bd9Sstevel@tonic-gate &minfo, /* qi_minfo */ 124*7c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 125*7c478bd9Sstevel@tonic-gate }; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate static struct streamtab qcnstrinfo = { 128*7c478bd9Sstevel@tonic-gate &rinit, 129*7c478bd9Sstevel@tonic-gate &winit, 130*7c478bd9Sstevel@tonic-gate NULL, 131*7c478bd9Sstevel@tonic-gate NULL 132*7c478bd9Sstevel@tonic-gate }; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /* standard device driver structures */ 135*7c478bd9Sstevel@tonic-gate static struct cb_ops qcn_cb_ops = { 136*7c478bd9Sstevel@tonic-gate nulldev, /* open() */ 137*7c478bd9Sstevel@tonic-gate nulldev, /* close() */ 138*7c478bd9Sstevel@tonic-gate nodev, /* strategy() */ 139*7c478bd9Sstevel@tonic-gate nodev, /* print() */ 140*7c478bd9Sstevel@tonic-gate nodev, /* dump() */ 141*7c478bd9Sstevel@tonic-gate nodev, /* read() */ 142*7c478bd9Sstevel@tonic-gate nodev, /* write() */ 143*7c478bd9Sstevel@tonic-gate nodev, /* ioctl() */ 144*7c478bd9Sstevel@tonic-gate nodev, /* devmap() */ 145*7c478bd9Sstevel@tonic-gate nodev, /* mmap() */ 146*7c478bd9Sstevel@tonic-gate nodev, /* segmap() */ 147*7c478bd9Sstevel@tonic-gate nochpoll, /* poll() */ 148*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op() */ 149*7c478bd9Sstevel@tonic-gate &qcnstrinfo, /* cb_str */ 150*7c478bd9Sstevel@tonic-gate D_NEW | D_MP /* cb_flag */ 151*7c478bd9Sstevel@tonic-gate }; 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate static struct dev_ops qcn_ops = { 154*7c478bd9Sstevel@tonic-gate DEVO_REV, 155*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 156*7c478bd9Sstevel@tonic-gate qcn_getinfo, /* getinfo() */ 157*7c478bd9Sstevel@tonic-gate nulldev, /* identify() */ 158*7c478bd9Sstevel@tonic-gate nulldev, /* probe() */ 159*7c478bd9Sstevel@tonic-gate qcn_attach, /* attach() */ 160*7c478bd9Sstevel@tonic-gate qcn_detach, /* detach() */ 161*7c478bd9Sstevel@tonic-gate nodev, /* reset() */ 162*7c478bd9Sstevel@tonic-gate &qcn_cb_ops, /* cb_ops */ 163*7c478bd9Sstevel@tonic-gate (struct bus_ops *)NULL, /* bus_ops */ 164*7c478bd9Sstevel@tonic-gate NULL /* power() */ 165*7c478bd9Sstevel@tonic-gate }; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 168*7c478bd9Sstevel@tonic-gate &mod_driverops, 169*7c478bd9Sstevel@tonic-gate "sun4v console driver v%I%", 170*7c478bd9Sstevel@tonic-gate &qcn_ops 171*7c478bd9Sstevel@tonic-gate }; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 174*7c478bd9Sstevel@tonic-gate MODREV_1, 175*7c478bd9Sstevel@tonic-gate (void*)&modldrv, 176*7c478bd9Sstevel@tonic-gate NULL 177*7c478bd9Sstevel@tonic-gate }; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* driver configuration routines */ 181*7c478bd9Sstevel@tonic-gate int 182*7c478bd9Sstevel@tonic-gate _init(void) 183*7c478bd9Sstevel@tonic-gate { 184*7c478bd9Sstevel@tonic-gate int error; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate qcn_state = kmem_zalloc(sizeof (qcn_t), KM_SLEEP); 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate error = mod_install(&modlinkage); 189*7c478bd9Sstevel@tonic-gate if (error != 0) 190*7c478bd9Sstevel@tonic-gate kmem_free(qcn_state, sizeof (qcn_t)); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate return (error); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate int 196*7c478bd9Sstevel@tonic-gate _fini(void) 197*7c478bd9Sstevel@tonic-gate { 198*7c478bd9Sstevel@tonic-gate /* can't remove console driver */ 199*7c478bd9Sstevel@tonic-gate return (EBUSY); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate int 203*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate static int 209*7c478bd9Sstevel@tonic-gate qcn_add_intrs(void) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate dev_info_t *devinfo = qcn_state->qcn_dip; 212*7c478bd9Sstevel@tonic-gate int actual, count = 0; 213*7c478bd9Sstevel@tonic-gate int x, y, rc, inum = 0; 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* get number of interrupts */ 217*7c478bd9Sstevel@tonic-gate rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count); 218*7c478bd9Sstevel@tonic-gate if ((rc != DDI_SUCCESS) || (count == 0)) { 219*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate /* Allocate an array of interrupt handles */ 223*7c478bd9Sstevel@tonic-gate qcn_state->qcn_intr_size = count * sizeof (ddi_intr_handle_t); 224*7c478bd9Sstevel@tonic-gate qcn_state->qcn_htable = kmem_zalloc(qcn_state->qcn_intr_size, KM_SLEEP); 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* call ddi_intr_alloc() */ 227*7c478bd9Sstevel@tonic-gate rc = ddi_intr_alloc(devinfo, qcn_state->qcn_htable, 228*7c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED, inum, count, &actual, 229*7c478bd9Sstevel@tonic-gate DDI_INTR_ALLOC_STRICT); 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate if ((rc != DDI_SUCCESS) || (actual == 0)) { 232*7c478bd9Sstevel@tonic-gate kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 233*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate if (actual < count) { 237*7c478bd9Sstevel@tonic-gate for (x = 0; x < actual; x++) { 238*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(qcn_state->qcn_htable[x]); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 242*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate qcn_state->qcn_intr_cnt = actual; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* Get intr priority */ 248*7c478bd9Sstevel@tonic-gate if (ddi_intr_get_pri(qcn_state->qcn_htable[0], 249*7c478bd9Sstevel@tonic-gate &qcn_state->qcn_intr_pri) != DDI_SUCCESS) { 250*7c478bd9Sstevel@tonic-gate for (x = 0; x < actual; x++) { 251*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(qcn_state->qcn_htable[x]); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size); 255*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* Call ddi_intr_add_handler() */ 259*7c478bd9Sstevel@tonic-gate for (x = 0; x < actual; x++) { 260*7c478bd9Sstevel@tonic-gate if (ddi_intr_add_handler(qcn_state->qcn_htable[x], 261*7c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)qcn_hi_intr, 262*7c478bd9Sstevel@tonic-gate (caddr_t)qcn_state, NULL) != DDI_SUCCESS) { 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate for (y = 0; y < x; y++) { 265*7c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_handler( 266*7c478bd9Sstevel@tonic-gate qcn_state->qcn_htable[y]); 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate for (y = 0; y < actual; y++) { 270*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(qcn_state->qcn_htable[y]); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate kmem_free(qcn_state->qcn_htable, 274*7c478bd9Sstevel@tonic-gate qcn_state->qcn_intr_size); 275*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate static void 283*7c478bd9Sstevel@tonic-gate qcn_remove_intrs(void) 284*7c478bd9Sstevel@tonic-gate { 285*7c478bd9Sstevel@tonic-gate int x; 286*7c478bd9Sstevel@tonic-gate for (x = 0; x < qcn_state->qcn_intr_cnt; x++) { 287*7c478bd9Sstevel@tonic-gate (void) ddi_intr_disable(qcn_state->qcn_htable[x]); 288*7c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_handler(qcn_state->qcn_htable[x]); 289*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(qcn_state->qcn_htable[x]); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate static void 294*7c478bd9Sstevel@tonic-gate qcn_intr_enable(void) 295*7c478bd9Sstevel@tonic-gate { 296*7c478bd9Sstevel@tonic-gate int x; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate for (x = 0; x < qcn_state->qcn_intr_cnt; x++) { 299*7c478bd9Sstevel@tonic-gate (void) ddi_intr_enable(qcn_state->qcn_htable[x]); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * qcn_attach is called at startup time. 305*7c478bd9Sstevel@tonic-gate * There is only once instance of this driver. 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate static int 308*7c478bd9Sstevel@tonic-gate qcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 309*7c478bd9Sstevel@tonic-gate { 310*7c478bd9Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *, char *, 311*7c478bd9Sstevel@tonic-gate int, minor_t); 312*7c478bd9Sstevel@tonic-gate uint_t soft_prip; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate #ifdef QCN_POLLING 315*7c478bd9Sstevel@tonic-gate char *binding_name; 316*7c478bd9Sstevel@tonic-gate #endif 317*7c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 318*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate if (ddi_create_internal_pathname(dip, "qcn", 321*7c478bd9Sstevel@tonic-gate S_IFCHR, 0) != DDI_SUCCESS) 322*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate qcn_state->qcn_soft_pend = 0; 325*7c478bd9Sstevel@tonic-gate qcn_state->qcn_hangup = 0; 326*7c478bd9Sstevel@tonic-gate qcn_state->qcn_rbuf_overflow = 0; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate /* prepare some data structures in soft state */ 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate qcn_state->qcn_dip = dip; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate qcn_state->qcn_polling = 0; 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate #ifdef QCN_POLLING 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * This test is for the sole purposes of allowing 337*7c478bd9Sstevel@tonic-gate * the console to work on older firmware releases. 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate binding_name = ddi_binding_name(qcn_state->qcn_dip); 340*7c478bd9Sstevel@tonic-gate if (strcmp(binding_name, "qcn") == 0) 341*7c478bd9Sstevel@tonic-gate qcn_state->qcn_polling = 1; 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_polling) { 344*7c478bd9Sstevel@tonic-gate qcn_poll_time.cyt_when = 0ull; 345*7c478bd9Sstevel@tonic-gate qcn_poll_time.cyt_interval = 346*7c478bd9Sstevel@tonic-gate qcn_poll_interval * 1000ull * 1000ull; 347*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 348*7c478bd9Sstevel@tonic-gate qcn_poll_cycid = cyclic_add(&qcn_poll_cychandler, 349*7c478bd9Sstevel@tonic-gate &qcn_poll_time); 350*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate #endif 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate if (!qcn_state->qcn_polling) { 355*7c478bd9Sstevel@tonic-gate if (qcn_add_intrs() != DDI_SUCCESS) { 356*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_attach: add_intr failed\n"); 357*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate if (ddi_intr_add_softint(dip, &qcn_state->qcn_softint_hdl, 360*7c478bd9Sstevel@tonic-gate DDI_INTR_SOFTPRI_MAX, qcn_soft_intr, 361*7c478bd9Sstevel@tonic-gate (caddr_t)qcn_state) != DDI_SUCCESS) { 362*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_attach: add_soft_intr failed\n"); 363*7c478bd9Sstevel@tonic-gate qcn_remove_intrs(); 364*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate if (ddi_intr_get_softint_pri(qcn_state->qcn_softint_hdl, 367*7c478bd9Sstevel@tonic-gate &soft_prip) != DDI_SUCCESS) { 368*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_attach: softint_pri failed\n"); 369*7c478bd9Sstevel@tonic-gate qcn_remove_intrs(); 370*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate qcn_state->qcn_soft_pri = 373*7c478bd9Sstevel@tonic-gate (ddi_iblock_cookie_t)(uint64_t)soft_prip; 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER, 376*7c478bd9Sstevel@tonic-gate (void *)(qcn_state->qcn_intr_pri)); 377*7c478bd9Sstevel@tonic-gate mutex_init(&qcn_state->qcn_softlock, NULL, MUTEX_DRIVER, 378*7c478bd9Sstevel@tonic-gate (void *)(qcn_state->qcn_soft_pri)); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* 384*7c478bd9Sstevel@tonic-gate * Enable interrupts 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate if (!qcn_state->qcn_polling) { 387*7c478bd9Sstevel@tonic-gate qcn_intr_enable(); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 390*7c478bd9Sstevel@tonic-gate prom_printf("qcn_attach(): qcn driver attached\n"); 391*7c478bd9Sstevel@tonic-gate #endif 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 398*7c478bd9Sstevel@tonic-gate static int 399*7c478bd9Sstevel@tonic-gate qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 400*7c478bd9Sstevel@tonic-gate { 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 403*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 407*7c478bd9Sstevel@tonic-gate prom_printf("qcn_detach(): QCN driver detached\n"); 408*7c478bd9Sstevel@tonic-gate #endif 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate #ifdef QCN_POLLING 411*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_polling) { 412*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 413*7c478bd9Sstevel@tonic-gate if (qcn_poll_cycid != CYCLIC_NONE) 414*7c478bd9Sstevel@tonic-gate cyclic_remove(qcn_poll_cycid); 415*7c478bd9Sstevel@tonic-gate qcn_poll_cycid = CYCLIC_NONE; 416*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate #endif 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if (!qcn_state->qcn_polling) 421*7c478bd9Sstevel@tonic-gate qcn_remove_intrs(); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 427*7c478bd9Sstevel@tonic-gate static int 428*7c478bd9Sstevel@tonic-gate qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 431*7c478bd9Sstevel@tonic-gate int instance = 0; 432*7c478bd9Sstevel@tonic-gate switch (infocmd) { 433*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 434*7c478bd9Sstevel@tonic-gate if (qcn_state) { 435*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 436*7c478bd9Sstevel@tonic-gate prom_printf("qcn_getinfo(): devt2dip %lx\n", arg); 437*7c478bd9Sstevel@tonic-gate #endif 438*7c478bd9Sstevel@tonic-gate *result = (void *)qcn_state->qcn_dip; 439*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate break; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 444*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 445*7c478bd9Sstevel@tonic-gate prom_printf("qcn_getinfo(): devt2instance %lx\n", arg); 446*7c478bd9Sstevel@tonic-gate #endif 447*7c478bd9Sstevel@tonic-gate if (getminor((dev_t)arg) == 0) { 448*7c478bd9Sstevel@tonic-gate *result = (void *)instance; 449*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate break; 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate return (error); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* streams open & close */ 458*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 459*7c478bd9Sstevel@tonic-gate static int 460*7c478bd9Sstevel@tonic-gate qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 461*7c478bd9Sstevel@tonic-gate { 462*7c478bd9Sstevel@tonic-gate tty_common_t *tty; 463*7c478bd9Sstevel@tonic-gate int unit = getminor(*devp); 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 466*7c478bd9Sstevel@tonic-gate prom_printf("qcn_open(): minor %x\n", unit); 467*7c478bd9Sstevel@tonic-gate #endif 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate if (unit != 0) 470*7c478bd9Sstevel@tonic-gate return (ENXIO); 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate /* stream already open */ 473*7c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL) 474*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate if (!qcn_state) { 477*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_open: console was not configured by " 478*7c478bd9Sstevel@tonic-gate "autoconfig\n"); 479*7c478bd9Sstevel@tonic-gate return (ENXIO); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 483*7c478bd9Sstevel@tonic-gate tty = &(qcn_state->qcn_tty); 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate tty->t_readq = q; 486*7c478bd9Sstevel@tonic-gate tty->t_writeq = WR(q); 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* Link the RD and WR Q's */ 489*7c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state; 490*7c478bd9Sstevel@tonic-gate qcn_state->qcn_readq = RD(q); 491*7c478bd9Sstevel@tonic-gate qcn_state->qcn_writeq = WR(q); 492*7c478bd9Sstevel@tonic-gate qprocson(q); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 497*7c478bd9Sstevel@tonic-gate prom_printf("qcn_open: opened as dev %lx\n", *devp); 498*7c478bd9Sstevel@tonic-gate #endif 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 504*7c478bd9Sstevel@tonic-gate static int 505*7c478bd9Sstevel@tonic-gate qcn_close(queue_t *q, int flag, cred_t *credp) 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate ASSERT(qcn_state == q->q_ptr); 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_wbufcid != 0) { 511*7c478bd9Sstevel@tonic-gate unbufcall(qcn_state->qcn_wbufcid); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate ttycommon_close(&qcn_state->qcn_tty); 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate qprocsoff(q); 516*7c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 517*7c478bd9Sstevel@tonic-gate qcn_state->qcn_readq = NULL; 518*7c478bd9Sstevel@tonic-gate qcn_state->qcn_writeq = NULL; 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * Put procedure for write queue. 525*7c478bd9Sstevel@tonic-gate * Respond to M_IOCTL, M_DATA and M_FLUSH messages here; 526*7c478bd9Sstevel@tonic-gate * It put's the data onto internal qcn_output_q. 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate static int 529*7c478bd9Sstevel@tonic-gate qcn_wput(queue_t *q, mblk_t *mp) 530*7c478bd9Sstevel@tonic-gate { 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 533*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 534*7c478bd9Sstevel@tonic-gate int i; 535*7c478bd9Sstevel@tonic-gate #endif 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate ASSERT(qcn_state == q->q_ptr); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (!mp->b_datap) { 540*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "qcn_wput: null datap"); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 544*7c478bd9Sstevel@tonic-gate prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n", 545*7c478bd9Sstevel@tonic-gate q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type); 546*7c478bd9Sstevel@tonic-gate #endif 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 551*7c478bd9Sstevel@tonic-gate case M_IOCTL: 552*7c478bd9Sstevel@tonic-gate case M_CTL: 553*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 554*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 555*7c478bd9Sstevel@tonic-gate prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n", 556*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd, TIOC); 557*7c478bd9Sstevel@tonic-gate #endif 558*7c478bd9Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 559*7c478bd9Sstevel@tonic-gate case TCSETSW: 560*7c478bd9Sstevel@tonic-gate case TCSETSF: 561*7c478bd9Sstevel@tonic-gate case TCSETAW: 562*7c478bd9Sstevel@tonic-gate case TCSETAF: 563*7c478bd9Sstevel@tonic-gate case TCSBRK: 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * The change do not take effect until all 566*7c478bd9Sstevel@tonic-gate * output queued before them is drained. 567*7c478bd9Sstevel@tonic-gate * Put this message on the queue, so that 568*7c478bd9Sstevel@tonic-gate * "qcn_start" will see it when it's done 569*7c478bd9Sstevel@tonic-gate * with the output before it. Poke the start 570*7c478bd9Sstevel@tonic-gate * routine, just in case. 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 573*7c478bd9Sstevel@tonic-gate qcn_start(); 574*7c478bd9Sstevel@tonic-gate break; 575*7c478bd9Sstevel@tonic-gate default: 576*7c478bd9Sstevel@tonic-gate qcn_ioctl(q, mp); 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate break; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate case M_FLUSH: 581*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 582*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 583*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 586*7c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 587*7c478bd9Sstevel@tonic-gate qreply(q, mp); 588*7c478bd9Sstevel@tonic-gate } else { 589*7c478bd9Sstevel@tonic-gate freemsg(mp); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate break; 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate case M_STOP: 594*7c478bd9Sstevel@tonic-gate qcn_stopped = B_TRUE; 595*7c478bd9Sstevel@tonic-gate freemsg(mp); 596*7c478bd9Sstevel@tonic-gate break; 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate case M_START: 599*7c478bd9Sstevel@tonic-gate qcn_stopped = B_FALSE; 600*7c478bd9Sstevel@tonic-gate freemsg(mp); 601*7c478bd9Sstevel@tonic-gate qenable(q); /* Start up delayed messages */ 602*7c478bd9Sstevel@tonic-gate break; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate case M_DATA: 605*7c478bd9Sstevel@tonic-gate /* 606*7c478bd9Sstevel@tonic-gate * Queue the message up to be transmitted, 607*7c478bd9Sstevel@tonic-gate * and poke the start routine. 608*7c478bd9Sstevel@tonic-gate */ 609*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 610*7c478bd9Sstevel@tonic-gate if (mp->b_rptr < mp->b_wptr) { 611*7c478bd9Sstevel@tonic-gate prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 612*7c478bd9Sstevel@tonic-gate q, mp, mp->b_rptr, mp->b_wptr); 613*7c478bd9Sstevel@tonic-gate prom_printf("qcn_wput(): ["); 614*7c478bd9Sstevel@tonic-gate for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 615*7c478bd9Sstevel@tonic-gate prom_printf("%c", *(mp->b_rptr+i)); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate prom_printf("]\n"); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate #endif /* QCN_DEBUG */ 620*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 621*7c478bd9Sstevel@tonic-gate qcn_start(); 622*7c478bd9Sstevel@tonic-gate break; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate default: 625*7c478bd9Sstevel@tonic-gate freemsg(mp); 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 629*7c478bd9Sstevel@tonic-gate return (0); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* 633*7c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 634*7c478bd9Sstevel@tonic-gate */ 635*7c478bd9Sstevel@tonic-gate static void 636*7c478bd9Sstevel@tonic-gate qcn_ioctl(queue_t *q, mblk_t *mp) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 639*7c478bd9Sstevel@tonic-gate tty_common_t *tty; 640*7c478bd9Sstevel@tonic-gate mblk_t *datamp; 641*7c478bd9Sstevel@tonic-gate int data_size; 642*7c478bd9Sstevel@tonic-gate int error = 0; 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 645*7c478bd9Sstevel@tonic-gate prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp); 646*7c478bd9Sstevel@tonic-gate #endif 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 649*7c478bd9Sstevel@tonic-gate tty = &(qcn_state->qcn_tty); 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (tty->t_iocpending != NULL) { 652*7c478bd9Sstevel@tonic-gate freemsg(tty->t_iocpending); 653*7c478bd9Sstevel@tonic-gate tty->t_iocpending = NULL; 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate data_size = ttycommon_ioctl(tty, q, mp, &error); 656*7c478bd9Sstevel@tonic-gate if (data_size != 0) { 657*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_wbufcid) 658*7c478bd9Sstevel@tonic-gate unbufcall(qcn_state->qcn_wbufcid); 659*7c478bd9Sstevel@tonic-gate /* call qcn_reioctl() */ 660*7c478bd9Sstevel@tonic-gate qcn_state->qcn_wbufcid = 661*7c478bd9Sstevel@tonic-gate bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state); 662*7c478bd9Sstevel@tonic-gate return; 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate if (error < 0) { 666*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate error = 0; 671*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 672*7c478bd9Sstevel@tonic-gate case TCSBRK: 673*7c478bd9Sstevel@tonic-gate case TIOCSBRK: 674*7c478bd9Sstevel@tonic-gate case TIOCCBRK: 675*7c478bd9Sstevel@tonic-gate case TIOCMSET: 676*7c478bd9Sstevel@tonic-gate case TIOCMBIS: 677*7c478bd9Sstevel@tonic-gate case TIOCMBIC: 678*7c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 679*7c478bd9Sstevel@tonic-gate qcn_ack(mp, NULL, 0); 680*7c478bd9Sstevel@tonic-gate else 681*7c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 682*7c478bd9Sstevel@tonic-gate break; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate case TIOCMGET: 685*7c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (int), BPRI_MED); 686*7c478bd9Sstevel@tonic-gate if (datamp == NULL) { 687*7c478bd9Sstevel@tonic-gate error = EAGAIN; 688*7c478bd9Sstevel@tonic-gate break; 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate *(int *)datamp->b_rptr = 0; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 694*7c478bd9Sstevel@tonic-gate qcn_ack(mp, datamp, sizeof (int)); 695*7c478bd9Sstevel@tonic-gate else 696*7c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, datamp); 697*7c478bd9Sstevel@tonic-gate break; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate default: 700*7c478bd9Sstevel@tonic-gate error = EINVAL; 701*7c478bd9Sstevel@tonic-gate break; 702*7c478bd9Sstevel@tonic-gate } 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate if (error != 0) { 705*7c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 706*7c478bd9Sstevel@tonic-gate iocp->ioc_error = error; 707*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate qreply(q, mp); 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate static void 713*7c478bd9Sstevel@tonic-gate qcn_reioctl(void *unit) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate queue_t *q; 716*7c478bd9Sstevel@tonic-gate mblk_t *mp; 717*7c478bd9Sstevel@tonic-gate qcn_t *qcnp = (qcn_t *)unit; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate if (!qcnp->qcn_wbufcid) 720*7c478bd9Sstevel@tonic-gate return; 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate qcnp->qcn_wbufcid = 0; 723*7c478bd9Sstevel@tonic-gate if ((q = qcnp->qcn_tty.t_writeq) == NULL) 724*7c478bd9Sstevel@tonic-gate return; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate if ((mp = qcnp->qcn_tty.t_iocpending) == NULL) 727*7c478bd9Sstevel@tonic-gate return; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate qcnp->qcn_tty.t_iocpending = NULL; 730*7c478bd9Sstevel@tonic-gate qcn_ioctl(q, mp); 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate static void 734*7c478bd9Sstevel@tonic-gate qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size) 735*7c478bd9Sstevel@tonic-gate { 736*7c478bd9Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 739*7c478bd9Sstevel@tonic-gate iocp->ioc_count = size; 740*7c478bd9Sstevel@tonic-gate iocp->ioc_error = 0; 741*7c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 742*7c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 743*7c478bd9Sstevel@tonic-gate freeb(mp->b_cont); 744*7c478bd9Sstevel@tonic-gate if (dp != NULL) { 745*7c478bd9Sstevel@tonic-gate mp->b_cont = dp; 746*7c478bd9Sstevel@tonic-gate dp->b_wptr += size; 747*7c478bd9Sstevel@tonic-gate } else 748*7c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate static void 752*7c478bd9Sstevel@tonic-gate qcn_start(void) 753*7c478bd9Sstevel@tonic-gate { 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate queue_t *q; 756*7c478bd9Sstevel@tonic-gate mblk_t *mp; 757*7c478bd9Sstevel@tonic-gate int rv; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* 762*7c478bd9Sstevel@tonic-gate * read stream queue and remove data from the queue and 763*7c478bd9Sstevel@tonic-gate * transmit them if possible 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate q = qcn_state->qcn_writeq; 766*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 767*7c478bd9Sstevel@tonic-gate while (mp = getq(q)) { 768*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_IOCTL) { 769*7c478bd9Sstevel@tonic-gate /* 770*7c478bd9Sstevel@tonic-gate * These are those IOCTLs queued up 771*7c478bd9Sstevel@tonic-gate * do it now 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate qcn_ioctl(q, mp); 774*7c478bd9Sstevel@tonic-gate continue; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate /* 777*7c478bd9Sstevel@tonic-gate * M_DATA 778*7c478bd9Sstevel@tonic-gate */ 779*7c478bd9Sstevel@tonic-gate rv = qcn_transmit(q, mp); 780*7c478bd9Sstevel@tonic-gate if (rv == EBUSY || rv == EAGAIN) 781*7c478bd9Sstevel@tonic-gate return; 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate static int 786*7c478bd9Sstevel@tonic-gate qcn_transmit(queue_t *q, mblk_t *mp) 787*7c478bd9Sstevel@tonic-gate { 788*7c478bd9Sstevel@tonic-gate caddr_t buf; 789*7c478bd9Sstevel@tonic-gate mblk_t *bp; 790*7c478bd9Sstevel@tonic-gate size_t len; 791*7c478bd9Sstevel@tonic-gate long i; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate #ifdef QCN_DEBUG 794*7c478bd9Sstevel@tonic-gate prom_printf("qcn_transmit(): q=%X mp=%X\n", q, mp); 795*7c478bd9Sstevel@tonic-gate #endif 796*7c478bd9Sstevel@tonic-gate do { 797*7c478bd9Sstevel@tonic-gate bp = mp; 798*7c478bd9Sstevel@tonic-gate len = bp->b_wptr - bp->b_rptr; 799*7c478bd9Sstevel@tonic-gate buf = (caddr_t)bp->b_rptr; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 802*7c478bd9Sstevel@tonic-gate if (hv_cnputchar(buf[i]) == -1) 803*7c478bd9Sstevel@tonic-gate break; 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate if (i != len) { 806*7c478bd9Sstevel@tonic-gate bp->b_rptr += i; 807*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 808*7c478bd9Sstevel@tonic-gate return (EAGAIN); 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate mp = bp->b_cont; 811*7c478bd9Sstevel@tonic-gate freeb(bp); 812*7c478bd9Sstevel@tonic-gate } while (mp != NULL); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate return (0); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * called when SC first establishes console connection 819*7c478bd9Sstevel@tonic-gate * drop all the data on the output queue 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate static void 822*7c478bd9Sstevel@tonic-gate qcn_flush(void) 823*7c478bd9Sstevel@tonic-gate { 824*7c478bd9Sstevel@tonic-gate queue_t *q; 825*7c478bd9Sstevel@tonic-gate mblk_t *mp; 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&qcn_state->qcn_lock)); 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate q = qcn_state->qcn_writeq; 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate prom_printf("qcn_flush(): WARNING console output is dropped time=%x\n", 832*7c478bd9Sstevel@tonic-gate gethrestime_sec()); 833*7c478bd9Sstevel@tonic-gate while (mp = getq(q)) 834*7c478bd9Sstevel@tonic-gate freemsg(mp); 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate static void 838*7c478bd9Sstevel@tonic-gate qcn_trigger_softint(void) 839*7c478bd9Sstevel@tonic-gate { 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate if (mutex_tryenter(&qcn_state->qcn_softlock)) { 842*7c478bd9Sstevel@tonic-gate if (!qcn_state->qcn_soft_pend) { 843*7c478bd9Sstevel@tonic-gate qcn_state->qcn_soft_pend = 1; 844*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_softlock); 845*7c478bd9Sstevel@tonic-gate (void) ddi_intr_trigger_softint( 846*7c478bd9Sstevel@tonic-gate qcn_state->qcn_softint_hdl, NULL); 847*7c478bd9Sstevel@tonic-gate } else 848*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_softlock); 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate } 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 853*7c478bd9Sstevel@tonic-gate static uint_t 854*7c478bd9Sstevel@tonic-gate qcn_soft_intr(caddr_t arg1, caddr_t arg2) 855*7c478bd9Sstevel@tonic-gate { 856*7c478bd9Sstevel@tonic-gate mblk_t *mp; 857*7c478bd9Sstevel@tonic-gate int cc; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_softlock); 860*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_hi_lock); 861*7c478bd9Sstevel@tonic-gate if ((cc = RING_CNT(qcn_state)) <= 0) { 862*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_hi_lock); 863*7c478bd9Sstevel@tonic-gate goto out; 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate if ((mp = allocb(cc, BPRI_MED)) == NULL) { 867*7c478bd9Sstevel@tonic-gate qcn_input_dropped += cc; 868*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_intr: allocb" 869*7c478bd9Sstevel@tonic-gate "failed (console input dropped)"); 870*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_hi_lock); 871*7c478bd9Sstevel@tonic-gate goto out; 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate do { 875*7c478bd9Sstevel@tonic-gate /* put console input onto stream */ 876*7c478bd9Sstevel@tonic-gate *(char *)mp->b_wptr++ = RING_GET(qcn_state); 877*7c478bd9Sstevel@tonic-gate } while (--cc); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_rbuf_overflow) { 880*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_hi_lock); 881*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn: Ring buffer overflow\n"); 882*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_hi_lock); 883*7c478bd9Sstevel@tonic-gate qcn_state->qcn_rbuf_overflow = 0; 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_hi_lock); 887*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_readq) { 888*7c478bd9Sstevel@tonic-gate putnext(qcn_state->qcn_readq, mp); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate out: 891*7c478bd9Sstevel@tonic-gate /* 892*7c478bd9Sstevel@tonic-gate * If there are pending transmits because hypervisor 893*7c478bd9Sstevel@tonic-gate * returned EWOULDBLOCK poke start now. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_writeq != NULL) { 897*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_hangup) { 898*7c478bd9Sstevel@tonic-gate (void) putctl(qcn_state->qcn_readq, M_HANGUP); 899*7c478bd9Sstevel@tonic-gate flushq(qcn_state->qcn_writeq, FLUSHDATA); 900*7c478bd9Sstevel@tonic-gate qcn_state->qcn_hangup = 0; 901*7c478bd9Sstevel@tonic-gate } else { 902*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 903*7c478bd9Sstevel@tonic-gate qcn_start(); 904*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate qcn_state->qcn_soft_pend = 0; 908*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_softlock); 909*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 913*7c478bd9Sstevel@tonic-gate static uint_t 914*7c478bd9Sstevel@tonic-gate qcn_hi_intr(caddr_t arg) 915*7c478bd9Sstevel@tonic-gate { 916*7c478bd9Sstevel@tonic-gate int64_t rv; 917*7c478bd9Sstevel@tonic-gate uint8_t buf; 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_hi_lock); 920*7c478bd9Sstevel@tonic-gate /* LINTED: E_CONSTANT_CONDITION */ 921*7c478bd9Sstevel@tonic-gate while (1) { 922*7c478bd9Sstevel@tonic-gate rv = hv_cngetchar(&buf); 923*7c478bd9Sstevel@tonic-gate if (rv == H_BREAK) { 924*7c478bd9Sstevel@tonic-gate if (abort_enable != KIOCABORTALTERNATE) 925*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 926*7c478bd9Sstevel@tonic-gate } 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate if (rv == H_HUP) { 929*7c478bd9Sstevel@tonic-gate qcn_state->qcn_hangup = 1; 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate if (rv != H_EOK) 933*7c478bd9Sstevel@tonic-gate goto out; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate if (abort_enable == KIOCABORTALTERNATE) { 936*7c478bd9Sstevel@tonic-gate if (abort_charseq_recognize(buf)) { 937*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 938*7c478bd9Sstevel@tonic-gate } 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate /* put console input onto stream */ 942*7c478bd9Sstevel@tonic-gate if (RING_POK(qcn_state, 1)) { 943*7c478bd9Sstevel@tonic-gate RING_PUT(qcn_state, buf); 944*7c478bd9Sstevel@tonic-gate } else { 945*7c478bd9Sstevel@tonic-gate qcn_state->qcn_rbuf_overflow++; 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate out: 949*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_hi_lock); 950*7c478bd9Sstevel@tonic-gate qcn_trigger_softint(); 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate #ifdef QCN_POLLING 956*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 957*7c478bd9Sstevel@tonic-gate static void 958*7c478bd9Sstevel@tonic-gate qcn_poll_handler(void *unused) 959*7c478bd9Sstevel@tonic-gate { 960*7c478bd9Sstevel@tonic-gate mblk_t *mp; 961*7c478bd9Sstevel@tonic-gate int64_t rv; 962*7c478bd9Sstevel@tonic-gate uint8_t buf; 963*7c478bd9Sstevel@tonic-gate int qcn_writeq_flush = 0; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate /* LINTED: E_CONSTANT_CONDITION */ 966*7c478bd9Sstevel@tonic-gate while (1) { 967*7c478bd9Sstevel@tonic-gate rv = hv_cngetchar(&buf); 968*7c478bd9Sstevel@tonic-gate if (rv == H_BREAK) { 969*7c478bd9Sstevel@tonic-gate if (abort_enable != KIOCABORTALTERNATE) 970*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate if (rv == H_HUP) { 974*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_readq) { 975*7c478bd9Sstevel@tonic-gate (void) putctl(qcn_state->qcn_readq, M_HANGUP); 976*7c478bd9Sstevel@tonic-gate qcn_writeq_flush = 1; 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate goto out; 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate if (rv != H_EOK) 982*7c478bd9Sstevel@tonic-gate goto out; 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate if (abort_enable == KIOCABORTALTERNATE) { 985*7c478bd9Sstevel@tonic-gate if (abort_charseq_recognize(buf)) { 986*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* put console input onto stream */ 991*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_readq) { 992*7c478bd9Sstevel@tonic-gate if ((mp = allocb(1, BPRI_MED)) == NULL) { 993*7c478bd9Sstevel@tonic-gate qcn_input_dropped++; 994*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "qcn_intr: allocb" 995*7c478bd9Sstevel@tonic-gate "failed (console input dropped)"); 996*7c478bd9Sstevel@tonic-gate return; 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate *(char *)mp->b_wptr++ = buf; 999*7c478bd9Sstevel@tonic-gate putnext(qcn_state->qcn_readq, mp); 1000*7c478bd9Sstevel@tonic-gate } 1001*7c478bd9Sstevel@tonic-gate } 1002*7c478bd9Sstevel@tonic-gate out: 1003*7c478bd9Sstevel@tonic-gate /* 1004*7c478bd9Sstevel@tonic-gate * If there are pending transmits because hypervisor 1005*7c478bd9Sstevel@tonic-gate * returned EWOULDBLOCK poke start now. 1006*7c478bd9Sstevel@tonic-gate */ 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 1009*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_writeq != NULL) { 1010*7c478bd9Sstevel@tonic-gate if (qcn_writeq_flush) { 1011*7c478bd9Sstevel@tonic-gate flushq(qcn_state->qcn_writeq, FLUSHDATA); 1012*7c478bd9Sstevel@tonic-gate } else { 1013*7c478bd9Sstevel@tonic-gate qcn_start(); 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate #endif 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* 1021*7c478bd9Sstevel@tonic-gate * Check for abort character sequence, copied from zs_async.c 1022*7c478bd9Sstevel@tonic-gate */ 1023*7c478bd9Sstevel@tonic-gate #define CNTRL(c) ((c)&037) 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate static boolean_t 1026*7c478bd9Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch) 1027*7c478bd9Sstevel@tonic-gate { 1028*7c478bd9Sstevel@tonic-gate static int state = 0; 1029*7c478bd9Sstevel@tonic-gate static char sequence[] = { '\r', '~', CNTRL('b') }; 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate if (ch == sequence[state]) { 1032*7c478bd9Sstevel@tonic-gate if (++state >= sizeof (sequence)) { 1033*7c478bd9Sstevel@tonic-gate state = 0; 1034*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate } else { 1037*7c478bd9Sstevel@tonic-gate state = (ch == sequence[0]) ? 1 : 0; 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate static int 1044*7c478bd9Sstevel@tonic-gate qcn_rsrv(queue_t *q) 1045*7c478bd9Sstevel@tonic-gate { 1046*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate if (qcn_stopped == B_TRUE) 1049*7c478bd9Sstevel@tonic-gate return (0); 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 1054*7c478bd9Sstevel@tonic-gate if (canputnext(q)) 1055*7c478bd9Sstevel@tonic-gate putnext(q, mp); 1056*7c478bd9Sstevel@tonic-gate else if (mp->b_datap->db_type >= QPCTL) 1057*7c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 1058*7c478bd9Sstevel@tonic-gate } 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate return (0); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1066*7c478bd9Sstevel@tonic-gate static int 1067*7c478bd9Sstevel@tonic-gate qcn_wsrv(queue_t *q) 1068*7c478bd9Sstevel@tonic-gate { 1069*7c478bd9Sstevel@tonic-gate if (qcn_stopped == B_TRUE) 1070*7c478bd9Sstevel@tonic-gate return (0); 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate mutex_enter(&qcn_state->qcn_lock); 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate if (qcn_state->qcn_writeq != NULL) 1075*7c478bd9Sstevel@tonic-gate qcn_start(); 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate mutex_exit(&qcn_state->qcn_lock); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate return (0); 1080*7c478bd9Sstevel@tonic-gate } 1081