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
_init()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
_fini()20403831d35Sstevel _fini()
20503831d35Sstevel {
20603831d35Sstevel return (EBUSY);
20703831d35Sstevel }
20803831d35Sstevel
20903831d35Sstevel int
_info(struct modinfo * modinfop)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
cvc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)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
cvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
cvc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
cvc_open(register queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)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
cvc_close(queue_t * q,int flag,cred_t * crp)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
cvc_wput(queue_t * q,mblk_t * mp)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
cvc_wsrv(queue_t * q)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
cvc_ioctl(register queue_t * q,register mblk_t * mp)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
cvc_redir(mblk_t * mp)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
cvc_register(queue_t * q)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
cvc_unregister(queue_t * q)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
cvc_reioctl(void * unit)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
cvc_iosram_ops(uint8_t op)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
cvc_send_to_iosram(mblk_t ** chainpp)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
cvc_flush_queue(void * notused)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
cvc_getstr(char * cp)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
cvc_input_daemon(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
cvc_win_resize(int clear_flag)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
cvc_dbg(uint32_t flag,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)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