17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 519397407SSherry Moore * Common Development and Distribution License (the "License"). 619397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*07d06da5SSurya Prakki 227c478bd9Sstevel@tonic-gate /* 23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * MT STREAMS Virtual Console Device Driver 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/processor.h> 357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 367c478bd9Sstevel@tonic-gate #include <sys/open.h> 377c478bd9Sstevel@tonic-gate #include <sys/param.h> 387c478bd9Sstevel@tonic-gate #include <sys/systm.h> 397c478bd9Sstevel@tonic-gate #include <sys/signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/cred.h> 417c478bd9Sstevel@tonic-gate #include <sys/user.h> 427c478bd9Sstevel@tonic-gate #include <sys/proc.h> 437c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 447c478bd9Sstevel@tonic-gate #include <sys/uio.h> 457c478bd9Sstevel@tonic-gate #include <sys/buf.h> 467c478bd9Sstevel@tonic-gate #include <sys/file.h> 477c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 487c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 497c478bd9Sstevel@tonic-gate #include <sys/stat.h> 507c478bd9Sstevel@tonic-gate #include <sys/stream.h> 517c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 527c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 537c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 547c478bd9Sstevel@tonic-gate #include <sys/tty.h> 557c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h> 567c478bd9Sstevel@tonic-gate #include <sys/poll.h> 577c478bd9Sstevel@tonic-gate #include <sys/debug.h> 587c478bd9Sstevel@tonic-gate #include <sys/conf.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #include <sys/starfire.h> 617c478bd9Sstevel@tonic-gate #include <sys/mman.h> 627c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 657c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 667c478bd9Sstevel@tonic-gate #include <sys/errno.h> 677c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 687c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 697c478bd9Sstevel@tonic-gate #include <sys/cvc.h> 707c478bd9Sstevel@tonic-gate #include <sys/cpu_sgn.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate extern void prom_printf(char *fmt, ...); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 757c478bd9Sstevel@tonic-gate static int cvc_attach(dev_info_t *, ddi_attach_cmd_t); 767c478bd9Sstevel@tonic-gate static int cvc_detach(dev_info_t *, ddi_detach_cmd_t); 777c478bd9Sstevel@tonic-gate static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *); 787c478bd9Sstevel@tonic-gate static int cvc_close(queue_t *, int, cred_t *); 797c478bd9Sstevel@tonic-gate static int cvc_wput(queue_t *, mblk_t *); 807c478bd9Sstevel@tonic-gate static int cvc_wsrv(queue_t *); 817c478bd9Sstevel@tonic-gate static void cvc_ioctl(queue_t *, mblk_t *); 827c478bd9Sstevel@tonic-gate static void cvc_ack(mblk_t *, mblk_t *, uint_t); 837c478bd9Sstevel@tonic-gate static void cvc_reioctl(void *); 847c478bd9Sstevel@tonic-gate static void cvc_input_daemon(void); 857c478bd9Sstevel@tonic-gate static void cvc_putc(register int); 867c478bd9Sstevel@tonic-gate static void cvc_flush_buf(void *); 877c478bd9Sstevel@tonic-gate static void cvc_bbsram_ops(volatile uchar_t *); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static caddr_t cvc_iobuf_mapin(processorid_t); 907c478bd9Sstevel@tonic-gate static void cvc_iobuf_mapout(processorid_t); 917c478bd9Sstevel@tonic-gate void cvc_assign_iocpu(processorid_t); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * Private copy of devinfo pointer; cvc_info uses it. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static dev_info_t *cvcdip; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * This buffer is used to manage mapping in the I/O buffer that CVC 1007c478bd9Sstevel@tonic-gate * uses when communicating with the SSP Client (netcon_server) via bbsram. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate static caddr_t cvc_iobufp[NCPU]; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate typedef struct cvc_s { 1057c478bd9Sstevel@tonic-gate bufcall_id_t cvc_wbufcid; 1067c478bd9Sstevel@tonic-gate tty_common_t cvc_tty; 1077c478bd9Sstevel@tonic-gate } cvc_t; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate cvc_t cvc_common_tty; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static struct module_info cvcm_info = { 1127c478bd9Sstevel@tonic-gate 1313, /* mi_idnum Bad luck number ;-) */ 1137c478bd9Sstevel@tonic-gate "cvc", /* mi_idname */ 1147c478bd9Sstevel@tonic-gate 0, /* mi_minpsz */ 1157c478bd9Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */ 1167c478bd9Sstevel@tonic-gate 2048, /* mi_hiwat */ 1177c478bd9Sstevel@tonic-gate 2048 /* mi_lowat */ 1187c478bd9Sstevel@tonic-gate }; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static struct qinit cvcrinit = { 1217c478bd9Sstevel@tonic-gate NULL, /* qi_putp */ 1227c478bd9Sstevel@tonic-gate NULL, /* qi_srvp */ 1237c478bd9Sstevel@tonic-gate cvc_open, /* qi_qopen */ 1247c478bd9Sstevel@tonic-gate cvc_close, /* qi_qclose */ 1257c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1267c478bd9Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 1277c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1287c478bd9Sstevel@tonic-gate }; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate static struct qinit cvcwinit = { 1317c478bd9Sstevel@tonic-gate cvc_wput, /* qi_putp */ 1327c478bd9Sstevel@tonic-gate cvc_wsrv, /* qi_srvp */ 1337c478bd9Sstevel@tonic-gate cvc_open, /* qi_qopen */ 1347c478bd9Sstevel@tonic-gate cvc_close, /* qi_qclose */ 1357c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 1367c478bd9Sstevel@tonic-gate &cvcm_info, /* qi_minfo */ 1377c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 1387c478bd9Sstevel@tonic-gate }; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate struct streamtab cvcinfo = { 1417c478bd9Sstevel@tonic-gate &cvcrinit, /* st_rdinit */ 1427c478bd9Sstevel@tonic-gate &cvcwinit, /* st_wrinit */ 1437c478bd9Sstevel@tonic-gate NULL, /* st_muxrinit */ 1447c478bd9Sstevel@tonic-gate NULL /* st_muxwrinit */ 1457c478bd9Sstevel@tonic-gate }; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate #define TIMEOUT_DELAY 100000 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate #define BBSRAM_INPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 1507c478bd9Sstevel@tonic-gate + BBSRAM_INPUT_COUNT_OFF)) 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate #define BBSRAM_OUTPUT_BUF ((volatile char *)(cvc_iobufp[cvc_iocpu] \ 1537c478bd9Sstevel@tonic-gate + BBSRAM_OUTPUT_COUNT_OFF)) 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate #define BBSRAM_INPUT_COUNT (*((volatile short *)BBSRAM_INPUT_BUF)) 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate #define BBSRAM_OUTPUT_COUNT (*((volatile short *)BBSRAM_OUTPUT_BUF)) 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate #define CVC_OUT_MAXSPIN 1024 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* The bbsram control reg is located at the end of the I/O buffers */ 1627c478bd9Sstevel@tonic-gate #define BBSRAM_CONTROL_REG ((volatile uchar_t *)(cvc_iobufp[cvc_iocpu] \ 1637c478bd9Sstevel@tonic-gate + CVC_IN_SIZE + CVC_OUT_SIZE)) 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static krwlock_t cvclock; /* lock protecting everything here */ 1667c478bd9Sstevel@tonic-gate static queue_t *cvcinput_q; /* queue for console input */ 1677c478bd9Sstevel@tonic-gate static queue_t *cvcoutput_q; /* queue for console output */ 1687c478bd9Sstevel@tonic-gate static int cvc_instance = -1; 1697c478bd9Sstevel@tonic-gate static int cvc_stopped = 0; 1707c478bd9Sstevel@tonic-gate static int cvc_suspended = 0; 1717c478bd9Sstevel@tonic-gate static int cvc_hangup_ok = 0; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static kthread_id_t cvc_input_daemon_thread; 1747c478bd9Sstevel@tonic-gate static kmutex_t cvcmutex; /* protects input */ 1757c478bd9Sstevel@tonic-gate static kmutex_t cvc_buf_mutex; /* protects internal output buffer */ 1767c478bd9Sstevel@tonic-gate static kmutex_t cvc_bbsram_input_mutex; /* protects BBSRAM inp buff */ 1777c478bd9Sstevel@tonic-gate static int input_ok = 0; /* true when stream is valid */ 1787c478bd9Sstevel@tonic-gate static int stop_bbsram = 1; /* true when BBSRAM is not usable */ 1797c478bd9Sstevel@tonic-gate static int stop_timeout = 0; 1807c478bd9Sstevel@tonic-gate static uchar_t cvc_output_buffer[MAX_XFER_OUTPUT]; /* output buffer */ 1817c478bd9Sstevel@tonic-gate static ushort_t cvc_output_count = 0; 1827c478bd9Sstevel@tonic-gate static int via_bbsram = 0; /* toggle switch */ 1837c478bd9Sstevel@tonic-gate static timeout_id_t cvc_timeout_id = (timeout_id_t)-1; 1847c478bd9Sstevel@tonic-gate static processorid_t cvc_iocpu = -1; /* cpu id of cpu zero */ 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach, 19119397407SSherry Moore nodev, cvc_info, (D_MTPERQ | D_MP), &cvcinfo, 19219397407SSherry Moore ddi_quiesce_not_supported); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1957c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 19619397407SSherry Moore "CVC driver 'cvc'", 1977c478bd9Sstevel@tonic-gate &cvcops, /* driver ops */ 1987c478bd9Sstevel@tonic-gate }; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2017c478bd9Sstevel@tonic-gate MODREV_1, 2027c478bd9Sstevel@tonic-gate &modldrv, 2037c478bd9Sstevel@tonic-gate NULL 2047c478bd9Sstevel@tonic-gate }; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate int 2077c478bd9Sstevel@tonic-gate _init(void) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate int status; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate status = mod_install(&modlinkage); 2127c478bd9Sstevel@tonic-gate if (status == 0) { 2137c478bd9Sstevel@tonic-gate mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate return (status); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate int 2197c478bd9Sstevel@tonic-gate _fini(void) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate return (EBUSY); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate int 2257c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * DDI glue routines. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2357c478bd9Sstevel@tonic-gate static int 2367c478bd9Sstevel@tonic-gate cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2377c478bd9Sstevel@tonic-gate { 2387c478bd9Sstevel@tonic-gate static char been_here = 0; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (cmd == DDI_RESUME) { 2417c478bd9Sstevel@tonic-gate cvc_suspended = 0; 2427c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate mutex_enter(&cvcmutex); 2467c478bd9Sstevel@tonic-gate if (!been_here) { 2477c478bd9Sstevel@tonic-gate been_here = 1; 2487c478bd9Sstevel@tonic-gate mutex_init(&cvc_buf_mutex, NULL, MUTEX_DEFAULT, NULL); 2497c478bd9Sstevel@tonic-gate mutex_init(&cvc_bbsram_input_mutex, NULL, MUTEX_DEFAULT, NULL); 2507c478bd9Sstevel@tonic-gate rw_init(&cvclock, NULL, RW_DRIVER, NULL); 2517c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 2527c478bd9Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 2537c478bd9Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 2547c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 2557c478bd9Sstevel@tonic-gate cvc_instance = ddi_get_instance(devi); 2567c478bd9Sstevel@tonic-gate } else { 2577c478bd9Sstevel@tonic-gate #if defined(DEBUG) 2587c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 2597c478bd9Sstevel@tonic-gate "cvc_attach: called multiple times!! (instance = %d)", 2607c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 2617c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2627c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate mutex_exit(&cvcmutex); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "cvc", S_IFCHR, 2677c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 2687c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2697c478bd9Sstevel@tonic-gate return (-1); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate cvcdip = devi; 2727c478bd9Sstevel@tonic-gate cvcinput_q = NULL; 2737c478bd9Sstevel@tonic-gate cvcoutput_q = NULL; 2747c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate static int 2787c478bd9Sstevel@tonic-gate cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate if (cmd == DDI_SUSPEND) { 2817c478bd9Sstevel@tonic-gate cvc_suspended = 1; 2827c478bd9Sstevel@tonic-gate } else { 2837c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) { 2847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate /* 2877c478bd9Sstevel@tonic-gate * XXX this doesn't even begin to address the detach 2887c478bd9Sstevel@tonic-gate * issues - it doesn't terminate the outstanding thread, 2897c478bd9Sstevel@tonic-gate * it doesn't clean up mutexes, kill the timeout routine 2907c478bd9Sstevel@tonic-gate * etc. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate if (cvc_instance == ddi_get_instance(dip)) { 2937c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3007c478bd9Sstevel@tonic-gate static int 3017c478bd9Sstevel@tonic-gate cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate register int error; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate switch (infocmd) { 3067c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 3077c478bd9Sstevel@tonic-gate if (cvcdip == NULL) { 3087c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 3097c478bd9Sstevel@tonic-gate } else { 3107c478bd9Sstevel@tonic-gate *result = (void *)cvcdip; 3117c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate break; 3147c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 3157c478bd9Sstevel@tonic-gate *result = (void *)0; 3167c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 3177c478bd9Sstevel@tonic-gate break; 3187c478bd9Sstevel@tonic-gate default: 3197c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate return (error); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3257c478bd9Sstevel@tonic-gate static int 3267c478bd9Sstevel@tonic-gate cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate register int unit = getminor(*devp); 3297c478bd9Sstevel@tonic-gate register int err = 0; 3307c478bd9Sstevel@tonic-gate tty_common_t *tty; 3317c478bd9Sstevel@tonic-gate cvc_t *cp; 3327c478bd9Sstevel@tonic-gate static int input_daemon_started; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (unit != 0) 3357c478bd9Sstevel@tonic-gate return (ENXIO); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (q->q_ptr) 3387c478bd9Sstevel@tonic-gate return (0); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate cp = (cvc_t *)&cvc_common_tty; 3417c478bd9Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 3427c478bd9Sstevel@tonic-gate cp->cvc_wbufcid = 0; 3437c478bd9Sstevel@tonic-gate tty = &cp->cvc_tty; 3447c478bd9Sstevel@tonic-gate tty->t_readq = q; 3457c478bd9Sstevel@tonic-gate tty->t_writeq = WR(q); 3467c478bd9Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)cp; 3477c478bd9Sstevel@tonic-gate cvcinput_q = RD(q); /* save for cvc_redir */ 3487c478bd9Sstevel@tonic-gate qprocson(q); 3497c478bd9Sstevel@tonic-gate mutex_enter(&cvcmutex); 3507c478bd9Sstevel@tonic-gate input_ok = 1; 3517c478bd9Sstevel@tonic-gate if (!input_daemon_started) { 3527c478bd9Sstevel@tonic-gate extern struct cpu *SIGBCPU; /* bugid4141050 */ 3537c478bd9Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate input_daemon_started = 1; 3567c478bd9Sstevel@tonic-gate mutex_exit(&cvcmutex); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate ASSERT(cpu_sgnblkp[SIGBCPU->cpu_id] != NULL); 3597c478bd9Sstevel@tonic-gate cvc_assign_iocpu(SIGBCPU->cpu_id); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate cvc_input_daemon_thread = thread_create(NULL, 0, 3627c478bd9Sstevel@tonic-gate cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); 3637c478bd9Sstevel@tonic-gate } else { 3647c478bd9Sstevel@tonic-gate mutex_exit(&cvcmutex); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate #ifdef lint 3677c478bd9Sstevel@tonic-gate cvc_input_daemon_thread = cvc_input_daemon_thread; 3687c478bd9Sstevel@tonic-gate #endif 3697c478bd9Sstevel@tonic-gate return (err); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3737c478bd9Sstevel@tonic-gate static int 3747c478bd9Sstevel@tonic-gate cvc_close(queue_t *q, int flag, cred_t *crp) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate register int err = 0; 3777c478bd9Sstevel@tonic-gate register cvc_t *cp; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate mutex_enter(&cvcmutex); 3807c478bd9Sstevel@tonic-gate input_ok = 0; 3817c478bd9Sstevel@tonic-gate mutex_exit(&cvcmutex); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate cp = q->q_ptr; 3847c478bd9Sstevel@tonic-gate if (cp->cvc_wbufcid != 0) { 3857c478bd9Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate ttycommon_close(&cp->cvc_tty); 3887c478bd9Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = NULL; 3897c478bd9Sstevel@tonic-gate cvcinput_q = NULL; 3907c478bd9Sstevel@tonic-gate bzero((caddr_t)cp, sizeof (cvc_t)); 3917c478bd9Sstevel@tonic-gate qprocsoff(q); 3927c478bd9Sstevel@tonic-gate return (err); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * cvc_wput() 3987c478bd9Sstevel@tonic-gate * cn driver does a strwrite of console output data to rconsvp which 3997c478bd9Sstevel@tonic-gate * has been set by consconfig. The data enters the cvc stream at the 4007c478bd9Sstevel@tonic-gate * streamhead and flows thru ttycompat and ldterm which have been 4017c478bd9Sstevel@tonic-gate * pushed on the stream. Console output data gets sent out either 4027c478bd9Sstevel@tonic-gate * by cvcredir (if there is a cvcd running) or bbsram (if there 4037c478bd9Sstevel@tonic-gate * isn't). 4047c478bd9Sstevel@tonic-gate * Data is sent to the cvcredir via it's read q which is cvcoutput_q 4057c478bd9Sstevel@tonic-gate * and was set in cvc_register(). 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate static int 4087c478bd9Sstevel@tonic-gate cvc_wput(register queue_t *q, register mblk_t *mp) 4097c478bd9Sstevel@tonic-gate { 4107c478bd9Sstevel@tonic-gate int error = 0; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 4137c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate case M_IOCTL: 4167c478bd9Sstevel@tonic-gate case M_CTL: 4177c478bd9Sstevel@tonic-gate cvc_ioctl(q, mp); 4187c478bd9Sstevel@tonic-gate break; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate case M_FLUSH: 4217c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Flush our write queue. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 4267c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4297c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 4307c478bd9Sstevel@tonic-gate qreply(q, mp); 4317c478bd9Sstevel@tonic-gate } else 4327c478bd9Sstevel@tonic-gate freemsg(mp); 4337c478bd9Sstevel@tonic-gate break; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate case M_STOP: 4367c478bd9Sstevel@tonic-gate cvc_stopped = 1; 4377c478bd9Sstevel@tonic-gate freemsg(mp); 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate case M_START: 4417c478bd9Sstevel@tonic-gate cvc_stopped = 0; 4427c478bd9Sstevel@tonic-gate freemsg(mp); 4437c478bd9Sstevel@tonic-gate qenable(q); /* Start up delayed messages */ 4447c478bd9Sstevel@tonic-gate break; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate case M_READ: 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * ldterm handles this (VMIN/VTIME processing). 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate freemsg(mp); 4517c478bd9Sstevel@tonic-gate break; 4527c478bd9Sstevel@tonic-gate default: 453*07d06da5SSurya Prakki cmn_err(CE_WARN, "cvc_wput: illegal mblk = 0x%p", 454*07d06da5SSurya Prakki (void *)mp); 4557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_wput: type = 0x%x", 4567c478bd9Sstevel@tonic-gate mp->b_datap->db_type); 4577c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 4587c478bd9Sstevel@tonic-gate #ifdef lint 4597c478bd9Sstevel@tonic-gate break; 4607c478bd9Sstevel@tonic-gate #endif 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate case M_DATA: 4637c478bd9Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 4647c478bd9Sstevel@tonic-gate (void) putq(q, mp); 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Send it up past cvcredir module. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate putnext(cvcoutput_q, mp); 4727c478bd9Sstevel@tonic-gate } else { 4737c478bd9Sstevel@tonic-gate char *msgp, c; 4747c478bd9Sstevel@tonic-gate mblk_t *mp2 = mp; 4757c478bd9Sstevel@tonic-gate int count; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate while (mp2 != NULL) { 4787c478bd9Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 4797c478bd9Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 4807c478bd9Sstevel@tonic-gate while (count > 0) { 4817c478bd9Sstevel@tonic-gate count--; 4827c478bd9Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 4837c478bd9Sstevel@tonic-gate /* don't print NULs */ 4847c478bd9Sstevel@tonic-gate cvc_putc(c); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate mp2 = mp2->b_cont; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate freemsg(mp); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 4957c478bd9Sstevel@tonic-gate return (error); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate static int cvc_wsrv_count = 0; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate static int 5017c478bd9Sstevel@tonic-gate cvc_wsrv(queue_t *q) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate register mblk_t *mp; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate cvc_wsrv_count++; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (cvc_stopped == 1 || cvc_suspended == 1) { 5087c478bd9Sstevel@tonic-gate return (0); 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 5127c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 5137c478bd9Sstevel@tonic-gate if (cvcoutput_q != NULL && !via_bbsram) { 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Send it up past cvcredir module. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate putnext(cvcoutput_q, mp); 5187c478bd9Sstevel@tonic-gate } else { 5197c478bd9Sstevel@tonic-gate char *msgp, c; 5207c478bd9Sstevel@tonic-gate mblk_t *mp2 = mp; 5217c478bd9Sstevel@tonic-gate int count; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate while (mp2 != NULL) { 5247c478bd9Sstevel@tonic-gate count = mp2->b_wptr - mp2->b_rptr; 5257c478bd9Sstevel@tonic-gate msgp = (char *)mp2->b_rptr; 5267c478bd9Sstevel@tonic-gate while (count > 0) { 5277c478bd9Sstevel@tonic-gate count--; 5287c478bd9Sstevel@tonic-gate if ((c = *msgp++) != '\0') { 5297c478bd9Sstevel@tonic-gate /* don't print NULs */ 5307c478bd9Sstevel@tonic-gate cvc_putc(c); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate mp2 = mp2->b_cont; 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate freemsg(mp); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 5397c478bd9Sstevel@tonic-gate return (0); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * cvc_ioctl() 5457c478bd9Sstevel@tonic-gate * handle normal console ioctls. 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate static void 5487c478bd9Sstevel@tonic-gate cvc_ioctl(register queue_t *q, register mblk_t *mp) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate register struct iocblk *iocp; 5517c478bd9Sstevel@tonic-gate register tty_common_t *tty; 5527c478bd9Sstevel@tonic-gate register cvc_t *cp; 5537c478bd9Sstevel@tonic-gate int datasize; 5547c478bd9Sstevel@tonic-gate int error = 0; 5557c478bd9Sstevel@tonic-gate mblk_t *tmp; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate cp = q->q_ptr; 5587c478bd9Sstevel@tonic-gate tty = &cp->cvc_tty; 5597c478bd9Sstevel@tonic-gate if (tty->t_iocpending != NULL) { 5607c478bd9Sstevel@tonic-gate freemsg(tty->t_iocpending); 5617c478bd9Sstevel@tonic-gate tty->t_iocpending = NULL; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate datasize = ttycommon_ioctl(tty, q, mp, &error); 5647c478bd9Sstevel@tonic-gate if (datasize != 0) { 5657c478bd9Sstevel@tonic-gate if (cp->cvc_wbufcid) 5667c478bd9Sstevel@tonic-gate unbufcall(cp->cvc_wbufcid); 5677c478bd9Sstevel@tonic-gate cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp); 5687c478bd9Sstevel@tonic-gate return; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate if (error < 0) { 5717c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate error = 0; 5767c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * Set modem bit ioctls. These are NOPs for us, since we 5807c478bd9Sstevel@tonic-gate * dont control any hardware. 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate case TCSBRK: 5837c478bd9Sstevel@tonic-gate case TIOCSBRK: 5847c478bd9Sstevel@tonic-gate case TIOCCBRK: 5857c478bd9Sstevel@tonic-gate case TIOCMSET: 5867c478bd9Sstevel@tonic-gate case TIOCMBIS: 5877c478bd9Sstevel@tonic-gate case TIOCMBIC: 5887c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 5897c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 5907c478bd9Sstevel@tonic-gate } else { 5917c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate /* qreply done below */ 5947c478bd9Sstevel@tonic-gate break; 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Get modem bits, we return 0 in mblk. 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate case TIOCMGET: 6007c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 6017c478bd9Sstevel@tonic-gate if (tmp == NULL) { 6027c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EAGAIN); 6037c478bd9Sstevel@tonic-gate return; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate *(int *)tmp->b_rptr = 0; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 6087c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 6097c478bd9Sstevel@tonic-gate else 6107c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 6117c478bd9Sstevel@tonic-gate /* qreply done below */ 6127c478bd9Sstevel@tonic-gate break; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate default: 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 6177c478bd9Sstevel@tonic-gate */ 6187c478bd9Sstevel@tonic-gate error = EINVAL; 6197c478bd9Sstevel@tonic-gate break; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate if (error != 0) { 6237c478bd9Sstevel@tonic-gate iocp->ioc_error = error; 6247c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate qreply(q, mp); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * cvc_redir() 6337c478bd9Sstevel@tonic-gate * called from cvcredir:cvcr_wput() to handle console input 6347c478bd9Sstevel@tonic-gate * data. This routine puts the cvcredir write (downstream) data 6357c478bd9Sstevel@tonic-gate * onto the cvc read (upstream) queues. Note that if `mp' is 6367c478bd9Sstevel@tonic-gate * an M_IOCTL, then it may be reused by the caller to send back 6377c478bd9Sstevel@tonic-gate * an M_IOCACK or M_IOCNAK. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate int 6407c478bd9Sstevel@tonic-gate cvc_redir(mblk_t *mp) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate register struct iocblk *iocp; 6437c478bd9Sstevel@tonic-gate register tty_common_t *tty; 6447c478bd9Sstevel@tonic-gate register cvc_t *cp; 6457c478bd9Sstevel@tonic-gate struct winsize *ws; 6467c478bd9Sstevel@tonic-gate int error; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (cvcinput_q == NULL) { 6497c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); 6507c478bd9Sstevel@tonic-gate return (EINVAL); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_IOCTL) { 6547c478bd9Sstevel@tonic-gate putnext(cvcinput_q, mp); 6557c478bd9Sstevel@tonic-gate return (0); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 6597c478bd9Sstevel@tonic-gate if (iocp->ioc_cmd == TIOCSWINSZ) { 6607c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct winsize)); 6617c478bd9Sstevel@tonic-gate if (error != 0) 6627c478bd9Sstevel@tonic-gate return (error); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 6657c478bd9Sstevel@tonic-gate cp = cvcinput_q->q_ptr; 6667c478bd9Sstevel@tonic-gate tty = &cp->cvc_tty; 6677c478bd9Sstevel@tonic-gate mutex_enter(&tty->t_excl); 6687c478bd9Sstevel@tonic-gate if (bcmp(&tty->t_size, ws, sizeof (struct winsize)) != 0) { 6697c478bd9Sstevel@tonic-gate tty->t_size = *ws; 6707c478bd9Sstevel@tonic-gate mutex_exit(&tty->t_excl); 6717c478bd9Sstevel@tonic-gate (void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH); 6727c478bd9Sstevel@tonic-gate } else 6737c478bd9Sstevel@tonic-gate mutex_exit(&tty->t_excl); 6747c478bd9Sstevel@tonic-gate } else { 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * It must be a CVC_DISCONNECT, send hangup. 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate ASSERT(iocp->ioc_cmd == CVC_DISCONNECT); 6797c478bd9Sstevel@tonic-gate if (cvc_hangup_ok) 6807c478bd9Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate return (0); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * cvc_register() 6897c478bd9Sstevel@tonic-gate * called from cvcredir to register it's queues. cvc 6907c478bd9Sstevel@tonic-gate * receives data from cn via the streamhead and sends it to cvcredir 6917c478bd9Sstevel@tonic-gate * via pointers to cvcredir's queues. 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate int 6947c478bd9Sstevel@tonic-gate cvc_register(queue_t *q) 6957c478bd9Sstevel@tonic-gate { 6967c478bd9Sstevel@tonic-gate int error = -1; 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate if (cvcinput_q == NULL) 6997c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: register w/ no console open!"); 7007c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 7017c478bd9Sstevel@tonic-gate if (cvcoutput_q == NULL) { 7027c478bd9Sstevel@tonic-gate cvcoutput_q = RD(q); /* Make sure its the upstream q */ 7037c478bd9Sstevel@tonic-gate qprocson(cvcoutput_q); /* must be done within cvclock */ 7047c478bd9Sstevel@tonic-gate error = 0; 7057c478bd9Sstevel@tonic-gate } else { 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * cmn_err will call us, so release lock. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 7107c478bd9Sstevel@tonic-gate if (cvcoutput_q == q) 7117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cvc_register: duplicate q!"); 7127c478bd9Sstevel@tonic-gate else 71304580fdfSmathue cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p", 714*07d06da5SSurya Prakki (void *)q); 7157c478bd9Sstevel@tonic-gate return (error); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * Unless "via_bbsram" is set, i/o will be going through cvcd, so 7207c478bd9Sstevel@tonic-gate * stop flushing output to BBSRAM. 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate if ((cvc_timeout_id != (timeout_id_t)-1) && (!via_bbsram)) { 7237c478bd9Sstevel@tonic-gate stop_timeout = 1; 7247c478bd9Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 7257c478bd9Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 7267c478bd9Sstevel@tonic-gate cvc_hangup_ok = 1; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 7297c478bd9Sstevel@tonic-gate return (error); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * cvc_unregister() 7357c478bd9Sstevel@tonic-gate * called from cvcredir to clear pointers to its queues. 7367c478bd9Sstevel@tonic-gate * cvcredir no longer wants to send or receive data. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate void 7397c478bd9Sstevel@tonic-gate cvc_unregister(queue_t *q) 7407c478bd9Sstevel@tonic-gate { 7417c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 7427c478bd9Sstevel@tonic-gate if (q == cvcoutput_q) { 7437c478bd9Sstevel@tonic-gate qprocsoff(cvcoutput_q); /* must be done within cvclock */ 7447c478bd9Sstevel@tonic-gate cvcoutput_q = NULL; 7457c478bd9Sstevel@tonic-gate } else { 7467c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 747*07d06da5SSurya Prakki cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered", 748*07d06da5SSurya Prakki (void *)q); 7497c478bd9Sstevel@tonic-gate return; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * i/o will not be going through cvcd, start flushing output to 7547c478bd9Sstevel@tonic-gate * BBSRAM 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 7577c478bd9Sstevel@tonic-gate stop_timeout = 0; 7587c478bd9Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 7597c478bd9Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate * cvc_reioctl() 7667c478bd9Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able 7677c478bd9Sstevel@tonic-gate * to allocate the buffer we need. 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate static void 7707c478bd9Sstevel@tonic-gate cvc_reioctl(void *unit) 7717c478bd9Sstevel@tonic-gate { 7727c478bd9Sstevel@tonic-gate register queue_t *q; 7737c478bd9Sstevel@tonic-gate register mblk_t *mp; 7747c478bd9Sstevel@tonic-gate register cvc_t *cp = (cvc_t *)unit; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * The bufcall is no longer pending. 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate if (!cp->cvc_wbufcid) { 7807c478bd9Sstevel@tonic-gate return; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate cp->cvc_wbufcid = 0; 7837c478bd9Sstevel@tonic-gate if ((q = cp->cvc_tty.t_writeq) == NULL) { 7847c478bd9Sstevel@tonic-gate return; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate if ((mp = cp->cvc_tty.t_iocpending) != NULL) { 7877c478bd9Sstevel@tonic-gate /* not pending any more */ 7887c478bd9Sstevel@tonic-gate cp->cvc_tty.t_iocpending = NULL; 7897c478bd9Sstevel@tonic-gate cvc_ioctl(q, mp); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * cvc_bbsram_ops() 7967c478bd9Sstevel@tonic-gate * Process commands sent to cvc from netcon_server via BBSRAM 7977c478bd9Sstevel@tonic-gate */ 7987c478bd9Sstevel@tonic-gate static void 7997c478bd9Sstevel@tonic-gate cvc_bbsram_ops(volatile unsigned char *op_reg) 8007c478bd9Sstevel@tonic-gate { 8017c478bd9Sstevel@tonic-gate uchar_t op; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if ((op = *op_reg) == 0) 8047c478bd9Sstevel@tonic-gate return; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cvc_bbsram_input_mutex)); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate switch (op) { 8097c478bd9Sstevel@tonic-gate case CVC_BBSRAM_BREAK: /* A console break (L1-A) */ 8107c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 8117c478bd9Sstevel@tonic-gate break; 8127c478bd9Sstevel@tonic-gate case CVC_BBSRAM_DISCONNECT: /* Break connection, hang up */ 8137c478bd9Sstevel@tonic-gate if (cvcinput_q && cvc_hangup_ok) 8147c478bd9Sstevel@tonic-gate (void) putnextctl(cvcinput_q, M_HANGUP); 8157c478bd9Sstevel@tonic-gate break; 8167c478bd9Sstevel@tonic-gate case CVC_BBSRAM_VIA_NET: /* console via network */ 8177c478bd9Sstevel@tonic-gate via_bbsram = 0; 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * stop periodic flushing of output to BBSRAM 8207c478bd9Sstevel@tonic-gate * only if cvcredir/cvcd are present 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 8237c478bd9Sstevel@tonic-gate if (cvcoutput_q != NULL) { 8247c478bd9Sstevel@tonic-gate stop_timeout = 1; 8257c478bd9Sstevel@tonic-gate if (cvc_timeout_id != (timeout_id_t)-1) { 8267c478bd9Sstevel@tonic-gate (void) untimeout(cvc_timeout_id); 8277c478bd9Sstevel@tonic-gate cvc_timeout_id = (timeout_id_t)-1; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 8317c478bd9Sstevel@tonic-gate break; 8327c478bd9Sstevel@tonic-gate case CVC_BBSRAM_VIA_BBSRAM: /* console via bbsram */ 8337c478bd9Sstevel@tonic-gate via_bbsram = 1; 8347c478bd9Sstevel@tonic-gate /* start periodic flushing of ouput to BBSRAM */ 8357c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_WRITER); 8367c478bd9Sstevel@tonic-gate if (cvc_timeout_id == (timeout_id_t)-1) { 8377c478bd9Sstevel@tonic-gate stop_timeout = 0; 8387c478bd9Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, 8397c478bd9Sstevel@tonic-gate NULL, drv_usectohz(TIMEOUT_DELAY)); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 8427c478bd9Sstevel@tonic-gate break; 8437c478bd9Sstevel@tonic-gate case CVC_BBSRAM_CLOSE_NET: 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * Send a hangup control message upstream to cvcd 8467c478bd9Sstevel@tonic-gate * thru cvcredir. This is an attempt to close 8477c478bd9Sstevel@tonic-gate * out any existing network connection(if any). 8487c478bd9Sstevel@tonic-gate * cvcoutput_q should point to the cvcredir's read 8497c478bd9Sstevel@tonic-gate * queue. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate rw_enter(&cvclock, RW_READER); 8527c478bd9Sstevel@tonic-gate if (cvcoutput_q != NULL) { 8537c478bd9Sstevel@tonic-gate (void) putnextctl(cvcoutput_q, M_HANGUP); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate rw_exit(&cvclock); 8567c478bd9Sstevel@tonic-gate break; 8577c478bd9Sstevel@tonic-gate default: 8587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cvc: unknown BBSRAM opcode %d\n", 8597c478bd9Sstevel@tonic-gate (unsigned int)op); 8607c478bd9Sstevel@tonic-gate break; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate *op_reg = 0; 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * cvc_putc() 8687c478bd9Sstevel@tonic-gate * Put a single character out to BBSRAM if space available. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate static void 8717c478bd9Sstevel@tonic-gate cvc_putc(register int c) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate static int output_lost = 0; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate if (c == '\n') 8767c478bd9Sstevel@tonic-gate cvc_putc('\r'); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * Just exit if the buffer is already full. 8817c478bd9Sstevel@tonic-gate * It will be up to cvc_flush_buf() to flush the buffer. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate if (cvc_output_count == MAX_XFER_OUTPUT) { 8847c478bd9Sstevel@tonic-gate output_lost = 1; 8857c478bd9Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 8867c478bd9Sstevel@tonic-gate return; 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate if (output_lost) 8897c478bd9Sstevel@tonic-gate prom_printf("WARNING: overflow of cvc output buffer, " 8907c478bd9Sstevel@tonic-gate "output lost!"); 8917c478bd9Sstevel@tonic-gate output_lost = 0; 8927c478bd9Sstevel@tonic-gate cvc_output_buffer[cvc_output_count] = (unsigned char)c; 8937c478bd9Sstevel@tonic-gate cvc_output_count++; 8947c478bd9Sstevel@tonic-gate if ((cvc_output_count == MAX_XFER_OUTPUT) || (c == '\n')) { 8957c478bd9Sstevel@tonic-gate /* flush cvc's internal output buffer to BBSRAM */ 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 8997c478bd9Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 9027c478bd9Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 9037c478bd9Sstevel@tonic-gate if (stop_bbsram) { 9047c478bd9Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9057c478bd9Sstevel@tonic-gate return; 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate DELAY(1000); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 9107c478bd9Sstevel@tonic-gate (caddr_t)(BBSRAM_OUTPUT_BUF - cvc_output_count), 9117c478bd9Sstevel@tonic-gate cvc_output_count); 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 9147c478bd9Sstevel@tonic-gate cvc_output_count = 0; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* 9217c478bd9Sstevel@tonic-gate * cvc_flush_buf() 9227c478bd9Sstevel@tonic-gate * Flush cvc's internal output buffer to BBSRAM at regular intervals. 9237c478bd9Sstevel@tonic-gate * This should only be done if cvcd is not running or the user (via the cvc 9247c478bd9Sstevel@tonic-gate * application on the SSP) has requested that i/o go through BBSRAM. 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9277c478bd9Sstevel@tonic-gate static void 9287c478bd9Sstevel@tonic-gate cvc_flush_buf(void *notused) 9297c478bd9Sstevel@tonic-gate { 9307c478bd9Sstevel@tonic-gate if (stop_timeout) 9317c478bd9Sstevel@tonic-gate return; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 9347c478bd9Sstevel@tonic-gate if (cvc_output_count != 0) { 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * Wait for the BBSRAM output buffer to be emptied. 9377c478bd9Sstevel@tonic-gate * This may hang if netcon_server isn't running on the SSP. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate int maxspin = CVC_OUT_MAXSPIN; 9407c478bd9Sstevel@tonic-gate while ((BBSRAM_OUTPUT_COUNT != 0) && --maxspin) { 9417c478bd9Sstevel@tonic-gate if (stop_bbsram) 9427c478bd9Sstevel@tonic-gate goto exit; 9437c478bd9Sstevel@tonic-gate DELAY(1000); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate bcopy((caddr_t)cvc_output_buffer, 9477c478bd9Sstevel@tonic-gate (caddr_t)BBSRAM_OUTPUT_BUF - cvc_output_count, 9487c478bd9Sstevel@tonic-gate cvc_output_count); 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate BBSRAM_OUTPUT_COUNT = cvc_output_count; 9517c478bd9Sstevel@tonic-gate cvc_output_count = 0; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate exit: 9547c478bd9Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 9557c478bd9Sstevel@tonic-gate /* rw_enter(&cvclock, RW_WRITER); */ 9567c478bd9Sstevel@tonic-gate cvc_timeout_id = timeout(cvc_flush_buf, NULL, 9577c478bd9Sstevel@tonic-gate drv_usectohz(TIMEOUT_DELAY)); 9587c478bd9Sstevel@tonic-gate /* rw_exit(&cvclock); */ 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * cvc_getstr() 9647c478bd9Sstevel@tonic-gate * Poll BBSRAM for console input while available. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate static void 9677c478bd9Sstevel@tonic-gate cvc_getstr(char *cp) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate short count; 9707c478bd9Sstevel@tonic-gate volatile char *lp; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 9737c478bd9Sstevel@tonic-gate /* Poll BBSRAM for input */ 9747c478bd9Sstevel@tonic-gate do { 9757c478bd9Sstevel@tonic-gate if (stop_bbsram) { 9767c478bd9Sstevel@tonic-gate *cp = '\0'; /* set string to zero-length */ 9777c478bd9Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 9787c478bd9Sstevel@tonic-gate return; 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Use a smaller delay between checks of BBSRAM for input 9827c478bd9Sstevel@tonic-gate * when cvcd/cvcredir are not running or "via_bbsram" has 9837c478bd9Sstevel@tonic-gate * been set. 9847c478bd9Sstevel@tonic-gate * We don't go away completely when i/o is going through the 9857c478bd9Sstevel@tonic-gate * network via cvcd since a command may be sent via BBSRAM 9867c478bd9Sstevel@tonic-gate * to switch if the network is down or hung. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate if ((cvcoutput_q == NULL) || (via_bbsram)) 9897c478bd9Sstevel@tonic-gate delay(drv_usectohz(100000)); 9907c478bd9Sstevel@tonic-gate else 9917c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 9927c478bd9Sstevel@tonic-gate cvc_bbsram_ops(BBSRAM_CONTROL_REG); 9937c478bd9Sstevel@tonic-gate count = BBSRAM_INPUT_COUNT; 9947c478bd9Sstevel@tonic-gate } while (count == 0); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate lp = BBSRAM_INPUT_BUF - count; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate while (count--) { 9997c478bd9Sstevel@tonic-gate *cp++ = *lp++; 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate *cp = '\0'; 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate BBSRAM_INPUT_COUNT = 0; 10047c478bd9Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * cvc_input_daemon() 10107c478bd9Sstevel@tonic-gate * this function runs as a separate kernel thread and polls BBSRAM for 10117c478bd9Sstevel@tonic-gate * input, and possibly put it on read stream for the console. 10127c478bd9Sstevel@tonic-gate * There are two poll rates (implemented in cvc_getstr): 10137c478bd9Sstevel@tonic-gate * 100 000 uS (10 Hz) - no cvcd communications || via_bbsram 10147c478bd9Sstevel@tonic-gate * 1000 000 uS ( 1 Hz) - cvcd communications 10157c478bd9Sstevel@tonic-gate * This continues to run even if there are network console communications 10167c478bd9Sstevel@tonic-gate * in order to handle out-of-band signaling. 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate static void 10197c478bd9Sstevel@tonic-gate cvc_input_daemon(void) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate char linebuf[MAX_XFER_INPUT]; 10227c478bd9Sstevel@tonic-gate char *cp; 10237c478bd9Sstevel@tonic-gate mblk_t *mbp; 10247c478bd9Sstevel@tonic-gate int c; 10257c478bd9Sstevel@tonic-gate int dropped_read = 0; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate for (;;) { 10287c478bd9Sstevel@tonic-gate cvc_getstr(linebuf); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate mbp = allocb(strlen(linebuf), BPRI_MED); 10317c478bd9Sstevel@tonic-gate if (mbp == NULL) { /* drop it & go on if no buffer */ 10327c478bd9Sstevel@tonic-gate if (!dropped_read) { 10337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 10347c478bd9Sstevel@tonic-gate "cvc_input_daemon: " 10357c478bd9Sstevel@tonic-gate "dropping BBSRAM reads\n"); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate dropped_read++; 10387c478bd9Sstevel@tonic-gate continue; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate if (dropped_read) { 10417c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 10427c478bd9Sstevel@tonic-gate "cvc_input_daemon: dropped %d BBSRAM reads\n", 10437c478bd9Sstevel@tonic-gate dropped_read); 10447c478bd9Sstevel@tonic-gate dropped_read = 0; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate for (cp = linebuf; *cp != '\0'; cp++) { 10487c478bd9Sstevel@tonic-gate c = (int)*cp; 10497c478bd9Sstevel@tonic-gate if (c == '\r') 10507c478bd9Sstevel@tonic-gate c = '\n'; 10517c478bd9Sstevel@tonic-gate c &= 0177; 10527c478bd9Sstevel@tonic-gate *mbp->b_wptr = (char)c; 10537c478bd9Sstevel@tonic-gate mbp->b_wptr++; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate mutex_enter(&cvcmutex); 10567c478bd9Sstevel@tonic-gate if (input_ok) { 10577c478bd9Sstevel@tonic-gate if (cvcinput_q == NULL) { 10587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 10597c478bd9Sstevel@tonic-gate "cvc_input_daemon: cvcinput_q is NULL!"); 10607c478bd9Sstevel@tonic-gate } else { 10617c478bd9Sstevel@tonic-gate putnext(cvcinput_q, mbp); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate } else { 10647c478bd9Sstevel@tonic-gate freemsg(mbp); 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate mutex_exit(&cvcmutex); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /* NOTREACHED */ 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * cvc_bbsram_stop() 10757c478bd9Sstevel@tonic-gate * Prevents accesses to BBSRAM. used by cvc_assign_iocpu() when 10767c478bd9Sstevel@tonic-gate * mapping in BBSRAM to a virtual address. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate static void 10797c478bd9Sstevel@tonic-gate cvc_bbsram_stop(void) 10807c478bd9Sstevel@tonic-gate { 10817c478bd9Sstevel@tonic-gate stop_bbsram = 1; 10827c478bd9Sstevel@tonic-gate mutex_enter(&cvc_bbsram_input_mutex); 10837c478bd9Sstevel@tonic-gate mutex_enter(&cvc_buf_mutex); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * cvc_bbsram_start() 10897c478bd9Sstevel@tonic-gate * Allow accesses to BBSRAM, used by cvc_assign_iocpu() after 10907c478bd9Sstevel@tonic-gate * BBSRAM has been mapped to a virtual address. 10917c478bd9Sstevel@tonic-gate */ 10927c478bd9Sstevel@tonic-gate static void 10937c478bd9Sstevel@tonic-gate cvc_bbsram_start(void) 10947c478bd9Sstevel@tonic-gate { 10957c478bd9Sstevel@tonic-gate stop_bbsram = 0; 10967c478bd9Sstevel@tonic-gate mutex_exit(&cvc_buf_mutex); 10977c478bd9Sstevel@tonic-gate mutex_exit(&cvc_bbsram_input_mutex); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate /* 11027c478bd9Sstevel@tonic-gate * cvc_assign_iocpu() 11037c478bd9Sstevel@tonic-gate * Map in BBSRAM to a virtual address 11047c478bd9Sstevel@tonic-gate * This called by the kernel with the cpu id of cpu zero. 11057c478bd9Sstevel@tonic-gate */ 11067c478bd9Sstevel@tonic-gate void 11077c478bd9Sstevel@tonic-gate cvc_assign_iocpu(processorid_t newcpu) 11087c478bd9Sstevel@tonic-gate { 11097c478bd9Sstevel@tonic-gate processorid_t oldcpu = cvc_iocpu; 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate if (newcpu == oldcpu) 11127c478bd9Sstevel@tonic-gate return; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate cvc_iobufp[newcpu] = cvc_iobuf_mapin(newcpu); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate cvc_bbsram_stop(); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate cvc_iocpu = newcpu; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate cvc_bbsram_start(); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (oldcpu != -1) 11237c478bd9Sstevel@tonic-gate cvc_iobuf_mapout(oldcpu); 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * cvc_iobuf_mapin() 11297c478bd9Sstevel@tonic-gate * Map in the cvc bbsram i/o buffer into kernel space. 11307c478bd9Sstevel@tonic-gate */ 11317c478bd9Sstevel@tonic-gate static caddr_t 11327c478bd9Sstevel@tonic-gate cvc_iobuf_mapin(processorid_t cpu_id) 11337c478bd9Sstevel@tonic-gate { 11347c478bd9Sstevel@tonic-gate caddr_t cvaddr; 11357c478bd9Sstevel@tonic-gate uint64_t cvc_iobuf_physaddr; 11367c478bd9Sstevel@tonic-gate pfn_t pfn; 11377c478bd9Sstevel@tonic-gate uint_t num_pages; 11387c478bd9Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[]; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate ASSERT(cpu_sgnblkp[cpu_id] != NULL); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * First construct the physical base address of the bbsram 11447c478bd9Sstevel@tonic-gate * in Starfire PSI space associated with this cpu in question. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate cvc_iobuf_physaddr = STARFIRE_UPAID2UPS(cpu_id) | STARFIRE_PSI_BASE; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * Next add the cvc i/o buffer offset obtained from the 11507c478bd9Sstevel@tonic-gate * sigblock to get cvc iobuf physical address 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate cvc_iobuf_physaddr += cpu_sgnblkp[cpu_id]->sigb_cvc_off; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* Get the page frame number */ 11557c478bd9Sstevel@tonic-gate pfn = (cvc_iobuf_physaddr >> MMU_PAGESHIFT); 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* Calculate how many pages we need to map in */ 11587c478bd9Sstevel@tonic-gate num_pages = mmu_btopr(((uint_t)(cvc_iobuf_physaddr 11597c478bd9Sstevel@tonic-gate & MMU_PAGEOFFSET) + sizeof (sigb_cvc_t))); 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate /* 11627c478bd9Sstevel@tonic-gate * Map in the cvc iobuf 11637c478bd9Sstevel@tonic-gate */ 11647c478bd9Sstevel@tonic-gate cvaddr = vmem_alloc(heap_arena, ptob(num_pages), VM_SLEEP); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate hat_devload(kas.a_hat, cvaddr, mmu_ptob(num_pages), pfn, 11677c478bd9Sstevel@tonic-gate PROT_READ | PROT_WRITE, HAT_LOAD_LOCK); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate return ((caddr_t)(cvaddr + (uint_t)(cvc_iobuf_physaddr 11707c478bd9Sstevel@tonic-gate & MMU_PAGEOFFSET))); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * cvc_iobuf_mapout() 11767c478bd9Sstevel@tonic-gate * Map out the cvc iobuf from kernel space 11777c478bd9Sstevel@tonic-gate */ 11787c478bd9Sstevel@tonic-gate static void 11797c478bd9Sstevel@tonic-gate cvc_iobuf_mapout(processorid_t cpu_id) 11807c478bd9Sstevel@tonic-gate { 11817c478bd9Sstevel@tonic-gate caddr_t cvaddr; 11827c478bd9Sstevel@tonic-gate size_t num_pages; 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate if ((cvaddr = cvc_iobufp[cpu_id]) == 0) { 11857c478bd9Sstevel@tonic-gate /* already unmapped - return */ 11867c478bd9Sstevel@tonic-gate return; 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* Calculate how many pages we need to map out */ 11907c478bd9Sstevel@tonic-gate num_pages = mmu_btopr(((size_t)((uint64_t)cvaddr & MMU_PAGEOFFSET) + 11917c478bd9Sstevel@tonic-gate sizeof (sigb_cvc_t))); 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* Get cvaddr to the start of the page boundary */ 11947c478bd9Sstevel@tonic-gate cvaddr = (caddr_t)(((uint64_t)cvaddr & MMU_PAGEMASK)); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, cvaddr, mmu_ptob(num_pages), HAT_UNLOAD_UNLOCK); 11977c478bd9Sstevel@tonic-gate vmem_free(heap_arena, cvaddr, ptob(num_pages)); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate cvc_iobufp[cpu_id] = NULL; 12007c478bd9Sstevel@tonic-gate } 1201