1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * MT STREAMS Virtual Console Device Driver 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/sysmacros.h> 35*0Sstevel@tonic-gate #include <sys/processor.h> 36*0Sstevel@tonic-gate #include <sys/cpuvar.h> 37*0Sstevel@tonic-gate #include <sys/open.h> 38*0Sstevel@tonic-gate #include <sys/param.h> 39*0Sstevel@tonic-gate #include <sys/systm.h> 40*0Sstevel@tonic-gate #include <sys/signal.h> 41*0Sstevel@tonic-gate #include <sys/cred.h> 42*0Sstevel@tonic-gate #include <sys/user.h> 43*0Sstevel@tonic-gate #include <sys/proc.h> 44*0Sstevel@tonic-gate #include <sys/vnode.h> 45*0Sstevel@tonic-gate #include <sys/uio.h> 46*0Sstevel@tonic-gate #include <sys/buf.h> 47*0Sstevel@tonic-gate #include <sys/file.h> 48*0Sstevel@tonic-gate #include <sys/kmem.h> 49*0Sstevel@tonic-gate #include <sys/vmem.h> 50*0Sstevel@tonic-gate #include <sys/stat.h> 51*0Sstevel@tonic-gate #include <sys/stream.h> 52*0Sstevel@tonic-gate #include <sys/stropts.h> 53*0Sstevel@tonic-gate #include <sys/strsubr.h> 54*0Sstevel@tonic-gate #include <sys/strsun.h> 55*0Sstevel@tonic-gate #include <sys/tty.h> 56*0Sstevel@tonic-gate #include <sys/ptyvar.h> 57*0Sstevel@tonic-gate #include <sys/poll.h> 58*0Sstevel@tonic-gate #include <sys/debug.h> 59*0Sstevel@tonic-gate #include <sys/conf.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <sys/starfire.h> 62*0Sstevel@tonic-gate #include <sys/mman.h> 63*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate #include <sys/ddi.h> 66*0Sstevel@tonic-gate #include <sys/sunddi.h> 67*0Sstevel@tonic-gate #include <sys/errno.h> 68*0Sstevel@tonic-gate #include <sys/modctl.h> 69*0Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 70*0Sstevel@tonic-gate #include <sys/cvc.h> 71*0Sstevel@tonic-gate #include <sys/cpu_sgn.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate extern void prom_printf(char *fmt, ...); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 76*0Sstevel@tonic-gate static int cvc_attach(dev_info_t *, ddi_attach_cmd_t); 77*0Sstevel@tonic-gate static int cvc_detach(dev_info_t *, ddi_detach_cmd_t); 78*0Sstevel@tonic-gate static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *); 79*0Sstevel@tonic-gate static int cvc_close(queue_t *, int, cred_t *); 80*0Sstevel@tonic-gate static int cvc_wput(queue_t *, mblk_t *); 81*0Sstevel@tonic-gate static int cvc_wsrv(queue_t *); 82*0Sstevel@tonic-gate static void cvc_ioctl(queue_t *, mblk_t *); 83*0Sstevel@tonic-gate static void cvc_ack(mblk_t *, mblk_t *, uint_t); 84*0Sstevel@tonic-gate static void cvc_reioctl(void *); 85*0Sstevel@tonic-gate static void cvc_input_daemon(void); 86*0Sstevel@tonic-gate static void cvc_putc(register int); 87*0Sstevel@tonic-gate static void cvc_flush_buf(void *); 88*0Sstevel@tonic-gate static void cvc_bbsram_ops(volatile uchar_t *); 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate static caddr_t cvc_iobuf_mapin(processorid_t); 91*0Sstevel@tonic-gate static void cvc_iobuf_mapout(processorid_t); 92*0Sstevel@tonic-gate void cvc_assign_iocpu(processorid_t); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Private copy of devinfo pointer; cvc_info uses it. 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate static dev_info_t *cvcdip; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* 100*0Sstevel@tonic-gate * This buffer is used to manage mapping in the I/O buffer that CVC 101*0Sstevel@tonic-gate * uses when communicating with the SSP Client (netcon_server) via bbsram. 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate static caddr_t cvc_iobufp[NCPU]; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate typedef struct cvc_s { 106*0Sstevel@tonic-gate bufcall_id_t cvc_wbufcid; 107*0Sstevel@tonic-gate tty_common_t cvc_tty; 108*0Sstevel@tonic-gate } cvc_t; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate cvc_t cvc_common_tty; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate static struct module_info cvcm_info = { 113*0Sstevel@tonic-gate 1313, /* mi_idnum Bad luck number ;-) */ 114*0Sstevel@tonic-gate "cvc", /* mi_idname */ 115*0Sstevel@tonic-gate 0, /* mi_minpsz */ 116*0Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 117*0Sstevel@tonic-gate 2048, /* mi_hiwat */ 118*0Sstevel@tonic-gate 2048 /* mi_lowat */ 119*0Sstevel@tonic-gate }; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate static struct qinit cvcrinit = { 122*0Sstevel@tonic-gate NULL, /* qi_putp */ 123*0Sstevel@tonic-gate NULL, /* qi_srvp */ 124*0Sstevel@tonic-gate cvc_open, /* qi_qopen */ 125*0Sstevel@tonic-gate cvc_close, /* qi_qclose */ 126*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 127*0Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 128*0Sstevel@tonic-gate NULL /* qi_mstat */ 129*0Sstevel@tonic-gate }; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static struct qinit cvcwinit = { 132*0Sstevel@tonic-gate cvc_wput, /* qi_putp */ 133*0Sstevel@tonic-gate cvc_wsrv, /* qi_srvp */ 134*0Sstevel@tonic-gate cvc_open, /* qi_qopen */ 135*0Sstevel@tonic-gate cvc_close, /* qi_qclose */ 136*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 137*0Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 138*0Sstevel@tonic-gate NULL /* qi_mstat */ 139*0Sstevel@tonic-gate }; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate struct streamtab cvcinfo = { 142*0Sstevel@tonic-gate &cvcrinit, /* st_rdinit */ 143*0Sstevel@tonic-gate &cvcwinit, /* st_wrinit */ 144*0Sstevel@tonic-gate NULL, /* st_muxrinit */ 145*0Sstevel@tonic-gate NULL /* st_muxwrinit */ 146*0Sstevel@tonic-gate }; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate #define TIMEOUT_DELAY 100000 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate #define BBSRAM_INPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 151*0Sstevel@tonic-gate + BBSRAM_INPUT_COUNT_OFF)) 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate #define BBSRAM_OUTPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 154*0Sstevel@tonic-gate + BBSRAM_OUTPUT_COUNT_OFF)) 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate #define BBSRAM_INPUT_COUNT (*((volatile short *)BBSRAM_INPUT_BUF)) 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate #define BBSRAM_OUTPUT_COUNT (*((volatile short *)BBSRAM_OUTPUT_BUF)) 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate #define CVC_OUT_MAXSPIN 1024 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */ 163*0Sstevel@tonic-gate #define BBSRAM_CONTROL_REG ((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \ 164*0Sstevel@tonic-gate + CVC_IN_SIZE + CVC_OUT_SIZE)) 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate static krwlock_t cvclock; /* lock protecting everything here */ 167*0Sstevel@tonic-gate static queue_t *cvcinput_q; /* queue for console input */ 168*0Sstevel@tonic-gate static queue_t *cvcoutput_q; /* queue for console output */ 169*0Sstevel@tonic-gate static int cvc_instance = -1; 170*0Sstevel@tonic-gate static int cvc_stopped = 0; 171*0Sstevel@tonic-gate static int cvc_suspended = 0; 172*0Sstevel@tonic-gate static int cvc_hangup_ok = 0; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate static kthread_id_t cvc_input_daemon_thread; 175*0Sstevel@tonic-gate static kmutex_t cvcmutex; /* protects input */ 176*0Sstevel@tonic-gate static kmutex_t cvc_buf_mutex; /* protects internal output buffer */ 177*0Sstevel@tonic-gate static kmutex_t cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */ 178*0Sstevel@tonic-gate static int input_ok = 0; /* true when stream is valid */ 179*0Sstevel@tonic-gate static int stop_bbsram = 1; /* true when BBSRAM is not usable */ 180*0Sstevel@tonic-gate static int stop_timeout = 0; 181*0Sstevel@tonic-gate static uchar_t cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */ 182*0Sstevel@tonic-gate static ushort_t cvc_output_count = 0; 183*0Sstevel@tonic-gate static int via_bbsram = 0; /* toggle switch */ 184*0Sstevel@tonic-gate static timeout_id_t cvc_timeout_id = (timeout_id_t)-1; 185*0Sstevel@tonic-gate static processorid_t cvc_iocpu = -1; /* cpu id of cpu zero */ 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * Module linkage information for the kernel. 189*0Sstevel@tonic-gate */ 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach, 192*0Sstevel@tonic-gate nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo); 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate static struct modldrv modldrv = { 195*0Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 196*0Sstevel@tonic-gate "CVC driver 'cvc' v%I%", 197*0Sstevel@tonic-gate &cvcops, /* driver ops */ 198*0Sstevel@tonic-gate }; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 201*0Sstevel@tonic-gate MODREV_1, 202*0Sstevel@tonic-gate &modldrv, 203*0Sstevel@tonic-gate NULL 204*0Sstevel@tonic-gate }; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate int 207*0Sstevel@tonic-gate _init(void) 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate int status; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate status = mod_install(&modlinkage); 212*0Sstevel@tonic-gate if (status == 0) { 213*0Sstevel@tonic-gate mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL); 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate return (status); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate int 219*0Sstevel@tonic-gate _fini(void) 220*0Sstevel@tonic-gate { 221*0Sstevel@tonic-gate return (EBUSY); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate int 225*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate /* 231*0Sstevel@tonic-gate * DDI glue routines. 232*0Sstevel@tonic-gate */ 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* ARGSUSED */ 235*0Sstevel@tonic-gate static int 236*0Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate static char been_here = 0; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (cmd == DDI_RESUME) { 241*0Sstevel@tonic-gate cvc_suspended = 0; 242*0Sstevel@tonic-gate return (DDI_SUCCESS); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate mutex_enter(&cvcmutex); 246*0Sstevel@tonic-gate if (!been_here) { 247*0Sstevel@tonic-gate been_here = 1; 248*0Sstevel@tonic-gate mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL); 249*0Sstevel@tonic-gate mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL); 250*0Sstevel@tonic-gate rw_init(&cvclock, NULL, RW_DRIVER, NULL); 251*0Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 252*0Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 253*0Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 254*0Sstevel@tonic-gate rw_exit(&cvclock); 255*0Sstevel@tonic-gate cvc_instance = ddi_get_instance(devi); 256*0Sstevel@tonic-gate } else { 257*0Sstevel@tonic-gate #if defined(DEBUG) 258*0Sstevel@tonic-gate cmn_err(CE_NOTE, 259*0Sstevel@tonic-gate "cvc_attach: called multiple times!! (instance = %d)", 260*0Sstevel@tonic-gate ddi_get_instance(devi)); 261*0Sstevel@tonic-gate #endif /* DEBUG */ 262*0Sstevel@tonic-gate return (DDI_SUCCESS); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate mutex_exit(&cvcmutex); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, "cvc", S_IFCHR, 267*0Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 268*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 269*0Sstevel@tonic-gate return (-1); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate cvcdip = devi; 272*0Sstevel@tonic-gate cvcinput_q = NULL; 273*0Sstevel@tonic-gate cvcoutput_q = NULL; 274*0Sstevel@tonic-gate return (DDI_SUCCESS); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate static int 278*0Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate if (cmd == DDI_SUSPEND) { 281*0Sstevel@tonic-gate cvc_suspended = 1; 282*0Sstevel@tonic-gate } else { 283*0Sstevel@tonic-gate if (cmd != DDI_DETACH) { 284*0Sstevel@tonic-gate return (DDI_FAILURE); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * XXX this doesn't even begin to address the detach 288*0Sstevel@tonic-gate * issues - it doesn't terminate the outstanding thread, 289*0Sstevel@tonic-gate * it doesn't clean up mutexes, kill the timeout routine 290*0Sstevel@tonic-gate * etc. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate if (cvc_instance == ddi_get_instance(dip)) { 293*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate return (DDI_SUCCESS); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate /* ARGSUSED */ 300*0Sstevel@tonic-gate static int 301*0Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 302*0Sstevel@tonic-gate { 303*0Sstevel@tonic-gate register int error; 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate switch (infocmd) { 306*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 307*0Sstevel@tonic-gate if (cvcdip == NULL) { 308*0Sstevel@tonic-gate error = DDI_FAILURE; 309*0Sstevel@tonic-gate } else { 310*0Sstevel@tonic-gate *result = (void *)cvcdip; 311*0Sstevel@tonic-gate error = DDI_SUCCESS; 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate break; 314*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 315*0Sstevel@tonic-gate *result = (void *)0; 316*0Sstevel@tonic-gate error = DDI_SUCCESS; 317*0Sstevel@tonic-gate break; 318*0Sstevel@tonic-gate default: 319*0Sstevel@tonic-gate error = DDI_FAILURE; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate return (error); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate /* ARGSUSED */ 325*0Sstevel@tonic-gate static int 326*0Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate register int unit = getminor(*devp); 329*0Sstevel@tonic-gate register int err = 0; 330*0Sstevel@tonic-gate tty_common_t *tty; 331*0Sstevel@tonic-gate cvc_t *cp; 332*0Sstevel@tonic-gate static int input_daemon_started; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate if (unit != 0) 335*0Sstevel@tonic-gate return (ENXIO); 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate if (q->q_ptr) 338*0Sstevel@tonic-gate return (0); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate cp = (cvc_t *)&cvc_common_tty; 341*0Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 342*0Sstevel@tonic-gate cp->cvc_wbufcid = 0; 343*0Sstevel@tonic-gate tty = &cp->cvc_tty; 344*0Sstevel@tonic-gate tty->t_readq = q; 345*0Sstevel@tonic-gate tty->t_writeq = WR(q); 346*0Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)cp; 347*0Sstevel@tonic-gate cvcinput_q = RD(q); /* save for cvc_redir */ 348*0Sstevel@tonic-gate qprocson(q); 349*0Sstevel@tonic-gate mutex_enter(&cvcmutex); 350*0Sstevel@tonic-gate input_ok = 1; 351*0Sstevel@tonic-gate if (!input_daemon_started) { 352*0Sstevel@tonic-gate extern struct cpu *SIGBCPU; /* bugid4141050 */ 353*0Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate input_daemon_started = 1; 356*0Sstevel@tonic-gate mutex_exit(&cvcmutex); 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL); 359*0Sstevel@tonic-gate cvc_assign_iocpu(SIGBCPU->cpu_id); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate cvc_input_daemon_thread = thread_create(NULL, 0, 362*0Sstevel@tonic-gate cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); 363*0Sstevel@tonic-gate } else { 364*0Sstevel@tonic-gate mutex_exit(&cvcmutex); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate #ifdef lint 367*0Sstevel@tonic-gate cvc_input_daemon_thread = cvc_input_daemon_thread; 368*0Sstevel@tonic-gate #endif 369*0Sstevel@tonic-gate return (err); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* ARGSUSED */ 373*0Sstevel@tonic-gate static int 374*0Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp) 375*0Sstevel@tonic-gate { 376*0Sstevel@tonic-gate register int err = 0; 377*0Sstevel@tonic-gate register cvc_t *cp; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate mutex_enter(&cvcmutex); 380*0Sstevel@tonic-gate input_ok = 0; 381*0Sstevel@tonic-gate mutex_exit(&cvcmutex); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate cp = q->q_ptr; 384*0Sstevel@tonic-gate if (cp->cvc_wbufcid != 0) { 385*0Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate ttycommon_close(&cp->cvc_tty); 388*0Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = NULL; 389*0Sstevel@tonic-gate cvcinput_q = NULL; 390*0Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 391*0Sstevel@tonic-gate qprocsoff(q); 392*0Sstevel@tonic-gate return (err); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * cvc_wput() 398*0Sstevel@tonic-gate * cn driver does a strwrite of console output data to rconsvp which 399*0Sstevel@tonic-gate * has been set by consconfig. The data enters the cvc stream at the 400*0Sstevel@tonic-gate * streamhead and flows thru ttycompat and ldterm which have been 401*0Sstevel@tonic-gate * pushed on the stream. Console output data gets sent out either 402*0Sstevel@tonic-gate * by cvcredir (if there is a cvcd running) or bbsram (if there 403*0Sstevel@tonic-gate * isn't). 404*0Sstevel@tonic-gate * Data is sent to the cvcredir via it's read q which is cvcoutput_q 405*0Sstevel@tonic-gate * and was set in cvc_register(). 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate static int 408*0Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp) 409*0Sstevel@tonic-gate { 410*0Sstevel@tonic-gate int error = 0; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 413*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate case M_IOCTL: 416*0Sstevel@tonic-gate case M_CTL: 417*0Sstevel@tonic-gate cvc_ioctl(q, mp); 418*0Sstevel@tonic-gate break; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate case M_FLUSH: 421*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * Flush our write queue. 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate flushq(q, FLUSHDATA); 426*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 429*0Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 430*0Sstevel@tonic-gate qreply(q, mp); 431*0Sstevel@tonic-gate } else 432*0Sstevel@tonic-gate freemsg(mp); 433*0Sstevel@tonic-gate break; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate case M_STOP: 436*0Sstevel@tonic-gate cvc_stopped = 1; 437*0Sstevel@tonic-gate freemsg(mp); 438*0Sstevel@tonic-gate break; 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate case M_START: 441*0Sstevel@tonic-gate cvc_stopped = 0; 442*0Sstevel@tonic-gate freemsg(mp); 443*0Sstevel@tonic-gate qenable(q); /* Start up delayed messages */ 444*0Sstevel@tonic-gate break; 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate case M_READ: 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * ldterm handles this (VMIN/VTIME processing). 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate freemsg(mp); 451*0Sstevel@tonic-gate break; 452*0Sstevel@tonic-gate default: 453*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%x", mp); 454*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_wput: type = 0x%x", 455*0Sstevel@tonic-gate mp->b_datap->db_type); 456*0Sstevel@tonic-gate /* FALLTHROUGH */ 457*0Sstevel@tonic-gate #ifdef lint 458*0Sstevel@tonic-gate break; 459*0Sstevel@tonic-gate #endif 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate case M_DATA: 462*0Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 463*0Sstevel@tonic-gate (void) putq(q, mp); 464*0Sstevel@tonic-gate break; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Send it up past cvcredir module. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate putnext(cvcoutput_q, mp); 471*0Sstevel@tonic-gate } else { 472*0Sstevel@tonic-gate char *msgp, c; 473*0Sstevel@tonic-gate mblk_t *mp2 = mp; 474*0Sstevel@tonic-gate int count; 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate while (mp2 != NULL) { 477*0Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 478*0Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 479*0Sstevel@tonic-gate while (count > 0) { 480*0Sstevel@tonic-gate count--; 481*0Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 482*0Sstevel@tonic-gate /* don't print NULs */ 483*0Sstevel@tonic-gate cvc_putc(c); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate mp2 = mp2->b_cont; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate freemsg(mp); 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate break; 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate rw_exit(&cvclock); 494*0Sstevel@tonic-gate return (error); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate static int cvc_wsrv_count = 0; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate static int 500*0Sstevel@tonic-gate cvc_wsrv(queue_t *q) 501*0Sstevel@tonic-gate { 502*0Sstevel@tonic-gate register mblk_t *mp; 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate cvc_wsrv_count++; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 507*0Sstevel@tonic-gate return (0); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 511*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 512*0Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 513*0Sstevel@tonic-gate /* 514*0Sstevel@tonic-gate * Send it up past cvcredir module. 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate putnext(cvcoutput_q, mp); 517*0Sstevel@tonic-gate } else { 518*0Sstevel@tonic-gate char *msgp, c; 519*0Sstevel@tonic-gate mblk_t *mp2 = mp; 520*0Sstevel@tonic-gate int count; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate while (mp2 != NULL) { 523*0Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 524*0Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 525*0Sstevel@tonic-gate while (count > 0) { 526*0Sstevel@tonic-gate count--; 527*0Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 528*0Sstevel@tonic-gate /* don't print NULs */ 529*0Sstevel@tonic-gate cvc_putc(c); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate mp2 = mp2->b_cont; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate freemsg(mp); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate rw_exit(&cvclock); 538*0Sstevel@tonic-gate return (0); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* 543*0Sstevel@tonic-gate * cvc_ioctl() 544*0Sstevel@tonic-gate * handle normal console ioctls. 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate static void 547*0Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp) 548*0Sstevel@tonic-gate { 549*0Sstevel@tonic-gate register struct iocblk *iocp; 550*0Sstevel@tonic-gate register tty_common_t *tty; 551*0Sstevel@tonic-gate register cvc_t *cp; 552*0Sstevel@tonic-gate int datasize; 553*0Sstevel@tonic-gate int error = 0; 554*0Sstevel@tonic-gate mblk_t *tmp; 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate cp = q->q_ptr; 557*0Sstevel@tonic-gate tty = &cp->cvc_tty; 558*0Sstevel@tonic-gate if (tty->t_iocpending != NULL) { 559*0Sstevel@tonic-gate freemsg(tty->t_iocpending); 560*0Sstevel@tonic-gate tty->t_iocpending = NULL; 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate datasize = ttycommon_ioctl(tty, q, mp, &error); 563*0Sstevel@tonic-gate if (datasize != 0) { 564*0Sstevel@tonic-gate if (cp->cvc_wbufcid) 565*0Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 566*0Sstevel@tonic-gate cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp); 567*0Sstevel@tonic-gate return; 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate if (error < 0) { 570*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 573*0Sstevel@tonic-gate */ 574*0Sstevel@tonic-gate error = 0; 575*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* 578*0Sstevel@tonic-gate * Set modem bit ioctls. These are NOPs for us, since we 579*0Sstevel@tonic-gate * dont control any hardware. 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate case TCSBRK: 582*0Sstevel@tonic-gate case TIOCSBRK: 583*0Sstevel@tonic-gate case TIOCCBRK: 584*0Sstevel@tonic-gate case TIOCMSET: 585*0Sstevel@tonic-gate case TIOCMBIS: 586*0Sstevel@tonic-gate case TIOCMBIC: 587*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 588*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 589*0Sstevel@tonic-gate } else { 590*0Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate /* qreply done below */ 593*0Sstevel@tonic-gate break; 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * Get modem bits, we return 0 in mblk. 597*0Sstevel@tonic-gate */ 598*0Sstevel@tonic-gate case TIOCMGET: 599*0Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 600*0Sstevel@tonic-gate if (tmp == NULL) { 601*0Sstevel@tonic-gate miocnak(q, mp, 0, EAGAIN); 602*0Sstevel@tonic-gate return; 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate *(int *)tmp->b_rptr = 0; 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 607*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 608*0Sstevel@tonic-gate else 609*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 610*0Sstevel@tonic-gate /* qreply done below */ 611*0Sstevel@tonic-gate break; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate default: 614*0Sstevel@tonic-gate /* 615*0Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 616*0Sstevel@tonic-gate */ 617*0Sstevel@tonic-gate error = EINVAL; 618*0Sstevel@tonic-gate break; 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate if (error != 0) { 622*0Sstevel@tonic-gate iocp->ioc_error = error; 623*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 624*0Sstevel@tonic-gate } 625*0Sstevel@tonic-gate qreply(q, mp); 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate /* 631*0Sstevel@tonic-gate * cvc_redir() 632*0Sstevel@tonic-gate * called from cvcredir:cvcr_wput() to handle console input 633*0Sstevel@tonic-gate * data. This routine puts the cvcredir write (downstream) data 634*0Sstevel@tonic-gate * onto the cvc read (upstream) queues. Note that if `mp' is 635*0Sstevel@tonic-gate * an M_IOCTL, then it may be reused by the caller to send back 636*0Sstevel@tonic-gate * an M_IOCACK or M_IOCNAK. 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate int 639*0Sstevel@tonic-gate cvc_redir(mblk_t *mp) 640*0Sstevel@tonic-gate { 641*0Sstevel@tonic-gate register struct iocblk *iocp; 642*0Sstevel@tonic-gate register tty_common_t *tty; 643*0Sstevel@tonic-gate register cvc_t *cp; 644*0Sstevel@tonic-gate struct winsize *ws; 645*0Sstevel@tonic-gate int error; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate if (cvcinput_q == NULL) { 648*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); 649*0Sstevel@tonic-gate return (EINVAL); 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate if (DB_TYPE(mp) != M_IOCTL) { 653*0Sstevel@tonic-gate putnext(cvcinput_q, mp); 654*0Sstevel@tonic-gate return (0); 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 658*0Sstevel@tonic-gate if (iocp->ioc_cmd == TIOCSWINSZ) { 659*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct winsize)); 660*0Sstevel@tonic-gate if (error != 0) 661*0Sstevel@tonic-gate return (error); 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 664*0Sstevel@tonic-gate cp = cvcinput_q->q_ptr; 665*0Sstevel@tonic-gate tty = &cp->cvc_tty; 666*0Sstevel@tonic-gate mutex_enter(&tty->t_excl); 667*0Sstevel@tonic-gate if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) { 668*0Sstevel@tonic-gate tty->t_size = *ws; 669*0Sstevel@tonic-gate mutex_exit(&tty->t_excl); 670*0Sstevel@tonic-gate (void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH); 671*0Sstevel@tonic-gate } else 672*0Sstevel@tonic-gate mutex_exit(&tty->t_excl); 673*0Sstevel@tonic-gate } else { 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * It must be a CVC_DISCONNECT, send hangup. 676*0Sstevel@tonic-gate */ 677*0Sstevel@tonic-gate ASSERT(iocp->ioc_cmd == CVC_DISCONNECT); 678*0Sstevel@tonic-gate if (cvc_hangup_ok) 679*0Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate return (0); 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * cvc_register() 688*0Sstevel@tonic-gate * called from cvcredir to register it's queues. cvc 689*0Sstevel@tonic-gate * receives data from cn via the streamhead and sends it to cvcredir 690*0Sstevel@tonic-gate * via pointers to cvcredir's queues. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate int 693*0Sstevel@tonic-gate cvc_register(queue_t *q) 694*0Sstevel@tonic-gate { 695*0Sstevel@tonic-gate int error = -1; 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if (cvcinput_q == NULL) 698*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: register w/ no console open!"); 699*0Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 700*0Sstevel@tonic-gate if (cvcoutput_q == NULL) { 701*0Sstevel@tonic-gate cvcoutput_q = RD(q); /* Make sure its the upstream q */ 702*0Sstevel@tonic-gate qprocson(cvcoutput_q); /* must be done within cvclock */ 703*0Sstevel@tonic-gate error = 0; 704*0Sstevel@tonic-gate } else { 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * cmn_err will call us, so release lock. 707*0Sstevel@tonic-gate */ 708*0Sstevel@tonic-gate rw_exit(&cvclock); 709*0Sstevel@tonic-gate if (cvcoutput_q == q) 710*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: duplicate q!"); 711*0Sstevel@tonic-gate else 712*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: nondup q = 0x%x", 713*0Sstevel@tonic-gate q); 714*0Sstevel@tonic-gate return (error); 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* 718*0Sstevel@tonic-gate * Unless "via_bbsram" is set, i/o will be going through cvcd, so 719*0Sstevel@tonic-gate * stop flushing output to BBSRAM. 720*0Sstevel@tonic-gate */ 721*0Sstevel@tonic-gate if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) { 722*0Sstevel@tonic-gate stop_timeout = 1; 723*0Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 724*0Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 725*0Sstevel@tonic-gate cvc_hangup_ok = 1; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate rw_exit(&cvclock); 728*0Sstevel@tonic-gate return (error); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* 733*0Sstevel@tonic-gate * cvc_unregister() 734*0Sstevel@tonic-gate * called from cvcredir to clear pointers to its queues. 735*0Sstevel@tonic-gate * cvcredir no longer wants to send or receive data. 736*0Sstevel@tonic-gate */ 737*0Sstevel@tonic-gate void 738*0Sstevel@tonic-gate cvc_unregister(queue_t *q) 739*0Sstevel@tonic-gate { 740*0Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 741*0Sstevel@tonic-gate if (q == cvcoutput_q) { 742*0Sstevel@tonic-gate qprocsoff(cvcoutput_q); /* must be done within cvclock */ 743*0Sstevel@tonic-gate cvcoutput_q = NULL; 744*0Sstevel@tonic-gate } else { 745*0Sstevel@tonic-gate rw_exit(&cvclock); 746*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_unregister: q = 0x%x not registered", q); 747*0Sstevel@tonic-gate return; 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate /* 751*0Sstevel@tonic-gate * i/o will not be going through cvcd, start flushing output to 752*0Sstevel@tonic-gate * BBSRAM 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 755*0Sstevel@tonic-gate stop_timeout = 0; 756*0Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 757*0Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate rw_exit(&cvclock); 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate /* 763*0Sstevel@tonic-gate * cvc_reioctl() 764*0Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able 765*0Sstevel@tonic-gate * to allocate the buffer we need. 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate static void 768*0Sstevel@tonic-gate cvc_reioctl(void *unit) 769*0Sstevel@tonic-gate { 770*0Sstevel@tonic-gate register queue_t *q; 771*0Sstevel@tonic-gate register mblk_t *mp; 772*0Sstevel@tonic-gate register cvc_t *cp = (cvc_t *)unit; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * The bufcall is no longer pending. 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate if (!cp->cvc_wbufcid) { 778*0Sstevel@tonic-gate return; 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate cp->cvc_wbufcid = 0; 781*0Sstevel@tonic-gate if ((q = cp->cvc_tty.t_writeq) == NULL) { 782*0Sstevel@tonic-gate return; 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate if ((mp = cp->cvc_tty.t_iocpending) != NULL) { 785*0Sstevel@tonic-gate /* not pending any more */ 786*0Sstevel@tonic-gate cp->cvc_tty.t_iocpending = NULL; 787*0Sstevel@tonic-gate cvc_ioctl(q, mp); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate } 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * cvc_bbsram_ops() 794*0Sstevel@tonic-gate * Process commands sent to cvc from netcon_server via BBSRAM 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate static void 797*0Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg) 798*0Sstevel@tonic-gate { 799*0Sstevel@tonic-gate uchar_t op; 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate if ((op = *op_reg) == 0) 802*0Sstevel@tonic-gate return; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex)); 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate switch (op) { 807*0Sstevel@tonic-gate case CVC_BBSRAM_BREAK: /* A console break (L1-A) */ 808*0Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 809*0Sstevel@tonic-gate break; 810*0Sstevel@tonic-gate case CVC_BBSRAM_DISCONNECT: /* Break connection, hang up */ 811*0Sstevel@tonic-gate if (cvcinput_q && cvc_hangup_ok) 812*0Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 813*0Sstevel@tonic-gate break; 814*0Sstevel@tonic-gate case CVC_BBSRAM_VIA_NET: /* console via network */ 815*0Sstevel@tonic-gate via_bbsram = 0; 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * stop periodic flushing of output to BBSRAM 818*0Sstevel@tonic-gate * only if cvcredir/cvcd are present 819*0Sstevel@tonic-gate */ 820*0Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 821*0Sstevel@tonic-gate if (cvcoutput_q != NULL) { 822*0Sstevel@tonic-gate stop_timeout = 1; 823*0Sstevel@tonic-gate if (cvc_timeout_id != (timeout_id_t)-1) { 824*0Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 825*0Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate rw_exit(&cvclock); 829*0Sstevel@tonic-gate break; 830*0Sstevel@tonic-gate case CVC_BBSRAM_VIA_BBSRAM: /* console via bbsram */ 831*0Sstevel@tonic-gate via_bbsram = 1; 832*0Sstevel@tonic-gate /* start periodic flushing of ouput to BBSRAM */ 833*0Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 834*0Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 835*0Sstevel@tonic-gate stop_timeout = 0; 836*0Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, 837*0Sstevel@tonic-gate NULL, drv_usectohz(TIMEOUT_DELAY)); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate rw_exit(&cvclock); 840*0Sstevel@tonic-gate break; 841*0Sstevel@tonic-gate case CVC_BBSRAM_CLOSE_NET: 842*0Sstevel@tonic-gate /* 843*0Sstevel@tonic-gate * Send a hangup control message upstream to cvcd 844*0Sstevel@tonic-gate * thru cvcredir. This is an attempt to close 845*0Sstevel@tonic-gate * out any existing network connection(if any). 846*0Sstevel@tonic-gate * cvcoutput_q should point to the cvcredir's read 847*0Sstevel@tonic-gate * queue. 848*0Sstevel@tonic-gate */ 849*0Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 850*0Sstevel@tonic-gate if (cvcoutput_q != NULL) { 851*0Sstevel@tonic-gate (void) putnextctl(cvcoutput_q, M_HANGUP); 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate rw_exit(&cvclock); 854*0Sstevel@tonic-gate break; 855*0Sstevel@tonic-gate default: 856*0Sstevel@tonic-gate cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n", 857*0Sstevel@tonic-gate (unsigned int)op); 858*0Sstevel@tonic-gate break; 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate *op_reg = 0; 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate /* 865*0Sstevel@tonic-gate * cvc_putc() 866*0Sstevel@tonic-gate * Put a single character out to BBSRAM if space available. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate static void 869*0Sstevel@tonic-gate cvc_putc(register int c) 870*0Sstevel@tonic-gate { 871*0Sstevel@tonic-gate static int output_lost = 0; 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate if (c == '\n') 874*0Sstevel@tonic-gate cvc_putc('\r'); 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 877*0Sstevel@tonic-gate /* 878*0Sstevel@tonic-gate * Just exit if the buffer is already full. 879*0Sstevel@tonic-gate * It will be up to cvc_flush_buf() to flush the buffer. 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate if (cvc_output_count == MAX_XFER_OUTPUT) { 882*0Sstevel@tonic-gate output_lost = 1; 883*0Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 884*0Sstevel@tonic-gate return; 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate if (output_lost) 887*0Sstevel@tonic-gate prom_printf("WARNING: overflow of cvc output buffer, " 888*0Sstevel@tonic-gate "output lost!"); 889*0Sstevel@tonic-gate output_lost = 0; 890*0Sstevel@tonic-gate cvc_output_buffer[cvc_output_count] = (unsigned char)c; 891*0Sstevel@tonic-gate cvc_output_count++; 892*0Sstevel@tonic-gate if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) { 893*0Sstevel@tonic-gate /* flush cvc's internal output buffer to BBSRAM */ 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate /* 896*0Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 897*0Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP 898*0Sstevel@tonic-gate */ 899*0Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 900*0Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 901*0Sstevel@tonic-gate if (stop_bbsram) { 902*0Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 903*0Sstevel@tonic-gate return; 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate DELAY(1000); 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 908*0Sstevel@tonic-gate (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count), 909*0Sstevel@tonic-gate cvc_output_count); 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 912*0Sstevel@tonic-gate cvc_output_count = 0; 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 915*0Sstevel@tonic-gate } 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate /* 919*0Sstevel@tonic-gate * cvc_flush_buf() 920*0Sstevel@tonic-gate * Flush cvc's internal output buffer to BBSRAM at regular intervals. 921*0Sstevel@tonic-gate * This should only be done if cvcd is not running or the user (via the cvc 922*0Sstevel@tonic-gate * application on the SSP) has requested that i/o go through BBSRAM. 923*0Sstevel@tonic-gate */ 924*0Sstevel@tonic-gate /* ARGSUSED */ 925*0Sstevel@tonic-gate static void 926*0Sstevel@tonic-gate cvc_flush_buf(void *notused) 927*0Sstevel@tonic-gate { 928*0Sstevel@tonic-gate if (stop_timeout) 929*0Sstevel@tonic-gate return; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 932*0Sstevel@tonic-gate if (cvc_output_count != 0) { 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 935*0Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP. 936*0Sstevel@tonic-gate */ 937*0Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 938*0Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 939*0Sstevel@tonic-gate if (stop_bbsram) 940*0Sstevel@tonic-gate goto exit; 941*0Sstevel@tonic-gate DELAY(1000); 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 945*0Sstevel@tonic-gate (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count, 946*0Sstevel@tonic-gate cvc_output_count); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 949*0Sstevel@tonic-gate cvc_output_count = 0; 950*0Sstevel@tonic-gate } 951*0Sstevel@tonic-gate exit: 952*0Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 953*0Sstevel@tonic-gate /* rw_enter(&cvclock, RW_WRITER); */ 954*0Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 955*0Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 956*0Sstevel@tonic-gate /* rw_exit(&cvclock); */ 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate /* 961*0Sstevel@tonic-gate * cvc_getstr() 962*0Sstevel@tonic-gate * Poll BBSRAM for console input while available. 963*0Sstevel@tonic-gate */ 964*0Sstevel@tonic-gate static void 965*0Sstevel@tonic-gate cvc_getstr(char *cp) 966*0Sstevel@tonic-gate { 967*0Sstevel@tonic-gate short count; 968*0Sstevel@tonic-gate volatile char *lp; 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 971*0Sstevel@tonic-gate /* Poll BBSRAM for input */ 972*0Sstevel@tonic-gate do { 973*0Sstevel@tonic-gate if (stop_bbsram) { 974*0Sstevel@tonic-gate *cp = '\0'; /* set string to zero-length */ 975*0Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 976*0Sstevel@tonic-gate return; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate /* 979*0Sstevel@tonic-gate * Use a smaller delay between checks of BBSRAM for input 980*0Sstevel@tonic-gate * when cvcd/cvcredir are not running or "via_bbsram" has 981*0Sstevel@tonic-gate * been set. 982*0Sstevel@tonic-gate * We don't go away completely when i/o is going through the 983*0Sstevel@tonic-gate * network via cvcd since a command may be sent via BBSRAM 984*0Sstevel@tonic-gate * to switch if the network is down or hung. 985*0Sstevel@tonic-gate */ 986*0Sstevel@tonic-gate if ((cvcoutput_q == NULL) || (via_bbsram)) 987*0Sstevel@tonic-gate delay(drv_usectohz(100000)); 988*0Sstevel@tonic-gate else 989*0Sstevel@tonic-gate delay(drv_usectohz(1000000)); 990*0Sstevel@tonic-gate cvc_bbsram_ops(BBSRAM_CONTROL_REG); 991*0Sstevel@tonic-gate count = BBSRAM_INPUT_COUNT; 992*0Sstevel@tonic-gate } while (count == 0); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate lp = BBSRAM_INPUT_BUF - count; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate while (count--) { 997*0Sstevel@tonic-gate *cp++ = *lp++; 998*0Sstevel@tonic-gate } 999*0Sstevel@tonic-gate *cp = '\0'; 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate BBSRAM_INPUT_COUNT = 0; 1002*0Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 1003*0Sstevel@tonic-gate } 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * cvc_input_daemon() 1008*0Sstevel@tonic-gate * this function runs as a separate kernel thread and polls BBSRAM for 1009*0Sstevel@tonic-gate * input, and possibly put it on read stream for the console. 1010*0Sstevel@tonic-gate * There are two poll rates (implemented in cvc_getstr): 1011*0Sstevel@tonic-gate * 100 000 uS (10 Hz) - no cvcd communications || via_bbsram 1012*0Sstevel@tonic-gate * 1000 000 uS ( 1 Hz) - cvcd communications 1013*0Sstevel@tonic-gate * This continues to run even if there are network console communications 1014*0Sstevel@tonic-gate * in order to handle out-of-band signaling. 1015*0Sstevel@tonic-gate */ 1016*0Sstevel@tonic-gate static void 1017*0Sstevel@tonic-gate cvc_input_daemon(void) 1018*0Sstevel@tonic-gate { 1019*0Sstevel@tonic-gate char linebuf[MAX_XFER_INPUT]; 1020*0Sstevel@tonic-gate char *cp; 1021*0Sstevel@tonic-gate mblk_t *mbp; 1022*0Sstevel@tonic-gate int c; 1023*0Sstevel@tonic-gate int dropped_read = 0; 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate for (;;) { 1026*0Sstevel@tonic-gate cvc_getstr(linebuf); 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate mbp = allocb(strlen(linebuf), BPRI_MED); 1029*0Sstevel@tonic-gate if (mbp == NULL) { /* drop it & go on if no buffer */ 1030*0Sstevel@tonic-gate if (!dropped_read) { 1031*0Sstevel@tonic-gate cmn_err(CE_WARN, 1032*0Sstevel@tonic-gate "cvc_input_daemon: " 1033*0Sstevel@tonic-gate "dropping BBSRAM reads\n"); 1034*0Sstevel@tonic-gate } 1035*0Sstevel@tonic-gate dropped_read++; 1036*0Sstevel@tonic-gate continue; 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate if (dropped_read) { 1039*0Sstevel@tonic-gate cmn_err(CE_WARN, 1040*0Sstevel@tonic-gate "cvc_input_daemon: dropped %d BBSRAM reads\n", 1041*0Sstevel@tonic-gate dropped_read); 1042*0Sstevel@tonic-gate dropped_read = 0; 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate for (cp = linebuf; *cp != '\0'; cp++) { 1046*0Sstevel@tonic-gate c = (int)*cp; 1047*0Sstevel@tonic-gate if (c == '\r') 1048*0Sstevel@tonic-gate c = '\n'; 1049*0Sstevel@tonic-gate c &= 0177; 1050*0Sstevel@tonic-gate *mbp->b_wptr = (char)c; 1051*0Sstevel@tonic-gate mbp->b_wptr++; 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate mutex_enter(&cvcmutex); 1054*0Sstevel@tonic-gate if (input_ok) { 1055*0Sstevel@tonic-gate if (cvcinput_q == NULL) { 1056*0Sstevel@tonic-gate cmn_err(CE_WARN, 1057*0Sstevel@tonic-gate "cvc_input_daemon: cvcinput_q is NULL!"); 1058*0Sstevel@tonic-gate } else { 1059*0Sstevel@tonic-gate putnext(cvcinput_q, mbp); 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate } else { 1062*0Sstevel@tonic-gate freemsg(mbp); 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate mutex_exit(&cvcmutex); 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate /* NOTREACHED */ 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate /* 1072*0Sstevel@tonic-gate * cvc_bbsram_stop() 1073*0Sstevel@tonic-gate * Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when 1074*0Sstevel@tonic-gate * mapping in BBSRAM to a virtual address. 1075*0Sstevel@tonic-gate */ 1076*0Sstevel@tonic-gate static void 1077*0Sstevel@tonic-gate cvc_bbsram_stop(void) 1078*0Sstevel@tonic-gate { 1079*0Sstevel@tonic-gate stop_bbsram = 1; 1080*0Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 1081*0Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate /* 1086*0Sstevel@tonic-gate * cvc_bbsram_start() 1087*0Sstevel@tonic-gate * Allow accesses to BBSRAM, used by cvc_assign_iocpu() after 1088*0Sstevel@tonic-gate * BBSRAM has been mapped to a virtual address. 1089*0Sstevel@tonic-gate */ 1090*0Sstevel@tonic-gate static void 1091*0Sstevel@tonic-gate cvc_bbsram_start(void) 1092*0Sstevel@tonic-gate { 1093*0Sstevel@tonic-gate stop_bbsram = 0; 1094*0Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 1095*0Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * cvc_assign_iocpu() 1101*0Sstevel@tonic-gate * Map in BBSRAM to a virtual address 1102*0Sstevel@tonic-gate * This called by the kernel with the cpu id of cpu zero. 1103*0Sstevel@tonic-gate */ 1104*0Sstevel@tonic-gate void 1105*0Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu) 1106*0Sstevel@tonic-gate { 1107*0Sstevel@tonic-gate processorid_t oldcpu = cvc_iocpu; 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate if (newcpu == oldcpu) 1110*0Sstevel@tonic-gate return; 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu); 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate cvc_bbsram_stop(); 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate cvc_iocpu = newcpu; 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate cvc_bbsram_start(); 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate if (oldcpu != -1) 1121*0Sstevel@tonic-gate cvc_iobuf_mapout(oldcpu); 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate 1125*0Sstevel@tonic-gate /* 1126*0Sstevel@tonic-gate * cvc_iobuf_mapin() 1127*0Sstevel@tonic-gate * Map in the cvc bbsram i/o buffer into kernel space. 1128*0Sstevel@tonic-gate */ 1129*0Sstevel@tonic-gate static caddr_t 1130*0Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id) 1131*0Sstevel@tonic-gate { 1132*0Sstevel@tonic-gate caddr_t cvaddr; 1133*0Sstevel@tonic-gate uint64_t cvc_iobuf_physaddr; 1134*0Sstevel@tonic-gate pfn_t pfn; 1135*0Sstevel@tonic-gate uint_t num_pages; 1136*0Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate ASSERT(cpu_sgnblkp[cpu_id] != NULL); 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate /* 1141*0Sstevel@tonic-gate * First construct the physical base address of the bbsram 1142*0Sstevel@tonic-gate * in Starfire PSI space associated with this cpu in question. 1143*0Sstevel@tonic-gate */ 1144*0Sstevel@tonic-gate cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE; 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate /* 1147*0Sstevel@tonic-gate * Next add the cvc i/o buffer offset obtained from the 1148*0Sstevel@tonic-gate * sigblock to get cvc iobuf physical address 1149*0Sstevel@tonic-gate */ 1150*0Sstevel@tonic-gate cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off; 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate /* Get the page frame number */ 1153*0Sstevel@tonic-gate pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate /* Calculate how many pages we need to map in */ 1156*0Sstevel@tonic-gate num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr 1157*0Sstevel@tonic-gate & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t))); 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate /* 1160*0Sstevel@tonic-gate * Map in the cvc iobuf 1161*0Sstevel@tonic-gate */ 1162*0Sstevel@tonic-gate cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn, 1165*0Sstevel@tonic-gate PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr 1168*0Sstevel@tonic-gate & MMU_PAGEOFFSET))); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate /* 1173*0Sstevel@tonic-gate * cvc_iobuf_mapout() 1174*0Sstevel@tonic-gate * Map out the cvc iobuf from kernel space 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate static void 1177*0Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id) 1178*0Sstevel@tonic-gate { 1179*0Sstevel@tonic-gate caddr_t cvaddr; 1180*0Sstevel@tonic-gate size_t num_pages; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate if ((cvaddr = cvc_iobufp[cpu_id]) == 0) { 1183*0Sstevel@tonic-gate /* already unmapped - return */ 1184*0Sstevel@tonic-gate return; 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* Calculate how many pages we need to map out */ 1188*0Sstevel@tonic-gate num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) + 1189*0Sstevel@tonic-gate sizeof (sigb_cvc_t))); 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate /* Get cvaddr to the start of the page boundary */ 1192*0Sstevel@tonic-gate cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK)); 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK); 1195*0Sstevel@tonic-gate vmem_free(heap_arena, cvaddr, ptob(num_pages)); 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate cvc_iobufp[cpu_id] = NULL; 1198*0Sstevel@tonic-gate } 1199