103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * 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. 703831d35Sstevel * 803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 903831d35Sstevel * or http://www.opensolaris.org/os/licensing. 1003831d35Sstevel * See the License for the specific language governing permissions 1103831d35Sstevel * and limitations under the License. 1203831d35Sstevel * 1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1803831d35Sstevel * 1903831d35Sstevel * CDDL HEADER END 2003831d35Sstevel */ 21*07d06da5SSurya Prakki 2203831d35Sstevel /* 23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2403831d35Sstevel * Use is subject to license terms. 2503831d35Sstevel */ 2603831d35Sstevel 2703831d35Sstevel 2803831d35Sstevel /* 2903831d35Sstevel * MT STREAMS Virtual Console Device Driver 3003831d35Sstevel */ 3103831d35Sstevel 3203831d35Sstevel #include <sys/types.h> 3303831d35Sstevel #include <sys/open.h> 3403831d35Sstevel #include <sys/param.h> 3503831d35Sstevel #include <sys/systm.h> 3603831d35Sstevel #include <sys/signal.h> 3703831d35Sstevel #include <sys/cred.h> 3803831d35Sstevel #include <sys/user.h> 3903831d35Sstevel #include <sys/proc.h> 4003831d35Sstevel #include <sys/disp.h> 4103831d35Sstevel #include <sys/vnode.h> 4203831d35Sstevel #include <sys/uio.h> 4303831d35Sstevel #include <sys/buf.h> 4403831d35Sstevel #include <sys/file.h> 4503831d35Sstevel #include <sys/kmem.h> 4603831d35Sstevel #include <sys/stat.h> 4703831d35Sstevel #include <sys/stream.h> 4803831d35Sstevel #include <sys/stropts.h> 4903831d35Sstevel #include <sys/strsubr.h> 5003831d35Sstevel #include <sys/strsun.h> 5103831d35Sstevel #include <sys/tty.h> 5203831d35Sstevel #include <sys/ptyvar.h> 5303831d35Sstevel #include <sys/poll.h> 5403831d35Sstevel #include <sys/debug.h> 5503831d35Sstevel #include <sys/conf.h> 5603831d35Sstevel #include <sys/ddi.h> 5703831d35Sstevel #include <sys/sunddi.h> 5803831d35Sstevel #include <sys/errno.h> 5903831d35Sstevel #include <sys/modctl.h> 6003831d35Sstevel 6103831d35Sstevel #include <sys/sc_cvc.h> 6203831d35Sstevel #include <sys/sc_cvcio.h> 6303831d35Sstevel #include <sys/iosramio.h> 6403831d35Sstevel 6503831d35Sstevel static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 6603831d35Sstevel static int cvc_attach(dev_info_t *, ddi_attach_cmd_t); 6703831d35Sstevel static int cvc_detach(dev_info_t *, ddi_detach_cmd_t); 6803831d35Sstevel static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *); 6903831d35Sstevel static int cvc_close(queue_t *, int, cred_t *); 7003831d35Sstevel static int cvc_wput(queue_t *, mblk_t *); 7103831d35Sstevel static int cvc_wsrv(queue_t *); 7203831d35Sstevel static void cvc_ioctl(queue_t *, mblk_t *); 7303831d35Sstevel static void cvc_reioctl(void *); 7403831d35Sstevel static void cvc_input_daemon(void); 7503831d35Sstevel static void cvc_send_to_iosram(mblk_t **chainpp); 7603831d35Sstevel static void cvc_flush_queue(void *); 7703831d35Sstevel static void cvc_iosram_ops(uint8_t); 7803831d35Sstevel static void cvc_getstr(char *cp); 7903831d35Sstevel static void cvc_win_resize(int clear_flag); 8003831d35Sstevel 8103831d35Sstevel #define ESUCCESS 0 8203831d35Sstevel #ifndef TRUE 8303831d35Sstevel #define TRUE 1 8403831d35Sstevel #define FALSE 0 8503831d35Sstevel #endif 8603831d35Sstevel 8703831d35Sstevel /* 8803831d35Sstevel * Private copy of devinfo pointer; cvc_info uses it. 8903831d35Sstevel */ 9003831d35Sstevel static dev_info_t *cvcdip; 9103831d35Sstevel 9203831d35Sstevel /* 9303831d35Sstevel * This structure reflects the layout of data in CONI and CONO. If you are 9403831d35Sstevel * going to add fields that don't get written into those chunks, be sure to 9503831d35Sstevel * place them _after_ the buffer field. 9603831d35Sstevel */ 9703831d35Sstevel typedef struct cvc_buf { 9803831d35Sstevel ushort_t count; 9903831d35Sstevel uchar_t buffer[MAX_XFER_COUTPUT]; 10003831d35Sstevel } cvc_buf_t; 10103831d35Sstevel 10203831d35Sstevel typedef struct cvc_s { 10303831d35Sstevel bufcall_id_t cvc_wbufcid; 10403831d35Sstevel tty_common_t cvc_tty; 10503831d35Sstevel } cvc_t; 10603831d35Sstevel 10703831d35Sstevel cvc_t cvc_common_tty; 10803831d35Sstevel 10903831d35Sstevel static struct module_info cvcm_info = { 11003831d35Sstevel 1313, /* mi_idnum Bad luck number ;-) */ 11103831d35Sstevel "cvc", /* mi_idname */ 11203831d35Sstevel 0, /* mi_minpsz */ 11303831d35Sstevel INFPSZ, /* mi_maxpsz */ 11403831d35Sstevel 2048, /* mi_hiwat */ 11503831d35Sstevel 2048 /* mi_lowat */ 11603831d35Sstevel }; 11703831d35Sstevel 11803831d35Sstevel static struct qinit cvcrinit = { 11903831d35Sstevel NULL, /* qi_putp */ 12003831d35Sstevel NULL, /* qi_srvp */ 12103831d35Sstevel cvc_open, /* qi_qopen */ 12203831d35Sstevel cvc_close, /* qi_qclose */ 12303831d35Sstevel NULL, /* qi_qadmin */ 12403831d35Sstevel &cvcm_info, /* qi_minfo */ 12503831d35Sstevel NULL /* qi_mstat */ 12603831d35Sstevel }; 12703831d35Sstevel 12803831d35Sstevel static struct qinit cvcwinit = { 12903831d35Sstevel cvc_wput, /* qi_putp */ 13003831d35Sstevel cvc_wsrv, /* qi_srvp */ 13103831d35Sstevel cvc_open, /* qi_qopen */ 13203831d35Sstevel cvc_close, /* qi_qclose */ 13303831d35Sstevel NULL, /* qi_qadmin */ 13403831d35Sstevel &cvcm_info, /* qi_minfo */ 13503831d35Sstevel NULL /* qi_mstat */ 13603831d35Sstevel }; 13703831d35Sstevel 13803831d35Sstevel struct streamtab cvcinfo = { 13903831d35Sstevel &cvcrinit, /* st_rdinit */ 14003831d35Sstevel &cvcwinit, /* st_wrinit */ 14103831d35Sstevel NULL, /* st_muxrinit */ 14203831d35Sstevel NULL /* st_muxwrinit */ 14303831d35Sstevel }; 14403831d35Sstevel 14503831d35Sstevel static krwlock_t cvclock; /* lock protecting everything here */ 14603831d35Sstevel static queue_t *cvcinput_q; /* queue for console input */ 14703831d35Sstevel static queue_t *cvcoutput_q; /* queue for console output */ 14803831d35Sstevel static int cvc_instance = -1; 14903831d35Sstevel static int cvc_stopped = 0; 15003831d35Sstevel static int cvc_suspended = 0; 15103831d35Sstevel 15203831d35Sstevel kthread_id_t cvc_input_daemon_thread; /* just to aid debugging */ 15303831d35Sstevel static kmutex_t cvcmutex; /* protects input */ 15403831d35Sstevel static kmutex_t cvc_iosram_input_mutex; /* protects IOSRAM inp buff */ 15503831d35Sstevel static int input_ok = 0; /* true when stream is valid */ 15603831d35Sstevel 15703831d35Sstevel static int via_iosram = 0; /* toggle switch */ 15803831d35Sstevel static timeout_id_t cvc_timeout_id = (timeout_id_t)-1; 15903831d35Sstevel static int input_daemon_started = 0; 16003831d35Sstevel 16103831d35Sstevel /* debugging functions */ 16203831d35Sstevel #ifdef DEBUG 16303831d35Sstevel uint32_t cvc_dbg_flags = 0x0; 16403831d35Sstevel static void cvc_dbg(uint32_t flag, char *fmt, 16503831d35Sstevel uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5); 16603831d35Sstevel #endif 16703831d35Sstevel 16803831d35Sstevel /* 16903831d35Sstevel * Module linkage information for the kernel. 17003831d35Sstevel */ 17103831d35Sstevel 17203831d35Sstevel DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach, 17319397407SSherry Moore nodev, cvc_info, (D_NEW|D_MTPERQ|D_MP), &cvcinfo, 17419397407SSherry Moore ddi_quiesce_not_supported); 17503831d35Sstevel 17603831d35Sstevel extern int nodev(), nulldev(); 17703831d35Sstevel extern struct mod_ops mod_driverops; 17803831d35Sstevel 17903831d35Sstevel static struct modldrv modldrv = { 18003831d35Sstevel &mod_driverops, /* Type of module. This one is a pseudo driver */ 18119397407SSherry Moore "CVC driver 'cvc'", 18203831d35Sstevel &cvcops, /* driver ops */ 18303831d35Sstevel }; 18403831d35Sstevel 18503831d35Sstevel static struct modlinkage modlinkage = { 18603831d35Sstevel MODREV_1, 18703831d35Sstevel &modldrv, 18803831d35Sstevel NULL 18903831d35Sstevel }; 19003831d35Sstevel 19103831d35Sstevel int 19203831d35Sstevel _init() 19303831d35Sstevel { 19403831d35Sstevel int status; 19503831d35Sstevel 19603831d35Sstevel status = mod_install(&modlinkage); 19703831d35Sstevel if (status == 0) { 19803831d35Sstevel mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL); 19903831d35Sstevel } 20003831d35Sstevel return (status); 20103831d35Sstevel } 20203831d35Sstevel 20303831d35Sstevel int 20403831d35Sstevel _fini() 20503831d35Sstevel { 20603831d35Sstevel return (EBUSY); 20703831d35Sstevel } 20803831d35Sstevel 20903831d35Sstevel int 21003831d35Sstevel _info(struct modinfo *modinfop) 21103831d35Sstevel { 21203831d35Sstevel return (mod_info(&modlinkage, modinfop)); 21303831d35Sstevel } 21403831d35Sstevel 21503831d35Sstevel /* 21603831d35Sstevel * DDI glue routines. 21703831d35Sstevel */ 21803831d35Sstevel 21903831d35Sstevel /* ARGSUSED */ 22003831d35Sstevel static int 22103831d35Sstevel cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 22203831d35Sstevel { 22303831d35Sstevel static char been_here = 0; 22403831d35Sstevel 22503831d35Sstevel if (cmd == DDI_RESUME) { 22603831d35Sstevel cvc_suspended = 0; 22703831d35Sstevel if (cvcinput_q != NULL) { 22803831d35Sstevel qenable(WR(cvcinput_q)); 22903831d35Sstevel } 23003831d35Sstevel return (DDI_SUCCESS); 23103831d35Sstevel } 23203831d35Sstevel 23303831d35Sstevel mutex_enter(&cvcmutex); 23403831d35Sstevel if (!been_here) { 23503831d35Sstevel been_here = 1; 23603831d35Sstevel mutex_init(&cvc_iosram_input_mutex, NULL, MUTEX_DEFAULT, NULL); 23703831d35Sstevel rw_init(&cvclock, NULL, RW_DRIVER, NULL); 23803831d35Sstevel cvc_instance = ddi_get_instance(devi); 23903831d35Sstevel } else { 24003831d35Sstevel #if defined(DEBUG) 24103831d35Sstevel cmn_err(CE_NOTE, 24203831d35Sstevel "cvc_attach: called multiple times!! (instance = %d)", 24303831d35Sstevel ddi_get_instance(devi)); 24403831d35Sstevel #endif /* DEBUG */ 24503831d35Sstevel mutex_exit(&cvcmutex); 24603831d35Sstevel return (DDI_SUCCESS); 24703831d35Sstevel } 24803831d35Sstevel mutex_exit(&cvcmutex); 24903831d35Sstevel 25003831d35Sstevel if (ddi_create_minor_node(devi, "cvc", S_IFCHR, 25103831d35Sstevel 0, NULL, NULL) == DDI_FAILURE) { 25203831d35Sstevel ddi_remove_minor_node(devi, NULL); 25303831d35Sstevel return (-1); 25403831d35Sstevel } 25503831d35Sstevel cvcdip = devi; 25603831d35Sstevel cvcinput_q = NULL; 25703831d35Sstevel cvcoutput_q = NULL; 25803831d35Sstevel 25903831d35Sstevel CVC_DBG0(CVC_DBG_ATTACH, "Attached"); 26003831d35Sstevel 26103831d35Sstevel return (DDI_SUCCESS); 26203831d35Sstevel } 26303831d35Sstevel 26403831d35Sstevel static int 26503831d35Sstevel cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 26603831d35Sstevel { 26703831d35Sstevel if (cmd == DDI_SUSPEND) { 26803831d35Sstevel cvc_suspended = 1; 26903831d35Sstevel } else { 27003831d35Sstevel if (cmd != DDI_DETACH) { 27103831d35Sstevel return (DDI_FAILURE); 27203831d35Sstevel } 27303831d35Sstevel /* 27403831d35Sstevel * XXX this doesn't even begin to address the detach 27503831d35Sstevel * issues - it doesn't terminate the outstanding thread, 27603831d35Sstevel * it doesn't clean up mutexes, kill the timeout routine 27703831d35Sstevel * etc. 27803831d35Sstevel */ 27903831d35Sstevel if (cvc_instance == ddi_get_instance(dip)) { 28003831d35Sstevel ddi_remove_minor_node(dip, NULL); 28103831d35Sstevel } 28203831d35Sstevel } 28303831d35Sstevel 28403831d35Sstevel CVC_DBG0(CVC_DBG_DETACH, "Detached"); 28503831d35Sstevel 28603831d35Sstevel return (DDI_SUCCESS); 28703831d35Sstevel } 28803831d35Sstevel 28903831d35Sstevel /* ARGSUSED */ 29003831d35Sstevel static int 29103831d35Sstevel cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 29203831d35Sstevel { 29303831d35Sstevel register int error; 29403831d35Sstevel 29503831d35Sstevel switch (infocmd) { 29603831d35Sstevel case DDI_INFO_DEVT2DEVINFO: 29703831d35Sstevel if (cvcdip == NULL) { 29803831d35Sstevel error = DDI_FAILURE; 29903831d35Sstevel } else { 30003831d35Sstevel *result = (void *)cvcdip; 30103831d35Sstevel error = DDI_SUCCESS; 30203831d35Sstevel } 30303831d35Sstevel break; 30403831d35Sstevel case DDI_INFO_DEVT2INSTANCE: 30503831d35Sstevel *result = (void *)0; 30603831d35Sstevel error = DDI_SUCCESS; 30703831d35Sstevel break; 30803831d35Sstevel default: 30903831d35Sstevel error = DDI_FAILURE; 31003831d35Sstevel } 31103831d35Sstevel return (error); 31203831d35Sstevel } 31303831d35Sstevel 31403831d35Sstevel /* ARGSUSED */ 31503831d35Sstevel static int 31603831d35Sstevel cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 31703831d35Sstevel { 31803831d35Sstevel register int unit = getminor(*devp); 31903831d35Sstevel register int err = DDI_SUCCESS; 32003831d35Sstevel tty_common_t *tty; 32103831d35Sstevel cvc_t *cp; 32203831d35Sstevel 32303831d35Sstevel if (unit != 0) 32403831d35Sstevel return (ENXIO); 32503831d35Sstevel 32603831d35Sstevel if (q->q_ptr) 32703831d35Sstevel return (0); 32803831d35Sstevel 32903831d35Sstevel cp = (cvc_t *)&cvc_common_tty; 33003831d35Sstevel bzero((caddr_t)cp, sizeof (cvc_t)); 33103831d35Sstevel cp->cvc_wbufcid = 0; 33203831d35Sstevel tty = &cp->cvc_tty; 33303831d35Sstevel tty->t_readq = q; 33403831d35Sstevel tty->t_writeq = WR(q); 33503831d35Sstevel WR(q)->q_ptr = q->q_ptr = (caddr_t)cp; 33603831d35Sstevel cvcinput_q = RD(q); /* save for cvc_redir */ 33703831d35Sstevel qprocson(q); 33803831d35Sstevel mutex_enter(&cvcmutex); 33903831d35Sstevel input_ok = 1; 34003831d35Sstevel 34103831d35Sstevel /* 34203831d35Sstevel * Start the thread that handles input polling if it hasn't been started 34303831d35Sstevel * previously. 34403831d35Sstevel */ 34503831d35Sstevel if (!input_daemon_started) { 34603831d35Sstevel input_daemon_started = 1; 34703831d35Sstevel mutex_exit(&cvcmutex); 34803831d35Sstevel 34903831d35Sstevel cvc_input_daemon_thread = thread_create(NULL, 0, 35003831d35Sstevel cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); 35103831d35Sstevel CVC_DBG0(CVC_DBG_IOSRAM_RD, "Started input daemon"); 35203831d35Sstevel } else { 35303831d35Sstevel mutex_exit(&cvcmutex); 35403831d35Sstevel } 35503831d35Sstevel 35603831d35Sstevel /* 35703831d35Sstevel * Set the console window size. 35803831d35Sstevel */ 35903831d35Sstevel mutex_enter(&cvc_iosram_input_mutex); 36003831d35Sstevel cvc_win_resize(FALSE); 36103831d35Sstevel mutex_exit(&cvc_iosram_input_mutex); 36203831d35Sstevel 36303831d35Sstevel CVC_DBG0(CVC_DBG_OPEN, "Plumbed successfully"); 36403831d35Sstevel 36503831d35Sstevel return (err); 36603831d35Sstevel } 36703831d35Sstevel 36803831d35Sstevel /* ARGSUSED */ 36903831d35Sstevel static int 37003831d35Sstevel cvc_close(queue_t *q, int flag, cred_t *crp) 37103831d35Sstevel { 37203831d35Sstevel register int err = DDI_SUCCESS; 37303831d35Sstevel register cvc_t *cp; 37403831d35Sstevel 37503831d35Sstevel mutex_enter(&cvcmutex); 37603831d35Sstevel input_ok = 0; 37703831d35Sstevel mutex_exit(&cvcmutex); 37803831d35Sstevel 37903831d35Sstevel cp = q->q_ptr; 38003831d35Sstevel if (cp->cvc_wbufcid != 0) { 38103831d35Sstevel unbufcall(cp->cvc_wbufcid); 38203831d35Sstevel } 38303831d35Sstevel ttycommon_close(&cp->cvc_tty); 38403831d35Sstevel WR(q)->q_ptr = q->q_ptr = NULL; 38503831d35Sstevel cvcinput_q = NULL; 38603831d35Sstevel bzero((caddr_t)cp, sizeof (cvc_t)); 38703831d35Sstevel qprocsoff(q); 38803831d35Sstevel 38903831d35Sstevel CVC_DBG0(CVC_DBG_CLOSE, "Un-plumbed successfully"); 39003831d35Sstevel 39103831d35Sstevel return (err); 39203831d35Sstevel } 39303831d35Sstevel 39403831d35Sstevel 39503831d35Sstevel /* 39603831d35Sstevel * cvc_wput() 39703831d35Sstevel * cn driver does a strwrite of console output data to rconsvp which has 39803831d35Sstevel * been set by consconfig. The data enters the cvc stream at the streamhead 39903831d35Sstevel * and flows thru ttycompat and ldterm which have been pushed on the 40003831d35Sstevel * stream. Console output data gets sent out either to cvcredir, if the 40103831d35Sstevel * network path is available and selected, or to IOSRAM otherwise. Data is 40203831d35Sstevel * sent to cvcredir via its read queue (cvcoutput_q, which gets set in 40303831d35Sstevel * cvc_register()). If the IOSRAM path is selected, or if previous mblks 40403831d35Sstevel * are currently queued up for processing, the new mblk will be queued 40503831d35Sstevel * and handled later on by cvc_wsrv. 40603831d35Sstevel */ 40703831d35Sstevel static int 40803831d35Sstevel cvc_wput(queue_t *q, mblk_t *mp) 40903831d35Sstevel { 41003831d35Sstevel int error = 0; 41103831d35Sstevel 41203831d35Sstevel rw_enter(&cvclock, RW_READER); 41303831d35Sstevel 41403831d35Sstevel CVC_DBG2(CVC_DBG_WPUT, "mp 0x%x db_type 0x%x", 41503831d35Sstevel mp, mp->b_datap->db_type); 41603831d35Sstevel 41703831d35Sstevel switch (mp->b_datap->db_type) { 41803831d35Sstevel 41903831d35Sstevel case M_IOCTL: 42003831d35Sstevel case M_CTL: { 42103831d35Sstevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 42203831d35Sstevel 42303831d35Sstevel switch (iocp->ioc_cmd) { 42403831d35Sstevel /* 42503831d35Sstevel * These ioctls are only supposed to be 42603831d35Sstevel * processed after everything else that is 42703831d35Sstevel * already queued awaiting processing, so throw 42803831d35Sstevel * them on the queue and let cvc_wsrv handle 42903831d35Sstevel * them. 43003831d35Sstevel */ 43103831d35Sstevel case TCSETSW: 43203831d35Sstevel case TCSETSF: 43303831d35Sstevel case TCSETAW: 43403831d35Sstevel case TCSETAF: 43503831d35Sstevel case TCSBRK: 436*07d06da5SSurya Prakki (void) putq(q, mp); 43703831d35Sstevel break; 43803831d35Sstevel 43903831d35Sstevel default: 44003831d35Sstevel cvc_ioctl(q, mp); 44103831d35Sstevel } 44203831d35Sstevel break; 44303831d35Sstevel } 44403831d35Sstevel 44503831d35Sstevel case M_FLUSH: 44603831d35Sstevel if (*mp->b_rptr & FLUSHW) { 44703831d35Sstevel /* 44803831d35Sstevel * Flush our write queue. 44903831d35Sstevel */ 45003831d35Sstevel flushq(q, FLUSHDATA); 45103831d35Sstevel *mp->b_rptr &= ~FLUSHW; 45203831d35Sstevel } 45303831d35Sstevel if (*mp->b_rptr & FLUSHR) { 45403831d35Sstevel flushq(RD(q), FLUSHDATA); 45503831d35Sstevel qreply(q, mp); 45603831d35Sstevel } else 45703831d35Sstevel freemsg(mp); 45803831d35Sstevel break; 45903831d35Sstevel 46003831d35Sstevel case M_STOP: 46103831d35Sstevel cvc_stopped = 1; 46203831d35Sstevel freemsg(mp); 46303831d35Sstevel break; 46403831d35Sstevel 46503831d35Sstevel case M_START: 46603831d35Sstevel cvc_stopped = 0; 46703831d35Sstevel freemsg(mp); 46803831d35Sstevel qenable(q); /* Start up delayed messages */ 46903831d35Sstevel break; 47003831d35Sstevel 47103831d35Sstevel case M_READ: 47203831d35Sstevel /* 47303831d35Sstevel * ldterm handles this (VMIN/VTIME processing). 47403831d35Sstevel */ 47503831d35Sstevel freemsg(mp); 47603831d35Sstevel break; 47703831d35Sstevel 47803831d35Sstevel default: 47903831d35Sstevel cmn_err(CE_WARN, "cvc_wput: unexpected mblk type - mp =" 480*07d06da5SSurya Prakki " 0x%p, type = 0x%x", (void *)mp, 481*07d06da5SSurya Prakki mp->b_datap->db_type); 48203831d35Sstevel freemsg(mp); 48303831d35Sstevel break; 48403831d35Sstevel 48503831d35Sstevel case M_DATA: 48603831d35Sstevel /* 48703831d35Sstevel * If there are other mblks queued up for transmission, 48803831d35Sstevel * or we're using IOSRAM either because cvcredir hasn't 48903831d35Sstevel * registered yet or because we were configured that 49003831d35Sstevel * way, or cvc has been stopped or suspended, place this 49103831d35Sstevel * mblk on the input queue for future processing. 49203831d35Sstevel * Otherwise, hand it off to cvcredir for transmission 49303831d35Sstevel * via the network. 49403831d35Sstevel */ 49503831d35Sstevel if (q->q_first != NULL || cvcoutput_q == NULL || 49603831d35Sstevel via_iosram || cvc_stopped == 1 || 49703831d35Sstevel cvc_suspended == 1) { 49803831d35Sstevel (void) putq(q, mp); 49903831d35Sstevel } else { 50003831d35Sstevel /* 50103831d35Sstevel * XXX - should canputnext be called here? 50203831d35Sstevel * Starfire's cvc doesn't do that, and it 50303831d35Sstevel * appears to work anyway. 50403831d35Sstevel */ 50503831d35Sstevel (void) putnext(cvcoutput_q, mp); 50603831d35Sstevel } 50703831d35Sstevel break; 50803831d35Sstevel 50903831d35Sstevel } 51003831d35Sstevel rw_exit(&cvclock); 51103831d35Sstevel return (error); 51203831d35Sstevel } 51303831d35Sstevel 51403831d35Sstevel /* 51503831d35Sstevel * cvc_wsrv() 51603831d35Sstevel * cvc_wsrv handles mblks that have been queued by cvc_wput either because 51703831d35Sstevel * the IOSRAM path was selected or the queue contained preceding mblks. To 51803831d35Sstevel * optimize processing (particularly if the IOSRAM path is selected), all 51903831d35Sstevel * mblks are pulled off of the queue and chained together. Then, if there 52003831d35Sstevel * are any mblks on the chain, they are either forwarded to cvcredir or 52103831d35Sstevel * sent for IOSRAM processing as appropriate given current circumstances. 52203831d35Sstevel * IOSRAM processing may not be able to handle all of the data in the 52303831d35Sstevel * chain, in which case the remaining data is placed back on the queue and 52403831d35Sstevel * a timeout routine is registered to reschedule cvc_wsrv in the future. 52503831d35Sstevel * Automatic scheduling of the queue is disabled (noenable(q)) while 52603831d35Sstevel * cvc_wsrv is running to avoid superfluous calls. 52703831d35Sstevel */ 52803831d35Sstevel static int 52903831d35Sstevel cvc_wsrv(queue_t *q) 53003831d35Sstevel { 53103831d35Sstevel mblk_t *total_mp = NULL; 53203831d35Sstevel mblk_t *mp; 53303831d35Sstevel 53403831d35Sstevel if (cvc_stopped == 1 || cvc_suspended == 1) { 53503831d35Sstevel return (0); 53603831d35Sstevel } 53703831d35Sstevel 53803831d35Sstevel rw_enter(&cvclock, RW_READER); 53903831d35Sstevel noenable(q); 54003831d35Sstevel 54103831d35Sstevel /* 54203831d35Sstevel * If there's already a timeout registered for scheduling this routine 54303831d35Sstevel * in the future, it's a safe bet that we don't want to run right now. 54403831d35Sstevel */ 54503831d35Sstevel if (cvc_timeout_id != (timeout_id_t)-1) { 54603831d35Sstevel enableok(q); 54703831d35Sstevel rw_exit(&cvclock); 54803831d35Sstevel return (0); 54903831d35Sstevel } 55003831d35Sstevel 55103831d35Sstevel /* 55203831d35Sstevel * Start by linking all of the queued M_DATA mblks into a single chain 55303831d35Sstevel * so we can flush as much as possible to IOSRAM (if we choose that 55403831d35Sstevel * route). 55503831d35Sstevel */ 55603831d35Sstevel while ((mp = getq(q)) != NULL) { 55703831d35Sstevel /* 55803831d35Sstevel * Technically, certain IOCTLs are supposed to be processed only 55903831d35Sstevel * after all preceding data has completely "drained". In an 56003831d35Sstevel * attempt to support that, we delay processing of those IOCTLs 56103831d35Sstevel * until this point. It is still possible that an IOCTL will be 56203831d35Sstevel * processed before all preceding data is drained, for instance 56303831d35Sstevel * in the case where not all of the preceding data would fit 56403831d35Sstevel * into IOSRAM and we have to place it back on the queue. 56503831d35Sstevel * However, since none of these IOCTLs really appear to have any 56603831d35Sstevel * relevance for cvc, and we weren't supporting delayed 56703831d35Sstevel * processing at _all_ previously, this partial implementation 56803831d35Sstevel * should suffice. (Fully implementing the delayed IOCTL 56903831d35Sstevel * processing would be unjustifiably difficult given the nature 57003831d35Sstevel * of the underlying IOSRAM console protocol.) 57103831d35Sstevel */ 57203831d35Sstevel if (mp->b_datap->db_type == M_IOCTL) { 57303831d35Sstevel cvc_ioctl(q, mp); 57403831d35Sstevel continue; 57503831d35Sstevel } 57603831d35Sstevel 57703831d35Sstevel /* 57803831d35Sstevel * We know that only M_IOCTL and M_DATA blocks are placed on our 57903831d35Sstevel * queue. Since this block isn't an M_IOCTL, it must be M_DATA. 58003831d35Sstevel */ 58103831d35Sstevel if (total_mp != NULL) { 58203831d35Sstevel linkb(total_mp, mp); 58303831d35Sstevel } else { 58403831d35Sstevel total_mp = mp; 58503831d35Sstevel } 58603831d35Sstevel } 58703831d35Sstevel 58803831d35Sstevel /* 58903831d35Sstevel * Do we actually have anything to do? 59003831d35Sstevel */ 59103831d35Sstevel if (total_mp == NULL) { 59203831d35Sstevel enableok(q); 59303831d35Sstevel rw_exit(&cvclock); 59403831d35Sstevel return (0); 59503831d35Sstevel } 59603831d35Sstevel 59703831d35Sstevel /* 59803831d35Sstevel * Yes, we do, so send the data to either cvcredir or IOSRAM as 59903831d35Sstevel * appropriate. In the latter case, we might not be able to transmit 60003831d35Sstevel * everything right now, so re-queue the remainder. 60103831d35Sstevel */ 60203831d35Sstevel if (cvcoutput_q != NULL && !via_iosram) { 60303831d35Sstevel CVC_DBG0(CVC_DBG_NETWORK_WR, "Sending to cvcredir."); 60403831d35Sstevel /* 60503831d35Sstevel * XXX - should canputnext be called here? Starfire's cvc 60603831d35Sstevel * doesn't do that, and it appears to work anyway. 60703831d35Sstevel */ 60803831d35Sstevel (void) putnext(cvcoutput_q, total_mp); 60903831d35Sstevel } else { 61003831d35Sstevel CVC_DBG0(CVC_DBG_IOSRAM_WR, "Send to IOSRAM."); 61103831d35Sstevel cvc_send_to_iosram(&total_mp); 61203831d35Sstevel if (total_mp != NULL) { 61303831d35Sstevel (void) putbq(q, total_mp); 61403831d35Sstevel } 61503831d35Sstevel } 61603831d35Sstevel 61703831d35Sstevel /* 61803831d35Sstevel * If there is still data queued at this point, make sure the queue 61903831d35Sstevel * gets scheduled again after an appropriate delay (which has been 62003831d35Sstevel * somewhat arbitrarily selected as half of the SC's input polling 62103831d35Sstevel * frequency). 62203831d35Sstevel */ 62303831d35Sstevel enableok(q); 62403831d35Sstevel if (q->q_first != NULL) { 62503831d35Sstevel if (cvc_timeout_id == (timeout_id_t)-1) { 62603831d35Sstevel cvc_timeout_id = timeout(cvc_flush_queue, 62703831d35Sstevel NULL, drv_usectohz(CVC_IOSRAM_POLL_USECS / 2)); 62803831d35Sstevel } 62903831d35Sstevel } 63003831d35Sstevel rw_exit(&cvclock); 63103831d35Sstevel return (0); 63203831d35Sstevel } 63303831d35Sstevel 63403831d35Sstevel 63503831d35Sstevel /* 63603831d35Sstevel * cvc_ioctl() 63703831d35Sstevel * handle normal console ioctls. 63803831d35Sstevel */ 63903831d35Sstevel static void 64003831d35Sstevel cvc_ioctl(register queue_t *q, register mblk_t *mp) 64103831d35Sstevel { 64203831d35Sstevel register cvc_t *cp = q->q_ptr; 64303831d35Sstevel int datasize; 64403831d35Sstevel int error = 0; 64503831d35Sstevel 64603831d35Sstevel /* 64703831d35Sstevel * Let ttycommon_ioctl take the first shot at processing the ioctl. If 64803831d35Sstevel * it fails because it can't allocate memory, schedule processing of the 64903831d35Sstevel * ioctl later when a proper buffer is available. The mblk that 65003831d35Sstevel * couldn't be processed will have been stored in the tty structure by 65103831d35Sstevel * ttycommon_ioctl. 65203831d35Sstevel */ 65303831d35Sstevel datasize = ttycommon_ioctl(&cp->cvc_tty, q, mp, &error); 65403831d35Sstevel if (datasize != 0) { 65503831d35Sstevel if (cp->cvc_wbufcid) { 65603831d35Sstevel unbufcall(cp->cvc_wbufcid); 65703831d35Sstevel } 65803831d35Sstevel cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp); 65903831d35Sstevel return; 66003831d35Sstevel } 66103831d35Sstevel 66203831d35Sstevel /* 66303831d35Sstevel * ttycommon_ioctl didn't do anything, but there's nothing we really 66403831d35Sstevel * support either with the exception of TCSBRK, which is supported 66503831d35Sstevel * only to appear a bit more like a serial device for software that 66603831d35Sstevel * expects TCSBRK to work. 66703831d35Sstevel */ 66803831d35Sstevel if (error != 0) { 66903831d35Sstevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 67003831d35Sstevel 67103831d35Sstevel if (iocp->ioc_cmd == TCSBRK) { 67203831d35Sstevel miocack(q, mp, 0, 0); 67303831d35Sstevel } else { 67403831d35Sstevel miocnak(q, mp, 0, EINVAL); 67503831d35Sstevel } 67603831d35Sstevel } else { 67703831d35Sstevel qreply(q, mp); 67803831d35Sstevel } 67903831d35Sstevel } 68003831d35Sstevel 68103831d35Sstevel 68203831d35Sstevel /* 68303831d35Sstevel * cvc_redir() 68403831d35Sstevel * called from cvcredir:cvcr_wput() to handle console input 68503831d35Sstevel * data. This routine puts the cvcredir write (downstream) data 68603831d35Sstevel * onto the cvc read (upstream) queues. 68703831d35Sstevel */ 68803831d35Sstevel int 68903831d35Sstevel cvc_redir(mblk_t *mp) 69003831d35Sstevel { 69103831d35Sstevel register struct iocblk *iocp; 69203831d35Sstevel int rv = 1; 69303831d35Sstevel 69403831d35Sstevel /* 69503831d35Sstevel * This function shouldn't be called if cvcredir hasn't registered yet. 69603831d35Sstevel */ 69703831d35Sstevel if (cvcinput_q == NULL) { 69803831d35Sstevel /* 69903831d35Sstevel * Need to let caller know that it may be necessary for them to 70003831d35Sstevel * free the message buffer, so return 0. 70103831d35Sstevel */ 70203831d35Sstevel CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled"); 70303831d35Sstevel cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); 70403831d35Sstevel return (0); 70503831d35Sstevel } 70603831d35Sstevel 70703831d35Sstevel CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type); 70803831d35Sstevel if (mp->b_datap->db_type == M_DATA) { 70903831d35Sstevel /* 71003831d35Sstevel * XXX - should canputnext be called here? Starfire's cvc 71103831d35Sstevel * doesn't do that, and it appears to work anyway. 71203831d35Sstevel */ 71303831d35Sstevel CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp); 71403831d35Sstevel (void) putnext(cvcinput_q, mp); 71503831d35Sstevel } else if (mp->b_datap->db_type == M_IOCTL) { 71603831d35Sstevel /* 71703831d35Sstevel * The cvcredir driver filters out ioctl mblks we wouldn't 71803831d35Sstevel * understand, so we don't have to check for every conceivable 71903831d35Sstevel * ioc_cmd. However, additional ioctls may be supported (again) 72003831d35Sstevel * some day, so the code is structured to check the value even 72103831d35Sstevel * though there's only one that is currently supported. 72203831d35Sstevel */ 72303831d35Sstevel iocp = (struct iocblk *)mp->b_rptr; 72403831d35Sstevel if (iocp->ioc_cmd == CVC_DISCONNECT) { 72503831d35Sstevel (void) putnextctl(cvcinput_q, M_HANGUP); 72603831d35Sstevel } 72703831d35Sstevel } else { 72803831d35Sstevel /* 72903831d35Sstevel * Since we don't know what this mblk is, we're not going to 73003831d35Sstevel * process it. 73103831d35Sstevel */ 73203831d35Sstevel CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d", 73303831d35Sstevel mp->b_datap->db_type); 73403831d35Sstevel rv = 0; 73503831d35Sstevel } 73603831d35Sstevel 73703831d35Sstevel return (rv); 73803831d35Sstevel } 73903831d35Sstevel 74003831d35Sstevel 74103831d35Sstevel /* 74203831d35Sstevel * cvc_register() 74303831d35Sstevel * called from cvcredir to register it's queues. cvc 74403831d35Sstevel * receives data from cn via the streamhead and sends it to cvcredir 74503831d35Sstevel * via pointers to cvcredir's queues. 74603831d35Sstevel */ 74703831d35Sstevel int 74803831d35Sstevel cvc_register(queue_t *q) 74903831d35Sstevel { 75003831d35Sstevel int error = -1; 75103831d35Sstevel 75203831d35Sstevel if (cvcinput_q == NULL) 75303831d35Sstevel cmn_err(CE_WARN, "cvc_register: register w/ no console open!"); 75403831d35Sstevel rw_enter(&cvclock, RW_WRITER); 75503831d35Sstevel if (cvcoutput_q == NULL) { 75603831d35Sstevel cvcoutput_q = RD(q); /* Make sure its the upstream q */ 75703831d35Sstevel qprocson(cvcoutput_q); /* must be done within cvclock */ 75803831d35Sstevel error = 0; 75903831d35Sstevel } else { 76003831d35Sstevel /* 76103831d35Sstevel * cmn_err will call us, so release lock. 76203831d35Sstevel */ 76303831d35Sstevel rw_exit(&cvclock); 76403831d35Sstevel if (cvcoutput_q == q) 76503831d35Sstevel cmn_err(CE_WARN, "cvc_register: duplicate q!"); 76603831d35Sstevel else 76703831d35Sstevel cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p", 768*07d06da5SSurya Prakki (void *)q); 76903831d35Sstevel return (error); 77003831d35Sstevel } 77103831d35Sstevel rw_exit(&cvclock); 77203831d35Sstevel return (error); 77303831d35Sstevel } 77403831d35Sstevel 77503831d35Sstevel 77603831d35Sstevel /* 77703831d35Sstevel * cvc_unregister() 77803831d35Sstevel * called from cvcredir to clear pointers to its queues. 77903831d35Sstevel * cvcredir no longer wants to send or receive data. 78003831d35Sstevel */ 78103831d35Sstevel void 78203831d35Sstevel cvc_unregister(queue_t *q) 78303831d35Sstevel { 78403831d35Sstevel rw_enter(&cvclock, RW_WRITER); 78503831d35Sstevel if (q == cvcoutput_q) { 78603831d35Sstevel qprocsoff(cvcoutput_q); /* must be done within cvclock */ 78703831d35Sstevel cvcoutput_q = NULL; 78803831d35Sstevel } else { 78903831d35Sstevel rw_exit(&cvclock); 790*07d06da5SSurya Prakki cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered", 791*07d06da5SSurya Prakki (void *)q); 79203831d35Sstevel return; 79303831d35Sstevel } 79403831d35Sstevel rw_exit(&cvclock); 79503831d35Sstevel } 79603831d35Sstevel 79703831d35Sstevel 79803831d35Sstevel /* 79903831d35Sstevel * cvc_reioctl() 80003831d35Sstevel * Retry an "ioctl", now that "bufcall" claims we may be able 80103831d35Sstevel * to allocate the buffer we need. 80203831d35Sstevel */ 80303831d35Sstevel static void 80403831d35Sstevel cvc_reioctl(void *unit) 80503831d35Sstevel { 80603831d35Sstevel register queue_t *q; 80703831d35Sstevel register mblk_t *mp; 80803831d35Sstevel register cvc_t *cp = (cvc_t *)unit; 80903831d35Sstevel 81003831d35Sstevel /* 81103831d35Sstevel * The bufcall is no longer pending. 81203831d35Sstevel */ 81303831d35Sstevel if (!cp->cvc_wbufcid) { 81403831d35Sstevel return; 81503831d35Sstevel } 81603831d35Sstevel cp->cvc_wbufcid = 0; 81703831d35Sstevel if ((q = cp->cvc_tty.t_writeq) == NULL) { 81803831d35Sstevel return; 81903831d35Sstevel } 82003831d35Sstevel if ((mp = cp->cvc_tty.t_iocpending) != NULL) { 82103831d35Sstevel /* not pending any more */ 82203831d35Sstevel cp->cvc_tty.t_iocpending = NULL; 82303831d35Sstevel cvc_ioctl(q, mp); 82403831d35Sstevel } 82503831d35Sstevel } 82603831d35Sstevel 82703831d35Sstevel 82803831d35Sstevel /* 82903831d35Sstevel * cvc_iosram_ops() 83003831d35Sstevel * Process commands sent to cvc from netcon_server via IOSRAM 83103831d35Sstevel */ 83203831d35Sstevel static void 83303831d35Sstevel cvc_iosram_ops(uint8_t op) 83403831d35Sstevel { 83503831d35Sstevel int rval = ESUCCESS; 83603831d35Sstevel static uint8_t stale_op = 0; 83703831d35Sstevel 83803831d35Sstevel ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex)); 83903831d35Sstevel 84003831d35Sstevel CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op); 84103831d35Sstevel 84203831d35Sstevel /* 84303831d35Sstevel * If this is a repeated notice of a command that was previously 84403831d35Sstevel * processed but couldn't be cleared due to EAGAIN (tunnel switch in 84503831d35Sstevel * progress), just clear the data_valid flag and return. 84603831d35Sstevel */ 84703831d35Sstevel if (op == stale_op) { 84803831d35Sstevel if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID, 84903831d35Sstevel IOSRAM_INT_NONE) == 0) { 85003831d35Sstevel stale_op = 0; 85103831d35Sstevel } 85203831d35Sstevel return; 85303831d35Sstevel } 85403831d35Sstevel stale_op = 0; 85503831d35Sstevel 85603831d35Sstevel switch (op) { 85703831d35Sstevel case CVC_IOSRAM_BREAK: /* A console break (L1-A) */ 85803831d35Sstevel abort_sequence_enter((char *)NULL); 85903831d35Sstevel break; 86003831d35Sstevel 86103831d35Sstevel case CVC_IOSRAM_DISCONNECT: /* Break connection, hang up */ 86203831d35Sstevel if (cvcinput_q) 86303831d35Sstevel (void) putnextctl(cvcinput_q, M_HANGUP); 86403831d35Sstevel break; 86503831d35Sstevel 86603831d35Sstevel case CVC_IOSRAM_VIA_NET: /* console via network */ 86703831d35Sstevel via_iosram = 0; 86803831d35Sstevel break; 86903831d35Sstevel 87003831d35Sstevel case CVC_IOSRAM_VIA_IOSRAM: /* console via iosram */ 87103831d35Sstevel via_iosram = 1; 87203831d35Sstevel /* 87303831d35Sstevel * Tell cvcd to close any network connection it has. 87403831d35Sstevel */ 87503831d35Sstevel rw_enter(&cvclock, RW_READER); 87603831d35Sstevel if (cvcoutput_q != NULL) { 87703831d35Sstevel (void) putnextctl(cvcoutput_q, M_HANGUP); 87803831d35Sstevel } 87903831d35Sstevel rw_exit(&cvclock); 88003831d35Sstevel break; 88103831d35Sstevel 88203831d35Sstevel case CVC_IOSRAM_WIN_RESIZE: /* console window size data */ 88303831d35Sstevel /* 88403831d35Sstevel * In the case of window resizing, we don't want to 88503831d35Sstevel * record a stale_op value because we should always use 88603831d35Sstevel * the most recent winsize info, which could change 88703831d35Sstevel * between the time that we fail to clear the flag and 88803831d35Sstevel * the next time we try to process the command. So, 88903831d35Sstevel * we'll just let cvc_win_resize clear the data_valid 89003831d35Sstevel * flag itself (hence the TRUE parameter) and not worry 89103831d35Sstevel * about whether or not it succeeds. 89203831d35Sstevel */ 89303831d35Sstevel cvc_win_resize(TRUE); 89403831d35Sstevel return; 89503831d35Sstevel /* NOTREACHED */ 89603831d35Sstevel 89703831d35Sstevel default: 89803831d35Sstevel cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op); 89903831d35Sstevel break; 90003831d35Sstevel } 90103831d35Sstevel 90203831d35Sstevel /* 90303831d35Sstevel * Clear CONC's data_valid flag to indicate that the chunk is available 90403831d35Sstevel * for further communications. If the flag can't be cleared due to an 90503831d35Sstevel * error, record the op value so we'll know to ignore it when we see it 90603831d35Sstevel * on the next poll. 90703831d35Sstevel */ 90803831d35Sstevel rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID, 90903831d35Sstevel IOSRAM_INT_NONE); 91003831d35Sstevel if (rval != 0) { 91103831d35Sstevel stale_op = op; 91203831d35Sstevel if (rval != EAGAIN) { 91303831d35Sstevel cmn_err(CE_WARN, 91403831d35Sstevel "cvc_iosram_ops: set flag for cntlbuf ret %d", 91503831d35Sstevel rval); 91603831d35Sstevel } 91703831d35Sstevel } 91803831d35Sstevel } 91903831d35Sstevel 92003831d35Sstevel 92103831d35Sstevel /* 92203831d35Sstevel * cvc_send_to_iosram() 92303831d35Sstevel * Flush as much data as possible to the CONO chunk. If successful, free 92403831d35Sstevel * any mblks that were completely transmitted, update the b_rptr field in 92503831d35Sstevel * the first remaining mblk if it was partially transmitted, and update the 92603831d35Sstevel * caller's pointer to the new head of the mblk chain. Since the software 92703831d35Sstevel * that will be pulling this data out of IOSRAM (dxs on the SC) is just 92803831d35Sstevel * polling at some frequency, we avoid attempts to flush data to IOSRAM any 92903831d35Sstevel * faster than a large divisor of that polling frequency. 93003831d35Sstevel * 93103831d35Sstevel * Note that "cvc_buf_t out" is only declared "static" to keep it from 93203831d35Sstevel * being allocated on the stack. Allocating 1K+ structures on the stack 93303831d35Sstevel * seems rather antisocial. 93403831d35Sstevel */ 93503831d35Sstevel static void 93603831d35Sstevel cvc_send_to_iosram(mblk_t **chainpp) 93703831d35Sstevel { 93803831d35Sstevel int rval; 93903831d35Sstevel uint8_t dvalid; 94003831d35Sstevel uchar_t *cp; 94103831d35Sstevel mblk_t *mp; 94203831d35Sstevel mblk_t *last_empty_mp; 94303831d35Sstevel static clock_t last_flush = (clock_t)-1; 94403831d35Sstevel static cvc_buf_t out; /* see note above about static */ 94503831d35Sstevel 94603831d35Sstevel ASSERT(chainpp != NULL); 94703831d35Sstevel 94803831d35Sstevel /* 94903831d35Sstevel * We _do_ have something to do, right? 95003831d35Sstevel */ 95103831d35Sstevel if (*chainpp == NULL) { 95203831d35Sstevel return; 95303831d35Sstevel } 95403831d35Sstevel 95503831d35Sstevel /* 95603831d35Sstevel * We can actually increase throughput by throttling back on attempts to 95703831d35Sstevel * flush data to IOSRAM, since trying to write every little bit of data 95803831d35Sstevel * as it shows up will actually generate more delays waiting for the SC 95903831d35Sstevel * to pick up each of those bits. Instead, we'll avoid attempting to 96003831d35Sstevel * write data to IOSRAM any faster than half of the polling frequency we 96103831d35Sstevel * expect the SC to be using. 96203831d35Sstevel */ 96303831d35Sstevel if (ddi_get_lbolt() - last_flush < 96403831d35Sstevel drv_usectohz(CVC_IOSRAM_POLL_USECS / 2)) { 96503831d35Sstevel return; 96603831d35Sstevel } 96703831d35Sstevel 96803831d35Sstevel /* 96903831d35Sstevel * If IOSRAM is inaccessible or the CONO chunk still holds data that 97003831d35Sstevel * hasn't been picked up by the SC, there's nothing we can do right now. 97103831d35Sstevel */ 97203831d35Sstevel rval = iosram_get_flag(IOSRAM_KEY_CONO, &dvalid, NULL); 97303831d35Sstevel if ((rval != 0) || (dvalid == IOSRAM_DATA_VALID)) { 97403831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 97503831d35Sstevel cmn_err(CE_WARN, "cvc_send_to_iosram: get_flag ret %d", 97603831d35Sstevel rval); 97703831d35Sstevel } 97803831d35Sstevel return; 97903831d35Sstevel } 98003831d35Sstevel 98103831d35Sstevel /* 98203831d35Sstevel * Copy up to MAX_XFER_COUTPUT chars from the mblk chain into a buffer. 98303831d35Sstevel * Don't change any of the mblks just yet, since we can't be certain 98403831d35Sstevel * that we'll be successful in writing data to the CONO chunk. 98503831d35Sstevel */ 98603831d35Sstevel out.count = 0; 98703831d35Sstevel mp = *chainpp; 98803831d35Sstevel cp = mp->b_rptr; 98903831d35Sstevel last_empty_mp = NULL; 99003831d35Sstevel while ((mp != NULL) && (out.count < MAX_XFER_COUTPUT)) { 99103831d35Sstevel /* 99203831d35Sstevel * Process as many of the characters in the current mblk as 99303831d35Sstevel * possible. 99403831d35Sstevel */ 99503831d35Sstevel while ((cp != mp->b_wptr) && (out.count < MAX_XFER_COUTPUT)) { 99603831d35Sstevel out.buffer[out.count++] = *cp++; 99703831d35Sstevel } 99803831d35Sstevel 99903831d35Sstevel /* 100003831d35Sstevel * Did we process that entire mblk? If so, move on to the next 100103831d35Sstevel * one. If not, we're done filling the buffer even if there's 100203831d35Sstevel * space left, because apparently there wasn't room to process 100303831d35Sstevel * the next character. 100403831d35Sstevel */ 100503831d35Sstevel if (cp != mp->b_wptr) { 100603831d35Sstevel break; 100703831d35Sstevel } 100803831d35Sstevel 100903831d35Sstevel /* 101003831d35Sstevel * When this loop terminates, last_empty_mp will point to the 101103831d35Sstevel * last mblk that was completely processed, mp will point to the 101203831d35Sstevel * following mblk (or NULL if no more mblks exist), and cp will 101303831d35Sstevel * point to the first untransmitted character in the mblk 101403831d35Sstevel * pointed to by mp. We'll need this data to update the mblk 101503831d35Sstevel * chain if all of the data is successfully transmitted. 101603831d35Sstevel */ 101703831d35Sstevel last_empty_mp = mp; 101803831d35Sstevel mp = mp->b_cont; 101903831d35Sstevel cp = (mp != NULL) ? mp->b_rptr : NULL; 102003831d35Sstevel } 102103831d35Sstevel 102203831d35Sstevel /* 102303831d35Sstevel * If we succeeded in preparing some data, try to transmit it through 102403831d35Sstevel * IOSRAM. First write the count and the data, which can be done in a 102503831d35Sstevel * single operation thanks to the buffer structure we use, then set the 102603831d35Sstevel * data_valid flag if the first step succeeded. 102703831d35Sstevel */ 102803831d35Sstevel if (out.count != 0) { 102903831d35Sstevel rval = iosram_wr(IOSRAM_KEY_CONO, COUNT_OFFSET, 103003831d35Sstevel CONSBUF_COUNT_SIZE + out.count, (caddr_t)&out); 103103831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 103203831d35Sstevel cmn_err(CE_WARN, "cvc_putc: write ret %d", rval); 103303831d35Sstevel } 103403831d35Sstevel 103503831d35Sstevel /* if the data write succeeded, set the data_valid flag */ 103603831d35Sstevel if (rval == 0) { 103703831d35Sstevel rval = iosram_set_flag(IOSRAM_KEY_CONO, 103803831d35Sstevel IOSRAM_DATA_VALID, IOSRAM_INT_NONE); 103903831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 104003831d35Sstevel cmn_err(CE_WARN, 104103831d35Sstevel "cvc_putc: set flags for outbuf ret %d", 104203831d35Sstevel rval); 104303831d35Sstevel } 104403831d35Sstevel } 104503831d35Sstevel 104603831d35Sstevel /* 104703831d35Sstevel * If we successfully transmitted any data, modify the caller's 104803831d35Sstevel * mblk chain to remove the data that was transmitted, freeing 104903831d35Sstevel * all mblks that were completely processed. 105003831d35Sstevel */ 105103831d35Sstevel if (rval == 0) { 105203831d35Sstevel last_flush = ddi_get_lbolt(); 105303831d35Sstevel 105403831d35Sstevel /* 105503831d35Sstevel * If any data is left over, update the b_rptr field of 105603831d35Sstevel * the first remaining mblk in case some of its data was 105703831d35Sstevel * processed. 105803831d35Sstevel */ 105903831d35Sstevel if (mp != NULL) { 106003831d35Sstevel mp->b_rptr = cp; 106103831d35Sstevel } 106203831d35Sstevel 106303831d35Sstevel /* 106403831d35Sstevel * If any mblks have been emptied, unlink them from the 106503831d35Sstevel * residual chain, free them, and update the caller's 106603831d35Sstevel * mblk pointer. 106703831d35Sstevel */ 106803831d35Sstevel if (last_empty_mp != NULL) { 106903831d35Sstevel last_empty_mp->b_cont = NULL; 107003831d35Sstevel freemsg(*chainpp); 107103831d35Sstevel *chainpp = mp; 107203831d35Sstevel } 107303831d35Sstevel } 107403831d35Sstevel } 107503831d35Sstevel } 107603831d35Sstevel 107703831d35Sstevel 107803831d35Sstevel /* 107903831d35Sstevel * cvc_flush_queue() 108003831d35Sstevel * Tell the STREAMS subsystem to schedule cvc_wsrv to process the queue we 108103831d35Sstevel * use to gather console output. 108203831d35Sstevel */ 108303831d35Sstevel /* ARGSUSED */ 108403831d35Sstevel static void 108503831d35Sstevel cvc_flush_queue(void *notused) 108603831d35Sstevel { 108703831d35Sstevel rw_enter(&cvclock, RW_WRITER); 108803831d35Sstevel if (cvcinput_q != NULL) { 108903831d35Sstevel qenable(WR(cvcinput_q)); 109003831d35Sstevel } 109103831d35Sstevel 109203831d35Sstevel cvc_timeout_id = (timeout_id_t)-1; 109303831d35Sstevel rw_exit(&cvclock); 109403831d35Sstevel } 109503831d35Sstevel 109603831d35Sstevel 109703831d35Sstevel /* 109803831d35Sstevel * cvc_getstr() 109903831d35Sstevel * Poll IOSRAM for console input while available. 110003831d35Sstevel */ 110103831d35Sstevel static void 110203831d35Sstevel cvc_getstr(char *cp) 110303831d35Sstevel { 110403831d35Sstevel short count; 110503831d35Sstevel uint8_t command = 0; 110603831d35Sstevel int rval = ESUCCESS; 110703831d35Sstevel uint8_t dvalid = IOSRAM_DATA_INVALID; 110803831d35Sstevel uint8_t intrpending = 0; 110903831d35Sstevel 111003831d35Sstevel mutex_enter(&cvc_iosram_input_mutex); 111103831d35Sstevel while (dvalid == IOSRAM_DATA_INVALID) { 111203831d35Sstevel /* 111303831d35Sstevel * Check the CONC data_valid flag to see if a control message is 111403831d35Sstevel * available. 111503831d35Sstevel */ 111603831d35Sstevel rval = iosram_get_flag(IOSRAM_KEY_CONC, &dvalid, &intrpending); 111703831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 111803831d35Sstevel cmn_err(CE_WARN, 111903831d35Sstevel "cvc_getstr: get flag for cntl ret %d", rval); 112003831d35Sstevel } 112103831d35Sstevel 112203831d35Sstevel /* 112303831d35Sstevel * If a control message is available, try to read and process 112403831d35Sstevel * it. 112503831d35Sstevel */ 112603831d35Sstevel if ((dvalid == IOSRAM_DATA_VALID) && (rval == 0)) { 112703831d35Sstevel /* read the control reg offset */ 112803831d35Sstevel rval = iosram_rd(IOSRAM_KEY_CONC, 112903831d35Sstevel CVC_CTL_OFFSET(command), CVC_CTL_SIZE(command), 113003831d35Sstevel (caddr_t)&command); 113103831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 113203831d35Sstevel cmn_err(CE_WARN, 113303831d35Sstevel "cvc_getstr: read for command ret %d", 113403831d35Sstevel rval); 113503831d35Sstevel } 113603831d35Sstevel 113703831d35Sstevel /* process the cntl msg and clear the data_valid flag */ 113803831d35Sstevel if (rval == 0) { 113903831d35Sstevel cvc_iosram_ops(command); 114003831d35Sstevel } 114103831d35Sstevel } 114203831d35Sstevel 114303831d35Sstevel /* 114403831d35Sstevel * Check the CONI data_valid flag to see if console input data 114503831d35Sstevel * is available. 114603831d35Sstevel */ 114703831d35Sstevel rval = iosram_get_flag(IOSRAM_KEY_CONI, &dvalid, &intrpending); 114803831d35Sstevel if ((rval != 0) && (rval != EAGAIN)) { 114919397407SSherry Moore cmn_err(CE_WARN, 115019397407SSherry Moore "cvc_getstr: get flag for inbuf ret %d", 115103831d35Sstevel rval); 115203831d35Sstevel } 115303831d35Sstevel if ((rval != 0) || (dvalid != IOSRAM_DATA_VALID)) { 115403831d35Sstevel goto retry; 115503831d35Sstevel } 115603831d35Sstevel 115703831d35Sstevel /* 115803831d35Sstevel * Try to read the count. 115903831d35Sstevel */ 116003831d35Sstevel rval = iosram_rd(IOSRAM_KEY_CONI, COUNT_OFFSET, 116103831d35Sstevel CONSBUF_COUNT_SIZE, (caddr_t)&count); 116203831d35Sstevel if (rval != 0) { 116303831d35Sstevel if (rval != EAGAIN) { 116403831d35Sstevel cmn_err(CE_WARN, 116503831d35Sstevel "cvc_getstr: read for count ret %d", rval); 116603831d35Sstevel } 116703831d35Sstevel goto retry; 116803831d35Sstevel } 116903831d35Sstevel 117003831d35Sstevel /* 117103831d35Sstevel * If there is data to be read, try to read it. 117203831d35Sstevel */ 117303831d35Sstevel if (count != 0) { 117403831d35Sstevel rval = iosram_rd(IOSRAM_KEY_CONI, DATA_OFFSET, count, 117503831d35Sstevel (caddr_t)cp); 117603831d35Sstevel if (rval != 0) { 117703831d35Sstevel if (rval != EAGAIN) { 117803831d35Sstevel cmn_err(CE_WARN, 117903831d35Sstevel "cvc_getstr: read for count ret %d", 118003831d35Sstevel rval); 118103831d35Sstevel } 118203831d35Sstevel goto retry; 118303831d35Sstevel } 118403831d35Sstevel cp[count] = '\0'; 118503831d35Sstevel } 118603831d35Sstevel 118703831d35Sstevel /* 118803831d35Sstevel * Try to clear the data_valid flag to indicate that whatever 118903831d35Sstevel * was in CONI was read successfully. If successful, and some 119003831d35Sstevel * data was read, break out of the loop to return to the caller. 119103831d35Sstevel */ 119203831d35Sstevel rval = iosram_set_flag(IOSRAM_KEY_CONI, IOSRAM_DATA_INVALID, 119303831d35Sstevel IOSRAM_INT_NONE); 119403831d35Sstevel if (rval != 0) { 119503831d35Sstevel if (rval != EAGAIN) { 119603831d35Sstevel cmn_err(CE_WARN, 119703831d35Sstevel "cvc_getstr: set flag for inbuf ret %d", 119803831d35Sstevel rval); 119903831d35Sstevel } 120003831d35Sstevel } else if (count != 0) { 120103831d35Sstevel CVC_DBG1(CVC_DBG_IOSRAM_RD, "Read 0x%x", count); 120203831d35Sstevel break; 120303831d35Sstevel } 120403831d35Sstevel 120503831d35Sstevel /* 120603831d35Sstevel * Use a smaller delay between checks of IOSRAM for input 120703831d35Sstevel * when cvcd/cvcredir are not running or "via_iosram" has 120803831d35Sstevel * been set. 120903831d35Sstevel * We don't go away completely when i/o is going through the 121003831d35Sstevel * network via cvcd since a command may be sent via IOSRAM 121103831d35Sstevel * to switch if the network is down or hung. 121203831d35Sstevel */ 121303831d35Sstevel retry: 121403831d35Sstevel if ((cvcoutput_q == NULL) || (via_iosram)) 121503831d35Sstevel delay(drv_usectohz(CVC_IOSRAM_POLL_USECS)); 121603831d35Sstevel else 121703831d35Sstevel delay(drv_usectohz(CVC_IOSRAM_POLL_USECS * 10)); 121803831d35Sstevel 121903831d35Sstevel } 122003831d35Sstevel 122103831d35Sstevel mutex_exit(&cvc_iosram_input_mutex); 122203831d35Sstevel } 122303831d35Sstevel 122403831d35Sstevel 122503831d35Sstevel /* 122603831d35Sstevel * cvc_input_daemon() 122703831d35Sstevel * this function runs as a separate kernel thread and polls IOSRAM for 122803831d35Sstevel * input, and possibly put it on read stream for the console. 122903831d35Sstevel * There are two poll rates (implemented in cvc_getstr): 123003831d35Sstevel * 100 000 uS (10 Hz) - no cvcd communications || via_iosram 123103831d35Sstevel * 1000 000 uS ( 1 Hz) - cvcd communications 123203831d35Sstevel * This continues to run even if there are network console communications 123303831d35Sstevel * in order to handle out-of-band signaling. 123403831d35Sstevel */ 123503831d35Sstevel /* ARGSUSED */ 123603831d35Sstevel static void 123703831d35Sstevel cvc_input_daemon(void) 123803831d35Sstevel { 123903831d35Sstevel char linebuf[MAX_XFER_CINPUT + 1]; 124003831d35Sstevel char *cp; 124103831d35Sstevel mblk_t *mbp; 124203831d35Sstevel int c; 124303831d35Sstevel int dropped_read = 0; 124403831d35Sstevel 124503831d35Sstevel for (;;) { 124603831d35Sstevel cvc_getstr(linebuf); 124703831d35Sstevel 124803831d35Sstevel mbp = allocb(strlen(linebuf), BPRI_MED); 124903831d35Sstevel if (mbp == NULL) { /* drop it & go on if no buffer */ 125003831d35Sstevel if (!dropped_read) { 125103831d35Sstevel cmn_err(CE_WARN, "cvc_input_daemon: " 125203831d35Sstevel "dropping IOSRAM reads"); 125303831d35Sstevel } 125403831d35Sstevel dropped_read++; 125503831d35Sstevel continue; 125603831d35Sstevel } 125703831d35Sstevel 125803831d35Sstevel if (dropped_read) { 125903831d35Sstevel cmn_err(CE_WARN, 126003831d35Sstevel "cvc_input_daemon: dropped %d IOSRAM reads", 126103831d35Sstevel dropped_read); 126203831d35Sstevel dropped_read = 0; 126303831d35Sstevel } 126403831d35Sstevel 126503831d35Sstevel for (cp = linebuf; *cp != '\0'; cp++) { 126603831d35Sstevel c = (int)*cp; 126703831d35Sstevel if (c == '\r') 126803831d35Sstevel c = '\n'; 126903831d35Sstevel c &= 0177; 127003831d35Sstevel *mbp->b_wptr = (char)c; 127103831d35Sstevel mbp->b_wptr++; 127203831d35Sstevel } 127303831d35Sstevel mutex_enter(&cvcmutex); 127403831d35Sstevel if (input_ok) { 127503831d35Sstevel if (cvcinput_q == NULL) { 127603831d35Sstevel cmn_err(CE_WARN, 127703831d35Sstevel "cvc_input_daemon: cvcinput_q is NULL!"); 127803831d35Sstevel } else { 127903831d35Sstevel /* 128003831d35Sstevel * XXX - should canputnext be called here? 128103831d35Sstevel * Starfire's cvc doesn't do that, and it 128203831d35Sstevel * appears to work anyway. 128303831d35Sstevel */ 128403831d35Sstevel (void) putnext(cvcinput_q, mbp); 128503831d35Sstevel } 128603831d35Sstevel } else { 128703831d35Sstevel freemsg(mbp); 128803831d35Sstevel } 128903831d35Sstevel mutex_exit(&cvcmutex); 129003831d35Sstevel } 129103831d35Sstevel 129203831d35Sstevel /* NOTREACHED */ 129303831d35Sstevel } 129403831d35Sstevel 129503831d35Sstevel /* 129603831d35Sstevel * cvc_win_resize() 129703831d35Sstevel * cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set 129803831d35Sstevel * the console window size accordingly. If indicated by the caller, CONC's 129903831d35Sstevel * data_valid flag will also be cleared. The flag isn't cleared in all 130003831d35Sstevel * cases because we need to process winsize data at startup without waiting 130103831d35Sstevel * for a command. 130203831d35Sstevel */ 130303831d35Sstevel static void 130403831d35Sstevel cvc_win_resize(int clear_flag) 130503831d35Sstevel { 130603831d35Sstevel int rval; 130703831d35Sstevel uint16_t rows; 130803831d35Sstevel uint16_t cols; 130903831d35Sstevel uint16_t xpixels; 131003831d35Sstevel uint16_t ypixels; 131103831d35Sstevel tty_common_t *tty; 131203831d35Sstevel cvc_t *cp; 131303831d35Sstevel struct winsize ws; 131403831d35Sstevel 131503831d35Sstevel /* 131603831d35Sstevel * Start by reading the new window size out of the CONC chunk and, if 131703831d35Sstevel * requested, clearing CONC's data_valid flag. If any of that fails, 131803831d35Sstevel * return immediately. (Note that the rather bulky condition in the 131903831d35Sstevel * two "if" statements takes advantage of C's short-circuit logic 132003831d35Sstevel * evaluation) 132103831d35Sstevel */ 132203831d35Sstevel if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows), 132303831d35Sstevel CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) || 132403831d35Sstevel ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols), 132503831d35Sstevel CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) || 132603831d35Sstevel ((rval = iosram_rd(IOSRAM_KEY_CONC, 132703831d35Sstevel CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels), 132803831d35Sstevel (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC, 132903831d35Sstevel CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels), 133003831d35Sstevel (caddr_t)&ypixels)) != 0)) { 133103831d35Sstevel if (rval != EAGAIN) { 133203831d35Sstevel cmn_err(CE_WARN, 133303831d35Sstevel "cvc_win_resize: read for ctlbuf ret %d", rval); 133403831d35Sstevel } 133503831d35Sstevel return; 133603831d35Sstevel } 133703831d35Sstevel 133803831d35Sstevel if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC, 133903831d35Sstevel IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) { 134003831d35Sstevel if (rval != EAGAIN) { 134103831d35Sstevel cmn_err(CE_WARN, 134203831d35Sstevel "cvc_win_resize: set_flag for ctlbuf ret %d", rval); 134303831d35Sstevel } 134403831d35Sstevel return; 134503831d35Sstevel } 134603831d35Sstevel 134703831d35Sstevel /* 134803831d35Sstevel * Copy the parameters from IOSRAM to a winsize struct. 134903831d35Sstevel */ 135003831d35Sstevel ws.ws_row = rows; 135103831d35Sstevel ws.ws_col = cols; 135203831d35Sstevel ws.ws_xpixel = xpixels; 135303831d35Sstevel ws.ws_ypixel = ypixels; 135403831d35Sstevel 135503831d35Sstevel /* 135603831d35Sstevel * This code was taken from Starfire, and it appears to work correctly. 135703831d35Sstevel * However, since the original developer felt it necessary to add the 135803831d35Sstevel * following comment, it's probably worth preserving: 135903831d35Sstevel * 136003831d35Sstevel * XXX I hope this is safe... 136103831d35Sstevel */ 136203831d35Sstevel cp = cvcinput_q->q_ptr; 136303831d35Sstevel tty = &cp->cvc_tty; 136403831d35Sstevel mutex_enter(&tty->t_excl); 136503831d35Sstevel if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws, 136603831d35Sstevel sizeof (struct winsize))) { 136703831d35Sstevel tty->t_size = ws; 136803831d35Sstevel mutex_exit(&tty->t_excl); 136903831d35Sstevel (void) putnextctl1(cvcinput_q, M_PCSIG, 137003831d35Sstevel SIGWINCH); 137103831d35Sstevel } else { 137203831d35Sstevel mutex_exit(&tty->t_excl); 137303831d35Sstevel } 137403831d35Sstevel } 137503831d35Sstevel 137603831d35Sstevel #ifdef DEBUG 137703831d35Sstevel 137803831d35Sstevel void 137903831d35Sstevel cvc_dbg(uint32_t flag, char *fmt, 138003831d35Sstevel uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 138103831d35Sstevel { 138203831d35Sstevel char *s = NULL; 138303831d35Sstevel char buf[256]; 138403831d35Sstevel 138503831d35Sstevel if (cvc_dbg_flags && ((cvc_dbg_flags & flag) == flag)) { 138603831d35Sstevel switch (flag) { 138703831d35Sstevel case CVC_DBG_ATTACH: 138803831d35Sstevel s = "attach"; 138903831d35Sstevel break; 139003831d35Sstevel case CVC_DBG_DETACH: 139103831d35Sstevel s = "detach"; 139203831d35Sstevel break; 139303831d35Sstevel case CVC_DBG_OPEN: 139403831d35Sstevel s = "open"; 139503831d35Sstevel break; 139603831d35Sstevel case CVC_DBG_CLOSE: 139703831d35Sstevel s = "close"; 139803831d35Sstevel break; 139903831d35Sstevel case CVC_DBG_IOCTL: 140003831d35Sstevel s = "ioctl"; 140103831d35Sstevel break; 140203831d35Sstevel case CVC_DBG_REDIR: 140303831d35Sstevel s = "redir"; 140403831d35Sstevel break; 140503831d35Sstevel case CVC_DBG_WPUT: 140603831d35Sstevel s = "wput"; 140703831d35Sstevel break; 140803831d35Sstevel case CVC_DBG_WSRV: 140903831d35Sstevel s = "wsrv"; 141003831d35Sstevel break; 141103831d35Sstevel case CVC_DBG_IOSRAM_WR: 141203831d35Sstevel s = "iosram_wr"; 141303831d35Sstevel break; 141403831d35Sstevel case CVC_DBG_IOSRAM_RD: 141503831d35Sstevel s = "iosram_rd"; 141603831d35Sstevel break; 141703831d35Sstevel case CVC_DBG_NETWORK_WR: 141803831d35Sstevel s = "network_wr"; 141903831d35Sstevel break; 142003831d35Sstevel case CVC_DBG_NETWORK_RD: 142103831d35Sstevel s = "network_rd"; 142203831d35Sstevel break; 142303831d35Sstevel case CVC_DBG_IOSRAM_CNTL: 142403831d35Sstevel s = "iosram_cntlmsg"; 142503831d35Sstevel break; 142603831d35Sstevel default: 142703831d35Sstevel s = "Unknown debug flag"; 142803831d35Sstevel break; 142903831d35Sstevel } 143003831d35Sstevel 1431*07d06da5SSurya Prakki (void) sprintf(buf, "!%s_%s(%d): %s", ddi_driver_name(cvcdip), 1432*07d06da5SSurya Prakki s, cvc_instance, fmt); 143303831d35Sstevel cmn_err(CE_NOTE, buf, a1, a2, a3, a4, a5); 143403831d35Sstevel } 143503831d35Sstevel } 143603831d35Sstevel 143703831d35Sstevel #endif /* DEBUG */ 1438