10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*930Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * MT STREAMS Virtual Console Device Driver 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/sysmacros.h> 350Sstevel@tonic-gate #include <sys/processor.h> 360Sstevel@tonic-gate #include <sys/cpuvar.h> 370Sstevel@tonic-gate #include <sys/open.h> 380Sstevel@tonic-gate #include <sys/param.h> 390Sstevel@tonic-gate #include <sys/systm.h> 400Sstevel@tonic-gate #include <sys/signal.h> 410Sstevel@tonic-gate #include <sys/cred.h> 420Sstevel@tonic-gate #include <sys/user.h> 430Sstevel@tonic-gate #include <sys/proc.h> 440Sstevel@tonic-gate #include <sys/vnode.h> 450Sstevel@tonic-gate #include <sys/uio.h> 460Sstevel@tonic-gate #include <sys/buf.h> 470Sstevel@tonic-gate #include <sys/file.h> 480Sstevel@tonic-gate #include <sys/kmem.h> 490Sstevel@tonic-gate #include <sys/vmem.h> 500Sstevel@tonic-gate #include <sys/stat.h> 510Sstevel@tonic-gate #include <sys/stream.h> 520Sstevel@tonic-gate #include <sys/stropts.h> 530Sstevel@tonic-gate #include <sys/strsubr.h> 540Sstevel@tonic-gate #include <sys/strsun.h> 550Sstevel@tonic-gate #include <sys/tty.h> 560Sstevel@tonic-gate #include <sys/ptyvar.h> 570Sstevel@tonic-gate #include <sys/poll.h> 580Sstevel@tonic-gate #include <sys/debug.h> 590Sstevel@tonic-gate #include <sys/conf.h> 600Sstevel@tonic-gate 610Sstevel@tonic-gate #include <sys/starfire.h> 620Sstevel@tonic-gate #include <sys/mman.h> 630Sstevel@tonic-gate #include <vm/seg_kmem.h> 640Sstevel@tonic-gate 650Sstevel@tonic-gate #include <sys/ddi.h> 660Sstevel@tonic-gate #include <sys/sunddi.h> 670Sstevel@tonic-gate #include <sys/errno.h> 680Sstevel@tonic-gate #include <sys/modctl.h> 690Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 700Sstevel@tonic-gate #include <sys/cvc.h> 710Sstevel@tonic-gate #include <sys/cpu_sgn.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate extern void prom_printf(char *fmt, ...); 740Sstevel@tonic-gate 750Sstevel@tonic-gate static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 760Sstevel@tonic-gate static int cvc_attach(dev_info_t *, ddi_attach_cmd_t); 770Sstevel@tonic-gate static int cvc_detach(dev_info_t *, ddi_detach_cmd_t); 780Sstevel@tonic-gate static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *); 790Sstevel@tonic-gate static int cvc_close(queue_t *, int, cred_t *); 800Sstevel@tonic-gate static int cvc_wput(queue_t *, mblk_t *); 810Sstevel@tonic-gate static int cvc_wsrv(queue_t *); 820Sstevel@tonic-gate static void cvc_ioctl(queue_t *, mblk_t *); 830Sstevel@tonic-gate static void cvc_ack(mblk_t *, mblk_t *, uint_t); 840Sstevel@tonic-gate static void cvc_reioctl(void *); 850Sstevel@tonic-gate static void cvc_input_daemon(void); 860Sstevel@tonic-gate static void cvc_putc(register int); 870Sstevel@tonic-gate static void cvc_flush_buf(void *); 880Sstevel@tonic-gate static void cvc_bbsram_ops(volatile uchar_t *); 890Sstevel@tonic-gate 900Sstevel@tonic-gate static caddr_t cvc_iobuf_mapin(processorid_t); 910Sstevel@tonic-gate static void cvc_iobuf_mapout(processorid_t); 920Sstevel@tonic-gate void cvc_assign_iocpu(processorid_t); 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * Private copy of devinfo pointer; cvc_info uses it. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate static dev_info_t *cvcdip; 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * This buffer is used to manage mapping in the I/O buffer that CVC 1010Sstevel@tonic-gate * uses when communicating with the SSP Client (netcon_server) via bbsram. 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate static caddr_t cvc_iobufp[NCPU]; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate typedef struct cvc_s { 1060Sstevel@tonic-gate bufcall_id_t cvc_wbufcid; 1070Sstevel@tonic-gate tty_common_t cvc_tty; 1080Sstevel@tonic-gate } cvc_t; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate cvc_t cvc_common_tty; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate static struct module_info cvcm_info = { 1130Sstevel@tonic-gate 1313, /* mi_idnum Bad luck number ;-) */ 1140Sstevel@tonic-gate "cvc", /* mi_idname */ 1150Sstevel@tonic-gate 0, /* mi_minpsz */ 1160Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 1170Sstevel@tonic-gate 2048, /* mi_hiwat */ 1180Sstevel@tonic-gate 2048 /* mi_lowat */ 1190Sstevel@tonic-gate }; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate static struct qinit cvcrinit = { 1220Sstevel@tonic-gate NULL, /* qi_putp */ 1230Sstevel@tonic-gate NULL, /* qi_srvp */ 1240Sstevel@tonic-gate cvc_open, /* qi_qopen */ 1250Sstevel@tonic-gate cvc_close, /* qi_qclose */ 1260Sstevel@tonic-gate NULL, /* qi_qadmin */ 1270Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 1280Sstevel@tonic-gate NULL /* qi_mstat */ 1290Sstevel@tonic-gate }; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate static struct qinit cvcwinit = { 1320Sstevel@tonic-gate cvc_wput, /* qi_putp */ 1330Sstevel@tonic-gate cvc_wsrv, /* qi_srvp */ 1340Sstevel@tonic-gate cvc_open, /* qi_qopen */ 1350Sstevel@tonic-gate cvc_close, /* qi_qclose */ 1360Sstevel@tonic-gate NULL, /* qi_qadmin */ 1370Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 1380Sstevel@tonic-gate NULL /* qi_mstat */ 1390Sstevel@tonic-gate }; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate struct streamtab cvcinfo = { 1420Sstevel@tonic-gate &cvcrinit, /* st_rdinit */ 1430Sstevel@tonic-gate &cvcwinit, /* st_wrinit */ 1440Sstevel@tonic-gate NULL, /* st_muxrinit */ 1450Sstevel@tonic-gate NULL /* st_muxwrinit */ 1460Sstevel@tonic-gate }; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate #define TIMEOUT_DELAY 100000 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate #define BBSRAM_INPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 1510Sstevel@tonic-gate + BBSRAM_INPUT_COUNT_OFF)) 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate #define BBSRAM_OUTPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 1540Sstevel@tonic-gate + BBSRAM_OUTPUT_COUNT_OFF)) 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate #define BBSRAM_INPUT_COUNT (*((volatile short *)BBSRAM_INPUT_BUF)) 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate #define BBSRAM_OUTPUT_COUNT (*((volatile short *)BBSRAM_OUTPUT_BUF)) 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate #define CVC_OUT_MAXSPIN 1024 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */ 1630Sstevel@tonic-gate #define BBSRAM_CONTROL_REG ((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \ 1640Sstevel@tonic-gate + CVC_IN_SIZE + CVC_OUT_SIZE)) 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static krwlock_t cvclock; /* lock protecting everything here */ 1670Sstevel@tonic-gate static queue_t *cvcinput_q; /* queue for console input */ 1680Sstevel@tonic-gate static queue_t *cvcoutput_q; /* queue for console output */ 1690Sstevel@tonic-gate static int cvc_instance = -1; 1700Sstevel@tonic-gate static int cvc_stopped = 0; 1710Sstevel@tonic-gate static int cvc_suspended = 0; 1720Sstevel@tonic-gate static int cvc_hangup_ok = 0; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static kthread_id_t cvc_input_daemon_thread; 1750Sstevel@tonic-gate static kmutex_t cvcmutex; /* protects input */ 1760Sstevel@tonic-gate static kmutex_t cvc_buf_mutex; /* protects internal output buffer */ 1770Sstevel@tonic-gate static kmutex_t cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */ 1780Sstevel@tonic-gate static int input_ok = 0; /* true when stream is valid */ 1790Sstevel@tonic-gate static int stop_bbsram = 1; /* true when BBSRAM is not usable */ 1800Sstevel@tonic-gate static int stop_timeout = 0; 1810Sstevel@tonic-gate static uchar_t cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */ 1820Sstevel@tonic-gate static ushort_t cvc_output_count = 0; 1830Sstevel@tonic-gate static int via_bbsram = 0; /* toggle switch */ 1840Sstevel@tonic-gate static timeout_id_t cvc_timeout_id = (timeout_id_t)-1; 1850Sstevel@tonic-gate static processorid_t cvc_iocpu = -1; /* cpu id of cpu zero */ 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * Module linkage information for the kernel. 1890Sstevel@tonic-gate */ 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach, 1920Sstevel@tonic-gate nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate static struct modldrv modldrv = { 1950Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 1960Sstevel@tonic-gate "CVC driver 'cvc' v%I%", 1970Sstevel@tonic-gate &cvcops, /* driver ops */ 1980Sstevel@tonic-gate }; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate static struct modlinkage modlinkage = { 2010Sstevel@tonic-gate MODREV_1, 2020Sstevel@tonic-gate &modldrv, 2030Sstevel@tonic-gate NULL 2040Sstevel@tonic-gate }; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate int 2070Sstevel@tonic-gate _init(void) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate int status; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate status = mod_install(&modlinkage); 2120Sstevel@tonic-gate if (status == 0) { 2130Sstevel@tonic-gate mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate return (status); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate int 2190Sstevel@tonic-gate _fini(void) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate return (EBUSY); 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate int 2250Sstevel@tonic-gate _info(struct modinfo *modinfop) 2260Sstevel@tonic-gate { 2270Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * DDI glue routines. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* ARGSUSED */ 2350Sstevel@tonic-gate static int 2360Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2370Sstevel@tonic-gate { 2380Sstevel@tonic-gate static char been_here = 0; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (cmd == DDI_RESUME) { 2410Sstevel@tonic-gate cvc_suspended = 0; 2420Sstevel@tonic-gate return (DDI_SUCCESS); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate mutex_enter(&cvcmutex); 2460Sstevel@tonic-gate if (!been_here) { 2470Sstevel@tonic-gate been_here = 1; 2480Sstevel@tonic-gate mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL); 2490Sstevel@tonic-gate mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL); 2500Sstevel@tonic-gate rw_init(&cvclock, NULL, RW_DRIVER, NULL); 2510Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 2520Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 2530Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 2540Sstevel@tonic-gate rw_exit(&cvclock); 2550Sstevel@tonic-gate cvc_instance = ddi_get_instance(devi); 2560Sstevel@tonic-gate } else { 2570Sstevel@tonic-gate #if defined(DEBUG) 2580Sstevel@tonic-gate cmn_err(CE_NOTE, 2590Sstevel@tonic-gate "cvc_attach: called multiple times!! (instance = %d)", 2600Sstevel@tonic-gate ddi_get_instance(devi)); 2610Sstevel@tonic-gate #endif /* DEBUG */ 2620Sstevel@tonic-gate return (DDI_SUCCESS); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate mutex_exit(&cvcmutex); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate if (ddi_create_minor_node(devi, "cvc", S_IFCHR, 2670Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2680Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2690Sstevel@tonic-gate return (-1); 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate cvcdip = devi; 2720Sstevel@tonic-gate cvcinput_q = NULL; 2730Sstevel@tonic-gate cvcoutput_q = NULL; 2740Sstevel@tonic-gate return (DDI_SUCCESS); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate static int 2780Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2790Sstevel@tonic-gate { 2800Sstevel@tonic-gate if (cmd == DDI_SUSPEND) { 2810Sstevel@tonic-gate cvc_suspended = 1; 2820Sstevel@tonic-gate } else { 2830Sstevel@tonic-gate if (cmd != DDI_DETACH) { 2840Sstevel@tonic-gate return (DDI_FAILURE); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * XXX this doesn't even begin to address the detach 2880Sstevel@tonic-gate * issues - it doesn't terminate the outstanding thread, 2890Sstevel@tonic-gate * it doesn't clean up mutexes, kill the timeout routine 2900Sstevel@tonic-gate * etc. 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate if (cvc_instance == ddi_get_instance(dip)) { 2930Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate return (DDI_SUCCESS); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* ARGSUSED */ 3000Sstevel@tonic-gate static int 3010Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate register int error; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate switch (infocmd) { 3060Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 3070Sstevel@tonic-gate if (cvcdip == NULL) { 3080Sstevel@tonic-gate error = DDI_FAILURE; 3090Sstevel@tonic-gate } else { 3100Sstevel@tonic-gate *result = (void *)cvcdip; 3110Sstevel@tonic-gate error = DDI_SUCCESS; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate break; 3140Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 3150Sstevel@tonic-gate *result = (void *)0; 3160Sstevel@tonic-gate error = DDI_SUCCESS; 3170Sstevel@tonic-gate break; 3180Sstevel@tonic-gate default: 3190Sstevel@tonic-gate error = DDI_FAILURE; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate return (error); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* ARGSUSED */ 3250Sstevel@tonic-gate static int 3260Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate register int unit = getminor(*devp); 3290Sstevel@tonic-gate register int err = 0; 3300Sstevel@tonic-gate tty_common_t *tty; 3310Sstevel@tonic-gate cvc_t *cp; 3320Sstevel@tonic-gate static int input_daemon_started; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (unit != 0) 3350Sstevel@tonic-gate return (ENXIO); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (q->q_ptr) 3380Sstevel@tonic-gate return (0); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate cp = (cvc_t *)&cvc_common_tty; 3410Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 3420Sstevel@tonic-gate cp->cvc_wbufcid = 0; 3430Sstevel@tonic-gate tty = &cp->cvc_tty; 3440Sstevel@tonic-gate tty->t_readq = q; 3450Sstevel@tonic-gate tty->t_writeq = WR(q); 3460Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)cp; 3470Sstevel@tonic-gate cvcinput_q = RD(q); /* save for cvc_redir */ 3480Sstevel@tonic-gate qprocson(q); 3490Sstevel@tonic-gate mutex_enter(&cvcmutex); 3500Sstevel@tonic-gate input_ok = 1; 3510Sstevel@tonic-gate if (!input_daemon_started) { 3520Sstevel@tonic-gate extern struct cpu *SIGBCPU; /* bugid4141050 */ 3530Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate input_daemon_started = 1; 3560Sstevel@tonic-gate mutex_exit(&cvcmutex); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL); 3590Sstevel@tonic-gate cvc_assign_iocpu(SIGBCPU->cpu_id); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate cvc_input_daemon_thread = thread_create(NULL, 0, 3620Sstevel@tonic-gate cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); 3630Sstevel@tonic-gate } else { 3640Sstevel@tonic-gate mutex_exit(&cvcmutex); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate #ifdef lint 3670Sstevel@tonic-gate cvc_input_daemon_thread = cvc_input_daemon_thread; 3680Sstevel@tonic-gate #endif 3690Sstevel@tonic-gate return (err); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* ARGSUSED */ 3730Sstevel@tonic-gate static int 3740Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate register int err = 0; 3770Sstevel@tonic-gate register cvc_t *cp; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate mutex_enter(&cvcmutex); 3800Sstevel@tonic-gate input_ok = 0; 3810Sstevel@tonic-gate mutex_exit(&cvcmutex); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate cp = q->q_ptr; 3840Sstevel@tonic-gate if (cp->cvc_wbufcid != 0) { 3850Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate ttycommon_close(&cp->cvc_tty); 3880Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = NULL; 3890Sstevel@tonic-gate cvcinput_q = NULL; 3900Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 3910Sstevel@tonic-gate qprocsoff(q); 3920Sstevel@tonic-gate return (err); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * cvc_wput() 3980Sstevel@tonic-gate * cn driver does a strwrite of console output data to rconsvp which 3990Sstevel@tonic-gate * has been set by consconfig. The data enters the cvc stream at the 4000Sstevel@tonic-gate * streamhead and flows thru ttycompat and ldterm which have been 4010Sstevel@tonic-gate * pushed on the stream. Console output data gets sent out either 4020Sstevel@tonic-gate * by cvcredir (if there is a cvcd running) or bbsram (if there 4030Sstevel@tonic-gate * isn't). 4040Sstevel@tonic-gate * Data is sent to the cvcredir via it's read q which is cvcoutput_q 4050Sstevel@tonic-gate * and was set in cvc_register(). 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate static int 4080Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate int error = 0; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 4130Sstevel@tonic-gate switch (mp->b_datap->db_type) { 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate case M_IOCTL: 4160Sstevel@tonic-gate case M_CTL: 4170Sstevel@tonic-gate cvc_ioctl(q, mp); 4180Sstevel@tonic-gate break; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate case M_FLUSH: 4210Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * Flush our write queue. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate flushq(q, FLUSHDATA); 4260Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4290Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 4300Sstevel@tonic-gate qreply(q, mp); 4310Sstevel@tonic-gate } else 4320Sstevel@tonic-gate freemsg(mp); 4330Sstevel@tonic-gate break; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate case M_STOP: 4360Sstevel@tonic-gate cvc_stopped = 1; 4370Sstevel@tonic-gate freemsg(mp); 4380Sstevel@tonic-gate break; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate case M_START: 4410Sstevel@tonic-gate cvc_stopped = 0; 4420Sstevel@tonic-gate freemsg(mp); 4430Sstevel@tonic-gate qenable(q); /* Start up delayed messages */ 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate case M_READ: 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * ldterm handles this (VMIN/VTIME processing). 4490Sstevel@tonic-gate */ 4500Sstevel@tonic-gate freemsg(mp); 4510Sstevel@tonic-gate break; 4520Sstevel@tonic-gate default: 453*930Smathue cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%p", mp); 4540Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_wput: type = 0x%x", 4550Sstevel@tonic-gate mp->b_datap->db_type); 4560Sstevel@tonic-gate /* FALLTHROUGH */ 4570Sstevel@tonic-gate #ifdef lint 4580Sstevel@tonic-gate break; 4590Sstevel@tonic-gate #endif 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate case M_DATA: 4620Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 4630Sstevel@tonic-gate (void) putq(q, mp); 4640Sstevel@tonic-gate break; 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Send it up past cvcredir module. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate putnext(cvcoutput_q, mp); 4710Sstevel@tonic-gate } else { 4720Sstevel@tonic-gate char *msgp, c; 4730Sstevel@tonic-gate mblk_t *mp2 = mp; 4740Sstevel@tonic-gate int count; 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate while (mp2 != NULL) { 4770Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 4780Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 4790Sstevel@tonic-gate while (count > 0) { 4800Sstevel@tonic-gate count--; 4810Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 4820Sstevel@tonic-gate /* don't print NULs */ 4830Sstevel@tonic-gate cvc_putc(c); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate mp2 = mp2->b_cont; 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate freemsg(mp); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate rw_exit(&cvclock); 4940Sstevel@tonic-gate return (error); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate static int cvc_wsrv_count = 0; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate static int 5000Sstevel@tonic-gate cvc_wsrv(queue_t *q) 5010Sstevel@tonic-gate { 5020Sstevel@tonic-gate register mblk_t *mp; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate cvc_wsrv_count++; 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 5070Sstevel@tonic-gate return (0); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 5110Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 5120Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * Send it up past cvcredir module. 5150Sstevel@tonic-gate */ 5160Sstevel@tonic-gate putnext(cvcoutput_q, mp); 5170Sstevel@tonic-gate } else { 5180Sstevel@tonic-gate char *msgp, c; 5190Sstevel@tonic-gate mblk_t *mp2 = mp; 5200Sstevel@tonic-gate int count; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate while (mp2 != NULL) { 5230Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 5240Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 5250Sstevel@tonic-gate while (count > 0) { 5260Sstevel@tonic-gate count--; 5270Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 5280Sstevel@tonic-gate /* don't print NULs */ 5290Sstevel@tonic-gate cvc_putc(c); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate mp2 = mp2->b_cont; 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate freemsg(mp); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate rw_exit(&cvclock); 5380Sstevel@tonic-gate return (0); 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * cvc_ioctl() 5440Sstevel@tonic-gate * handle normal console ioctls. 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate static void 5470Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate register struct iocblk *iocp; 5500Sstevel@tonic-gate register tty_common_t *tty; 5510Sstevel@tonic-gate register cvc_t *cp; 5520Sstevel@tonic-gate int datasize; 5530Sstevel@tonic-gate int error = 0; 5540Sstevel@tonic-gate mblk_t *tmp; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate cp = q->q_ptr; 5570Sstevel@tonic-gate tty = &cp->cvc_tty; 5580Sstevel@tonic-gate if (tty->t_iocpending != NULL) { 5590Sstevel@tonic-gate freemsg(tty->t_iocpending); 5600Sstevel@tonic-gate tty->t_iocpending = NULL; 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate datasize = ttycommon_ioctl(tty, q, mp, &error); 5630Sstevel@tonic-gate if (datasize != 0) { 5640Sstevel@tonic-gate if (cp->cvc_wbufcid) 5650Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 5660Sstevel@tonic-gate cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp); 5670Sstevel@tonic-gate return; 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate if (error < 0) { 5700Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate error = 0; 5750Sstevel@tonic-gate switch (iocp->ioc_cmd) { 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * Set modem bit ioctls. These are NOPs for us, since we 5790Sstevel@tonic-gate * dont control any hardware. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate case TCSBRK: 5820Sstevel@tonic-gate case TIOCSBRK: 5830Sstevel@tonic-gate case TIOCCBRK: 5840Sstevel@tonic-gate case TIOCMSET: 5850Sstevel@tonic-gate case TIOCMBIS: 5860Sstevel@tonic-gate case TIOCMBIC: 5870Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 5880Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 5890Sstevel@tonic-gate } else { 5900Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate /* qreply done below */ 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * Get modem bits, we return 0 in mblk. 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate case TIOCMGET: 5990Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 6000Sstevel@tonic-gate if (tmp == NULL) { 6010Sstevel@tonic-gate miocnak(q, mp, 0, EAGAIN); 6020Sstevel@tonic-gate return; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate *(int *)tmp->b_rptr = 0; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 6070Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 6080Sstevel@tonic-gate else 6090Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 6100Sstevel@tonic-gate /* qreply done below */ 6110Sstevel@tonic-gate break; 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate default: 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 6160Sstevel@tonic-gate */ 6170Sstevel@tonic-gate error = EINVAL; 6180Sstevel@tonic-gate break; 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate if (error != 0) { 6220Sstevel@tonic-gate iocp->ioc_error = error; 6230Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate qreply(q, mp); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate /* 6310Sstevel@tonic-gate * cvc_redir() 6320Sstevel@tonic-gate * called from cvcredir:cvcr_wput() to handle console input 6330Sstevel@tonic-gate * data. This routine puts the cvcredir write (downstream) data 6340Sstevel@tonic-gate * onto the cvc read (upstream) queues. Note that if `mp' is 6350Sstevel@tonic-gate * an M_IOCTL, then it may be reused by the caller to send back 6360Sstevel@tonic-gate * an M_IOCACK or M_IOCNAK. 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate int 6390Sstevel@tonic-gate cvc_redir(mblk_t *mp) 6400Sstevel@tonic-gate { 6410Sstevel@tonic-gate register struct iocblk *iocp; 6420Sstevel@tonic-gate register tty_common_t *tty; 6430Sstevel@tonic-gate register cvc_t *cp; 6440Sstevel@tonic-gate struct winsize *ws; 6450Sstevel@tonic-gate int error; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate if (cvcinput_q == NULL) { 6480Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); 6490Sstevel@tonic-gate return (EINVAL); 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate if (DB_TYPE(mp) != M_IOCTL) { 6530Sstevel@tonic-gate putnext(cvcinput_q, mp); 6540Sstevel@tonic-gate return (0); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6580Sstevel@tonic-gate if (iocp->ioc_cmd == TIOCSWINSZ) { 6590Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct winsize)); 6600Sstevel@tonic-gate if (error != 0) 6610Sstevel@tonic-gate return (error); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 6640Sstevel@tonic-gate cp = cvcinput_q->q_ptr; 6650Sstevel@tonic-gate tty = &cp->cvc_tty; 6660Sstevel@tonic-gate mutex_enter(&tty->t_excl); 6670Sstevel@tonic-gate if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) { 6680Sstevel@tonic-gate tty->t_size = *ws; 6690Sstevel@tonic-gate mutex_exit(&tty->t_excl); 6700Sstevel@tonic-gate (void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH); 6710Sstevel@tonic-gate } else 6720Sstevel@tonic-gate mutex_exit(&tty->t_excl); 6730Sstevel@tonic-gate } else { 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * It must be a CVC_DISCONNECT, send hangup. 6760Sstevel@tonic-gate */ 6770Sstevel@tonic-gate ASSERT(iocp->ioc_cmd == CVC_DISCONNECT); 6780Sstevel@tonic-gate if (cvc_hangup_ok) 6790Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate return (0); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate /* 6870Sstevel@tonic-gate * cvc_register() 6880Sstevel@tonic-gate * called from cvcredir to register it's queues. cvc 6890Sstevel@tonic-gate * receives data from cn via the streamhead and sends it to cvcredir 6900Sstevel@tonic-gate * via pointers to cvcredir's queues. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate int 6930Sstevel@tonic-gate cvc_register(queue_t *q) 6940Sstevel@tonic-gate { 6950Sstevel@tonic-gate int error = -1; 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate if (cvcinput_q == NULL) 6980Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: register w/ no console open!"); 6990Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 7000Sstevel@tonic-gate if (cvcoutput_q == NULL) { 7010Sstevel@tonic-gate cvcoutput_q = RD(q); /* Make sure its the upstream q */ 7020Sstevel@tonic-gate qprocson(cvcoutput_q); /* must be done within cvclock */ 7030Sstevel@tonic-gate error = 0; 7040Sstevel@tonic-gate } else { 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * cmn_err will call us, so release lock. 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate rw_exit(&cvclock); 7090Sstevel@tonic-gate if (cvcoutput_q == q) 7100Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: duplicate q!"); 7110Sstevel@tonic-gate else 712*930Smathue cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p", 7130Sstevel@tonic-gate q); 7140Sstevel@tonic-gate return (error); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* 7180Sstevel@tonic-gate * Unless "via_bbsram" is set, i/o will be going through cvcd, so 7190Sstevel@tonic-gate * stop flushing output to BBSRAM. 7200Sstevel@tonic-gate */ 7210Sstevel@tonic-gate if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) { 7220Sstevel@tonic-gate stop_timeout = 1; 7230Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 7240Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 7250Sstevel@tonic-gate cvc_hangup_ok = 1; 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate rw_exit(&cvclock); 7280Sstevel@tonic-gate return (error); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * cvc_unregister() 7340Sstevel@tonic-gate * called from cvcredir to clear pointers to its queues. 7350Sstevel@tonic-gate * cvcredir no longer wants to send or receive data. 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate void 7380Sstevel@tonic-gate cvc_unregister(queue_t *q) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 7410Sstevel@tonic-gate if (q == cvcoutput_q) { 7420Sstevel@tonic-gate qprocsoff(cvcoutput_q); /* must be done within cvclock */ 7430Sstevel@tonic-gate cvcoutput_q = NULL; 7440Sstevel@tonic-gate } else { 7450Sstevel@tonic-gate rw_exit(&cvclock); 746*930Smathue cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered", q); 7470Sstevel@tonic-gate return; 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* 7510Sstevel@tonic-gate * i/o will not be going through cvcd, start flushing output to 7520Sstevel@tonic-gate * BBSRAM 7530Sstevel@tonic-gate */ 7540Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 7550Sstevel@tonic-gate stop_timeout = 0; 7560Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 7570Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate rw_exit(&cvclock); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate /* 7630Sstevel@tonic-gate * cvc_reioctl() 7640Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able 7650Sstevel@tonic-gate * to allocate the buffer we need. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate static void 7680Sstevel@tonic-gate cvc_reioctl(void *unit) 7690Sstevel@tonic-gate { 7700Sstevel@tonic-gate register queue_t *q; 7710Sstevel@tonic-gate register mblk_t *mp; 7720Sstevel@tonic-gate register cvc_t *cp = (cvc_t *)unit; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * The bufcall is no longer pending. 7760Sstevel@tonic-gate */ 7770Sstevel@tonic-gate if (!cp->cvc_wbufcid) { 7780Sstevel@tonic-gate return; 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate cp->cvc_wbufcid = 0; 7810Sstevel@tonic-gate if ((q = cp->cvc_tty.t_writeq) == NULL) { 7820Sstevel@tonic-gate return; 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate if ((mp = cp->cvc_tty.t_iocpending) != NULL) { 7850Sstevel@tonic-gate /* not pending any more */ 7860Sstevel@tonic-gate cp->cvc_tty.t_iocpending = NULL; 7870Sstevel@tonic-gate cvc_ioctl(q, mp); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * cvc_bbsram_ops() 7940Sstevel@tonic-gate * Process commands sent to cvc from netcon_server via BBSRAM 7950Sstevel@tonic-gate */ 7960Sstevel@tonic-gate static void 7970Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg) 7980Sstevel@tonic-gate { 7990Sstevel@tonic-gate uchar_t op; 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if ((op = *op_reg) == 0) 8020Sstevel@tonic-gate return; 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex)); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate switch (op) { 8070Sstevel@tonic-gate case CVC_BBSRAM_BREAK: /* A console break (L1-A) */ 8080Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 8090Sstevel@tonic-gate break; 8100Sstevel@tonic-gate case CVC_BBSRAM_DISCONNECT: /* Break connection, hang up */ 8110Sstevel@tonic-gate if (cvcinput_q && cvc_hangup_ok) 8120Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 8130Sstevel@tonic-gate break; 8140Sstevel@tonic-gate case CVC_BBSRAM_VIA_NET: /* console via network */ 8150Sstevel@tonic-gate via_bbsram = 0; 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * stop periodic flushing of output to BBSRAM 8180Sstevel@tonic-gate * only if cvcredir/cvcd are present 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 8210Sstevel@tonic-gate if (cvcoutput_q != NULL) { 8220Sstevel@tonic-gate stop_timeout = 1; 8230Sstevel@tonic-gate if (cvc_timeout_id != (timeout_id_t)-1) { 8240Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 8250Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate rw_exit(&cvclock); 8290Sstevel@tonic-gate break; 8300Sstevel@tonic-gate case CVC_BBSRAM_VIA_BBSRAM: /* console via bbsram */ 8310Sstevel@tonic-gate via_bbsram = 1; 8320Sstevel@tonic-gate /* start periodic flushing of ouput to BBSRAM */ 8330Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 8340Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 8350Sstevel@tonic-gate stop_timeout = 0; 8360Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, 8370Sstevel@tonic-gate NULL, drv_usectohz(TIMEOUT_DELAY)); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate rw_exit(&cvclock); 8400Sstevel@tonic-gate break; 8410Sstevel@tonic-gate case CVC_BBSRAM_CLOSE_NET: 8420Sstevel@tonic-gate /* 8430Sstevel@tonic-gate * Send a hangup control message upstream to cvcd 8440Sstevel@tonic-gate * thru cvcredir. This is an attempt to close 8450Sstevel@tonic-gate * out any existing network connection(if any). 8460Sstevel@tonic-gate * cvcoutput_q should point to the cvcredir's read 8470Sstevel@tonic-gate * queue. 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 8500Sstevel@tonic-gate if (cvcoutput_q != NULL) { 8510Sstevel@tonic-gate (void) putnextctl(cvcoutput_q, M_HANGUP); 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate rw_exit(&cvclock); 8540Sstevel@tonic-gate break; 8550Sstevel@tonic-gate default: 8560Sstevel@tonic-gate cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n", 8570Sstevel@tonic-gate (unsigned int)op); 8580Sstevel@tonic-gate break; 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate *op_reg = 0; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate /* 8650Sstevel@tonic-gate * cvc_putc() 8660Sstevel@tonic-gate * Put a single character out to BBSRAM if space available. 8670Sstevel@tonic-gate */ 8680Sstevel@tonic-gate static void 8690Sstevel@tonic-gate cvc_putc(register int c) 8700Sstevel@tonic-gate { 8710Sstevel@tonic-gate static int output_lost = 0; 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate if (c == '\n') 8740Sstevel@tonic-gate cvc_putc('\r'); 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 8770Sstevel@tonic-gate /* 8780Sstevel@tonic-gate * Just exit if the buffer is already full. 8790Sstevel@tonic-gate * It will be up to cvc_flush_buf() to flush the buffer. 8800Sstevel@tonic-gate */ 8810Sstevel@tonic-gate if (cvc_output_count == MAX_XFER_OUTPUT) { 8820Sstevel@tonic-gate output_lost = 1; 8830Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 8840Sstevel@tonic-gate return; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate if (output_lost) 8870Sstevel@tonic-gate prom_printf("WARNING: overflow of cvc output buffer, " 8880Sstevel@tonic-gate "output lost!"); 8890Sstevel@tonic-gate output_lost = 0; 8900Sstevel@tonic-gate cvc_output_buffer[cvc_output_count] = (unsigned char)c; 8910Sstevel@tonic-gate cvc_output_count++; 8920Sstevel@tonic-gate if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) { 8930Sstevel@tonic-gate /* flush cvc's internal output buffer to BBSRAM */ 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /* 8960Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 8970Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP 8980Sstevel@tonic-gate */ 8990Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 9000Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 9010Sstevel@tonic-gate if (stop_bbsram) { 9020Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9030Sstevel@tonic-gate return; 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate DELAY(1000); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 9080Sstevel@tonic-gate (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count), 9090Sstevel@tonic-gate cvc_output_count); 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 9120Sstevel@tonic-gate cvc_output_count = 0; 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /* 9190Sstevel@tonic-gate * cvc_flush_buf() 9200Sstevel@tonic-gate * Flush cvc's internal output buffer to BBSRAM at regular intervals. 9210Sstevel@tonic-gate * This should only be done if cvcd is not running or the user (via the cvc 9220Sstevel@tonic-gate * application on the SSP) has requested that i/o go through BBSRAM. 9230Sstevel@tonic-gate */ 9240Sstevel@tonic-gate /* ARGSUSED */ 9250Sstevel@tonic-gate static void 9260Sstevel@tonic-gate cvc_flush_buf(void *notused) 9270Sstevel@tonic-gate { 9280Sstevel@tonic-gate if (stop_timeout) 9290Sstevel@tonic-gate return; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 9320Sstevel@tonic-gate if (cvc_output_count != 0) { 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 9350Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP. 9360Sstevel@tonic-gate */ 9370Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 9380Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 9390Sstevel@tonic-gate if (stop_bbsram) 9400Sstevel@tonic-gate goto exit; 9410Sstevel@tonic-gate DELAY(1000); 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 9450Sstevel@tonic-gate (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count, 9460Sstevel@tonic-gate cvc_output_count); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 9490Sstevel@tonic-gate cvc_output_count = 0; 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate exit: 9520Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9530Sstevel@tonic-gate /* rw_enter(&cvclock, RW_WRITER); */ 9540Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 9550Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 9560Sstevel@tonic-gate /* rw_exit(&cvclock); */ 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * cvc_getstr() 9620Sstevel@tonic-gate * Poll BBSRAM for console input while available. 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate static void 9650Sstevel@tonic-gate cvc_getstr(char *cp) 9660Sstevel@tonic-gate { 9670Sstevel@tonic-gate short count; 9680Sstevel@tonic-gate volatile char *lp; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 9710Sstevel@tonic-gate /* Poll BBSRAM for input */ 9720Sstevel@tonic-gate do { 9730Sstevel@tonic-gate if (stop_bbsram) { 9740Sstevel@tonic-gate *cp = '\0'; /* set string to zero-length */ 9750Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 9760Sstevel@tonic-gate return; 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Use a smaller delay between checks of BBSRAM for input 9800Sstevel@tonic-gate * when cvcd/cvcredir are not running or "via_bbsram" has 9810Sstevel@tonic-gate * been set. 9820Sstevel@tonic-gate * We don't go away completely when i/o is going through the 9830Sstevel@tonic-gate * network via cvcd since a command may be sent via BBSRAM 9840Sstevel@tonic-gate * to switch if the network is down or hung. 9850Sstevel@tonic-gate */ 9860Sstevel@tonic-gate if ((cvcoutput_q == NULL) || (via_bbsram)) 9870Sstevel@tonic-gate delay(drv_usectohz(100000)); 9880Sstevel@tonic-gate else 9890Sstevel@tonic-gate delay(drv_usectohz(1000000)); 9900Sstevel@tonic-gate cvc_bbsram_ops(BBSRAM_CONTROL_REG); 9910Sstevel@tonic-gate count = BBSRAM_INPUT_COUNT; 9920Sstevel@tonic-gate } while (count == 0); 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate lp = BBSRAM_INPUT_BUF - count; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate while (count--) { 9970Sstevel@tonic-gate *cp++ = *lp++; 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate *cp = '\0'; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate BBSRAM_INPUT_COUNT = 0; 10020Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate /* 10070Sstevel@tonic-gate * cvc_input_daemon() 10080Sstevel@tonic-gate * this function runs as a separate kernel thread and polls BBSRAM for 10090Sstevel@tonic-gate * input, and possibly put it on read stream for the console. 10100Sstevel@tonic-gate * There are two poll rates (implemented in cvc_getstr): 10110Sstevel@tonic-gate * 100 000 uS (10 Hz) - no cvcd communications || via_bbsram 10120Sstevel@tonic-gate * 1000 000 uS ( 1 Hz) - cvcd communications 10130Sstevel@tonic-gate * This continues to run even if there are network console communications 10140Sstevel@tonic-gate * in order to handle out-of-band signaling. 10150Sstevel@tonic-gate */ 10160Sstevel@tonic-gate static void 10170Sstevel@tonic-gate cvc_input_daemon(void) 10180Sstevel@tonic-gate { 10190Sstevel@tonic-gate char linebuf[MAX_XFER_INPUT]; 10200Sstevel@tonic-gate char *cp; 10210Sstevel@tonic-gate mblk_t *mbp; 10220Sstevel@tonic-gate int c; 10230Sstevel@tonic-gate int dropped_read = 0; 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate for (;;) { 10260Sstevel@tonic-gate cvc_getstr(linebuf); 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate mbp = allocb(strlen(linebuf), BPRI_MED); 10290Sstevel@tonic-gate if (mbp == NULL) { /* drop it & go on if no buffer */ 10300Sstevel@tonic-gate if (!dropped_read) { 10310Sstevel@tonic-gate cmn_err(CE_WARN, 10320Sstevel@tonic-gate "cvc_input_daemon: " 10330Sstevel@tonic-gate "dropping BBSRAM reads\n"); 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate dropped_read++; 10360Sstevel@tonic-gate continue; 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate if (dropped_read) { 10390Sstevel@tonic-gate cmn_err(CE_WARN, 10400Sstevel@tonic-gate "cvc_input_daemon: dropped %d BBSRAM reads\n", 10410Sstevel@tonic-gate dropped_read); 10420Sstevel@tonic-gate dropped_read = 0; 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate for (cp = linebuf; *cp != '\0'; cp++) { 10460Sstevel@tonic-gate c = (int)*cp; 10470Sstevel@tonic-gate if (c == '\r') 10480Sstevel@tonic-gate c = '\n'; 10490Sstevel@tonic-gate c &= 0177; 10500Sstevel@tonic-gate *mbp->b_wptr = (char)c; 10510Sstevel@tonic-gate mbp->b_wptr++; 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate mutex_enter(&cvcmutex); 10540Sstevel@tonic-gate if (input_ok) { 10550Sstevel@tonic-gate if (cvcinput_q == NULL) { 10560Sstevel@tonic-gate cmn_err(CE_WARN, 10570Sstevel@tonic-gate "cvc_input_daemon: cvcinput_q is NULL!"); 10580Sstevel@tonic-gate } else { 10590Sstevel@tonic-gate putnext(cvcinput_q, mbp); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate } else { 10620Sstevel@tonic-gate freemsg(mbp); 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate mutex_exit(&cvcmutex); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate /* NOTREACHED */ 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate /* 10720Sstevel@tonic-gate * cvc_bbsram_stop() 10730Sstevel@tonic-gate * Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when 10740Sstevel@tonic-gate * mapping in BBSRAM to a virtual address. 10750Sstevel@tonic-gate */ 10760Sstevel@tonic-gate static void 10770Sstevel@tonic-gate cvc_bbsram_stop(void) 10780Sstevel@tonic-gate { 10790Sstevel@tonic-gate stop_bbsram = 1; 10800Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 10810Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * cvc_bbsram_start() 10870Sstevel@tonic-gate * Allow accesses to BBSRAM, used by cvc_assign_iocpu() after 10880Sstevel@tonic-gate * BBSRAM has been mapped to a virtual address. 10890Sstevel@tonic-gate */ 10900Sstevel@tonic-gate static void 10910Sstevel@tonic-gate cvc_bbsram_start(void) 10920Sstevel@tonic-gate { 10930Sstevel@tonic-gate stop_bbsram = 0; 10940Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 10950Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * cvc_assign_iocpu() 11010Sstevel@tonic-gate * Map in BBSRAM to a virtual address 11020Sstevel@tonic-gate * This called by the kernel with the cpu id of cpu zero. 11030Sstevel@tonic-gate */ 11040Sstevel@tonic-gate void 11050Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu) 11060Sstevel@tonic-gate { 11070Sstevel@tonic-gate processorid_t oldcpu = cvc_iocpu; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (newcpu == oldcpu) 11100Sstevel@tonic-gate return; 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu); 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate cvc_bbsram_stop(); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate cvc_iocpu = newcpu; 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate cvc_bbsram_start(); 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate if (oldcpu != -1) 11210Sstevel@tonic-gate cvc_iobuf_mapout(oldcpu); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate /* 11260Sstevel@tonic-gate * cvc_iobuf_mapin() 11270Sstevel@tonic-gate * Map in the cvc bbsram i/o buffer into kernel space. 11280Sstevel@tonic-gate */ 11290Sstevel@tonic-gate static caddr_t 11300Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id) 11310Sstevel@tonic-gate { 11320Sstevel@tonic-gate caddr_t cvaddr; 11330Sstevel@tonic-gate uint64_t cvc_iobuf_physaddr; 11340Sstevel@tonic-gate pfn_t pfn; 11350Sstevel@tonic-gate uint_t num_pages; 11360Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate ASSERT(cpu_sgnblkp[cpu_id] != NULL); 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate /* 11410Sstevel@tonic-gate * First construct the physical base address of the bbsram 11420Sstevel@tonic-gate * in Starfire PSI space associated with this cpu in question. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE; 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate /* 11470Sstevel@tonic-gate * Next add the cvc i/o buffer offset obtained from the 11480Sstevel@tonic-gate * sigblock to get cvc iobuf physical address 11490Sstevel@tonic-gate */ 11500Sstevel@tonic-gate cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off; 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /* Get the page frame number */ 11530Sstevel@tonic-gate pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT); 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate /* Calculate how many pages we need to map in */ 11560Sstevel@tonic-gate num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr 11570Sstevel@tonic-gate & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t))); 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate /* 11600Sstevel@tonic-gate * Map in the cvc iobuf 11610Sstevel@tonic-gate */ 11620Sstevel@tonic-gate cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn, 11650Sstevel@tonic-gate PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr 11680Sstevel@tonic-gate & MMU_PAGEOFFSET))); 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate /* 11730Sstevel@tonic-gate * cvc_iobuf_mapout() 11740Sstevel@tonic-gate * Map out the cvc iobuf from kernel space 11750Sstevel@tonic-gate */ 11760Sstevel@tonic-gate static void 11770Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id) 11780Sstevel@tonic-gate { 11790Sstevel@tonic-gate caddr_t cvaddr; 11800Sstevel@tonic-gate size_t num_pages; 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate if ((cvaddr = cvc_iobufp[cpu_id]) == 0) { 11830Sstevel@tonic-gate /* already unmapped - return */ 11840Sstevel@tonic-gate return; 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /* Calculate how many pages we need to map out */ 11880Sstevel@tonic-gate num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) + 11890Sstevel@tonic-gate sizeof (sigb_cvc_t))); 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate /* Get cvaddr to the start of the page boundary */ 11920Sstevel@tonic-gate cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK)); 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK); 11950Sstevel@tonic-gate vmem_free(heap_arena, cvaddr, ptob(num_pages)); 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate cvc_iobufp[cpu_id] = NULL; 11980Sstevel@tonic-gate } 1199