11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel
281708Sstevel /*
291708Sstevel * Serengeti console driver, see sys/sgcn.h for more information
301708Sstevel * This driver uses the QPAIR form of STREAMS Perimeters to serialize access
311708Sstevel * to the read and write STREAMS queues.
321708Sstevel */
331708Sstevel
341708Sstevel #include <sys/errno.h>
351708Sstevel #include <sys/stat.h>
361708Sstevel #include <sys/kmem.h>
371708Sstevel #include <sys/conf.h>
381708Sstevel #include <sys/termios.h>
391708Sstevel #include <sys/modctl.h>
401708Sstevel #include <sys/kbio.h>
411708Sstevel #include <sys/stropts.h>
421708Sstevel #include <sys/stream.h>
431708Sstevel #include <sys/strsun.h>
441708Sstevel #include <sys/sysmacros.h>
451708Sstevel #include <sys/promif.h>
461708Sstevel #include <sys/prom_plat.h>
471708Sstevel #include <sys/sgsbbc.h>
481708Sstevel #include <sys/sgsbbc_iosram.h>
491708Sstevel #include <sys/sgcn.h>
501708Sstevel #include <sys/serengeti.h>
511708Sstevel #include <sys/ddi.h>
521708Sstevel #include <sys/sunddi.h>
531708Sstevel #include <sys/strsubr.h>
541708Sstevel
551708Sstevel /*
561708Sstevel * Here we define several macros for accessing console IOSRAM
571708Sstevel */
581708Sstevel
591708Sstevel #define POINTER(base, field) ((caddr_t)&base.field)
601708Sstevel #define OFFSETOF(base, field) ((caddr_t)&base.field - (caddr_t)&base)
611708Sstevel
621708Sstevel #define RW_CONSOLE_READ 0xAAAA
631708Sstevel #define RW_CONSOLE_WRITE 0xBBBB
641708Sstevel
651708Sstevel #define CONSOLE_READ(buf, len) sgcn_rw(RW_CONSOLE_READ, buf, len)
661708Sstevel #define CONSOLE_WRITE(buf, len) sgcn_rw(RW_CONSOLE_WRITE, buf, len)
671708Sstevel
681708Sstevel #define SGCN_MI_IDNUM 0xABCD
691708Sstevel #define SGCN_MI_HIWAT 2048*2048
701708Sstevel #define SGCN_MI_LOWAT 128
711708Sstevel
721708Sstevel /* dev_ops and cb_ops for device driver */
731708Sstevel static int sgcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
741708Sstevel static int sgcn_attach(dev_info_t *, ddi_attach_cmd_t);
751708Sstevel static int sgcn_detach(dev_info_t *, ddi_detach_cmd_t);
761708Sstevel static int sgcn_open(queue_t *, dev_t *, int, int, cred_t *);
771708Sstevel static int sgcn_close(queue_t *, int, cred_t *);
781708Sstevel static int sgcn_wput(queue_t *, mblk_t *);
791708Sstevel static int sgcn_wsrv(queue_t *);
801708Sstevel static int sgcn_rsrv(queue_t *);
811708Sstevel
821708Sstevel /* interrupt handlers */
831708Sstevel static void sgcn_data_in_handler(caddr_t);
841708Sstevel static void sgcn_space_2_out_handler(caddr_t);
851708Sstevel static void sgcn_break_handler(caddr_t);
861708Sstevel
871708Sstevel /* other internal sgcn routines */
881708Sstevel static void sgcn_ioctl(queue_t *, mblk_t *);
891708Sstevel static void sgcn_reioctl(void *);
901708Sstevel static void sgcn_start(void);
911708Sstevel static int sgcn_transmit(queue_t *, mblk_t *);
921708Sstevel static void sgcn_flush(void);
931708Sstevel static int sgcn_read_header(int, cnsram_header *);
941708Sstevel static int sgcn_rw(int, caddr_t, int);
951708Sstevel static void sgcn_log_error(int, int);
961708Sstevel
971708Sstevel /* circular buffer routines */
981708Sstevel static int circular_buffer_write(int, int, int, int, caddr_t, int);
991708Sstevel static int circular_buffer_read(int, int, int, int, caddr_t, int);
1001708Sstevel
1011708Sstevel static boolean_t abort_charseq_recognize(uchar_t);
1021708Sstevel static void sg_abort_seq_handler(char *);
1031708Sstevel
1041708Sstevel static sgcn_t *sgcn_state;
1051708Sstevel static uchar_t sgcn_stopped = FALSE;
1061708Sstevel static int sgcn_timeout_period = 20; /* time out in seconds */
1071708Sstevel
1081708Sstevel /* streams structures */
1091708Sstevel static struct module_info minfo = {
1101708Sstevel SGCN_MI_IDNUM, /* mi_idnum */
1111708Sstevel "sgcn", /* mi_idname */
1121708Sstevel 0, /* mi_minpsz */
1131708Sstevel INFPSZ, /* mi_maxpsz */
1141708Sstevel SGCN_MI_HIWAT, /* mi_hiwat */
1151708Sstevel SGCN_MI_LOWAT /* mi_lowat */
1161708Sstevel };
1171708Sstevel
1181708Sstevel static struct qinit rinit = {
1191708Sstevel putq, /* qi_putp */
1201708Sstevel sgcn_rsrv, /* qi_srvp */
1211708Sstevel sgcn_open, /* qi_qopen */
1221708Sstevel sgcn_close, /* qi_qclose */
1231708Sstevel NULL, /* qi_qadmin */
1241708Sstevel &minfo, /* qi_minfo */
1251708Sstevel NULL /* qi_mstat */
1261708Sstevel };
1271708Sstevel
1281708Sstevel static struct qinit winit = {
1291708Sstevel sgcn_wput, /* qi_putp */
1301708Sstevel sgcn_wsrv, /* qi_srvp */
1311708Sstevel sgcn_open, /* qi_qopen */
1321708Sstevel sgcn_close, /* qi_qclose */
1331708Sstevel NULL, /* qi_qadmin */
1341708Sstevel &minfo, /* qi_minfo */
1351708Sstevel NULL /* qi_mstat */
1361708Sstevel };
1371708Sstevel
1381708Sstevel static struct streamtab sgcnstrinfo = {
1391708Sstevel &rinit,
1401708Sstevel &winit,
1411708Sstevel NULL,
1421708Sstevel NULL
1431708Sstevel };
1441708Sstevel
1451708Sstevel /* standard device driver structures */
1461708Sstevel static struct cb_ops sgcn_cb_ops = {
1471708Sstevel nulldev, /* open() */
1481708Sstevel nulldev, /* close() */
1491708Sstevel nodev, /* strategy() */
1501708Sstevel nodev, /* print() */
1511708Sstevel nodev, /* dump() */
1521708Sstevel nodev, /* read() */
1531708Sstevel nodev, /* write() */
1541708Sstevel nodev, /* ioctl() */
1551708Sstevel nodev, /* devmap() */
1561708Sstevel nodev, /* mmap() */
1571708Sstevel nodev, /* segmap() */
1581708Sstevel nochpoll, /* poll() */
1591708Sstevel ddi_prop_op, /* prop_op() */
1601708Sstevel &sgcnstrinfo, /* cb_str */
1611708Sstevel D_MP | D_MTQPAIR /* cb_flag */
1621708Sstevel };
1631708Sstevel
1641708Sstevel static struct dev_ops sgcn_ops = {
1651708Sstevel DEVO_REV,
1661708Sstevel 0, /* refcnt */
1671708Sstevel sgcn_getinfo, /* getinfo() */
1681708Sstevel nulldev, /* identify() */
1691708Sstevel nulldev, /* probe() */
1701708Sstevel sgcn_attach, /* attach() */
1711708Sstevel sgcn_detach, /* detach() */
1721708Sstevel nodev, /* reset() */
1731708Sstevel &sgcn_cb_ops, /* cb_ops */
1741708Sstevel (struct bus_ops *)NULL, /* bus_ops */
1757656SSherry.Moore@Sun.COM NULL, /* power() */
1767656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* quiesce */
1771708Sstevel };
1781708Sstevel
1791708Sstevel static struct modldrv modldrv = {
1801708Sstevel &mod_driverops,
1817656SSherry.Moore@Sun.COM "Serengeti console driver",
1821708Sstevel &sgcn_ops
1831708Sstevel };
1841708Sstevel
1851708Sstevel static struct modlinkage modlinkage = {
1861708Sstevel MODREV_1,
1871708Sstevel (void*)&modldrv,
1881708Sstevel NULL
1891708Sstevel };
1901708Sstevel
1911708Sstevel
1921708Sstevel /* driver configuration routines */
1931708Sstevel int
_init(void)1941708Sstevel _init(void)
1951708Sstevel {
1961708Sstevel int error;
1971708Sstevel
1981708Sstevel sgcn_state = kmem_zalloc(sizeof (sgcn_t), KM_SLEEP);
1991708Sstevel
2001708Sstevel error = mod_install(&modlinkage);
2011708Sstevel
2021708Sstevel if (error == 0) {
2031708Sstevel mutex_init(&sgcn_state->sgcn_lock, NULL, MUTEX_DRIVER, NULL);
2041708Sstevel } else {
2051708Sstevel kmem_free(sgcn_state, sizeof (sgcn_t));
2061708Sstevel }
2071708Sstevel
2081708Sstevel return (error);
2091708Sstevel }
2101708Sstevel
2111708Sstevel int
_fini(void)2121708Sstevel _fini(void)
2131708Sstevel {
2141708Sstevel /* can't remove console driver */
2151708Sstevel return (EBUSY);
2161708Sstevel }
2171708Sstevel
2181708Sstevel int
_info(struct modinfo * modinfop)2191708Sstevel _info(struct modinfo *modinfop)
2201708Sstevel {
2211708Sstevel return (mod_info(&modlinkage, modinfop));
2221708Sstevel }
2231708Sstevel
2241708Sstevel /*
2251708Sstevel * sgcn_attach is called at startup time.
2261708Sstevel * There is only once instance of this driver.
2271708Sstevel */
2281708Sstevel static int
sgcn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2291708Sstevel sgcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2301708Sstevel {
2311708Sstevel extern int ddi_create_internal_pathname(
2321708Sstevel dev_info_t *, char *, int, minor_t);
2331708Sstevel cnsram_header header;
2341708Sstevel int rv;
2351708Sstevel
2361708Sstevel if (cmd != DDI_ATTACH)
2371708Sstevel return (DDI_FAILURE);
2381708Sstevel
2391708Sstevel if (ddi_create_internal_pathname(dip, "sgcn", S_IFCHR, 0)
2401708Sstevel != DDI_SUCCESS)
2411708Sstevel return (DDI_FAILURE);
2421708Sstevel
2431708Sstevel /* prepare some data structures in soft state */
2441708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
2451708Sstevel
2461708Sstevel sgcn_state->sgcn_dip = dip;
2471708Sstevel
2481708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
2491708Sstevel
2501708Sstevel /*
2511708Sstevel * We need to verify IOSRAM is intact at startup time. If by
2521708Sstevel * any chance IOSRAM is corrupted, that means SC is not ready.
2531708Sstevel * All we can do is stopping.
2541708Sstevel */
2551708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 0, (caddr_t)&header,
2567656SSherry.Moore@Sun.COM sizeof (cnsram_header));
2571708Sstevel if (rv != 0)
2581708Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Reading from IOSRAM failed");
2591708Sstevel if (header.cnsram_magic != CNSRAM_MAGIC)
2601708Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM console buffer");
2611708Sstevel if (!header.cnsram_in_end && !header.cnsram_in_begin)
2621708Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM input buffer");
2631708Sstevel if (!header.cnsram_out_end && !header.cnsram_out_begin)
2641708Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM output buffer");
2651708Sstevel /*
2661708Sstevel * XXX need to add extra check for version no.
2671708Sstevel */
2681708Sstevel
2691708Sstevel /* Allocate console input buffer */
2701708Sstevel sgcn_state->sgcn_inbuf_size =
2717656SSherry.Moore@Sun.COM header.cnsram_in_end - header.cnsram_in_begin;
2721708Sstevel sgcn_state->sgcn_inbuf =
2737656SSherry.Moore@Sun.COM kmem_alloc(sgcn_state->sgcn_inbuf_size, KM_SLEEP);
2741708Sstevel #ifdef SGCN_DEBUG
2751708Sstevel prom_printf("Allocated %d(0x%X) bytes for console\n",
2767656SSherry.Moore@Sun.COM sgcn_state->sgcn_inbuf_size);
2771708Sstevel #endif
2781708Sstevel
2791708Sstevel (void) prom_serengeti_set_console_input(SGCN_CLNT_STR);
2801708Sstevel
2811708Sstevel abort_seq_handler = sg_abort_seq_handler;
2821708Sstevel
2831708Sstevel #ifdef SGCN_DEBUG
2841708Sstevel prom_printf("sgcn_attach(): SGCN driver attached\n");
2851708Sstevel #endif
2861708Sstevel return (DDI_SUCCESS);
2871708Sstevel
2881708Sstevel }
2891708Sstevel
2901708Sstevel /* ARGSUSED */
2911708Sstevel static int
sgcn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2921708Sstevel sgcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2931708Sstevel {
2941708Sstevel
2951708Sstevel if (cmd == DDI_DETACH)
2961708Sstevel return (DDI_FAILURE);
2971708Sstevel
2981708Sstevel #ifdef SGCN_DEBUG
2991708Sstevel prom_printf("sgcn_detach(): SGCN driver detached\n");
3001708Sstevel #endif
3011708Sstevel return (DDI_SUCCESS);
3021708Sstevel }
3031708Sstevel
3041708Sstevel /* ARGSUSED */
3051708Sstevel static int
sgcn_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3061708Sstevel sgcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3071708Sstevel {
3081708Sstevel int error = DDI_FAILURE;
3091708Sstevel
3101708Sstevel switch (infocmd) {
3111708Sstevel case DDI_INFO_DEVT2DEVINFO:
3121708Sstevel if (sgcn_state) {
3131708Sstevel *result = (void *) sgcn_state->sgcn_dip;
3141708Sstevel error = DDI_SUCCESS;
3151708Sstevel }
3161708Sstevel break;
3171708Sstevel
3181708Sstevel case DDI_INFO_DEVT2INSTANCE:
3191708Sstevel if (getminor((dev_t)arg) == 0) {
3201708Sstevel *result = (void *)0;
3211708Sstevel error = DDI_SUCCESS;
3221708Sstevel }
3231708Sstevel break;
3241708Sstevel }
3251708Sstevel
3261708Sstevel return (error);
3271708Sstevel }
3281708Sstevel
3291708Sstevel /* streams open & close */
3301708Sstevel /* ARGSUSED */
3311708Sstevel static int
sgcn_open(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)3321708Sstevel sgcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
3331708Sstevel {
3341708Sstevel tty_common_t *tty;
3351708Sstevel int unit = getminor(*devp);
3361708Sstevel
3371708Sstevel if (unit != 0)
3381708Sstevel return (ENXIO);
3391708Sstevel
3401708Sstevel /* stream already open */
3411708Sstevel if (q->q_ptr) {
3421708Sstevel return (DDI_SUCCESS);
3431708Sstevel }
3441708Sstevel
3451708Sstevel if (!sgcn_state) {
3461708Sstevel cmn_err(CE_WARN, "sgcn_open(): sgcn is not configured by\
3471708Sstevel autoconfig\n");
3481708Sstevel return (ENXIO);
3491708Sstevel }
3501708Sstevel
3511708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
3521708Sstevel tty = &(sgcn_state->sgcn_tty);
3531708Sstevel
3541708Sstevel tty->t_readq = q;
3551708Sstevel tty->t_writeq = WR(q);
3561708Sstevel
3571708Sstevel /* Link the RD and WR Q's */
3581708Sstevel
3591708Sstevel q->q_ptr = WR(q)->q_ptr = (caddr_t)sgcn_state;
3601708Sstevel sgcn_state->sgcn_readq = RD(q);
3611708Sstevel sgcn_state->sgcn_writeq = WR(q);
3621708Sstevel qprocson(q);
3631708Sstevel
3641708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
3651708Sstevel
3661708Sstevel /* initialize interrupt handler */
367*11311SSurya.Prakki@Sun.COM (void) iosram_reg_intr(SBBC_CONSOLE_IN,
3681708Sstevel (sbbc_intrfunc_t)sgcn_data_in_handler, NULL,
3691708Sstevel &sgcn_state->sgcn_sbbc_in_state,
3701708Sstevel &sgcn_state->sgcn_sbbc_in_lock);
371*11311SSurya.Prakki@Sun.COM (void) iosram_reg_intr(SBBC_CONSOLE_SPACE_OUT,
3721708Sstevel (sbbc_intrfunc_t)sgcn_space_2_out_handler, NULL,
3731708Sstevel &sgcn_state->sgcn_sbbc_outspace_state,
3741708Sstevel &sgcn_state->sgcn_sbbc_outspace_lock);
375*11311SSurya.Prakki@Sun.COM (void) iosram_reg_intr(SBBC_CONSOLE_BRK,
3761708Sstevel (sbbc_intrfunc_t)sgcn_break_handler, NULL,
3771708Sstevel &sgcn_state->sgcn_sbbc_brk_state,
3781708Sstevel &sgcn_state->sgcn_sbbc_brk_lock);
3791708Sstevel
3801708Sstevel return (DDI_SUCCESS);
3811708Sstevel }
3821708Sstevel
3831708Sstevel /* ARGSUSED */
3841708Sstevel static int
sgcn_close(queue_t * q,int flag,cred_t * credp)3851708Sstevel sgcn_close(queue_t *q, int flag, cred_t *credp)
3861708Sstevel {
3871708Sstevel int ret;
3881708Sstevel
3891708Sstevel ASSERT(sgcn_state == q->q_ptr);
3901708Sstevel
3911708Sstevel if (sgcn_state->sgcn_wbufcid != 0) {
3921708Sstevel unbufcall(sgcn_state->sgcn_wbufcid);
3931708Sstevel }
3941708Sstevel
3951708Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_BRK);
3961708Sstevel ASSERT(ret == 0);
3971708Sstevel
3981708Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_SPACE_OUT);
3991708Sstevel ASSERT(ret == 0);
4001708Sstevel
4011708Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_IN);
4021708Sstevel ASSERT(ret == 0);
4031708Sstevel
4041708Sstevel ttycommon_close(&sgcn_state->sgcn_tty);
4051708Sstevel
4061708Sstevel qprocsoff(q);
4071708Sstevel q->q_ptr = WR(q)->q_ptr = NULL;
4081708Sstevel sgcn_state->sgcn_readq = NULL;
4091708Sstevel sgcn_state->sgcn_writeq = NULL;
4101708Sstevel
4111708Sstevel return (DDI_SUCCESS);
4121708Sstevel }
4131708Sstevel
4141708Sstevel /*
4151708Sstevel * Put procedure for write queue.
4161708Sstevel * Respond to M_IOCTL, M_DATA and M_FLUSH messages here;
4171708Sstevel * It put's the data onto internal sgcn_output_q.
4181708Sstevel */
4191708Sstevel static int
sgcn_wput(queue_t * q,mblk_t * mp)4201708Sstevel sgcn_wput(queue_t *q, mblk_t *mp)
4211708Sstevel {
4221708Sstevel
4231708Sstevel #ifdef SGCN_DEBUG
4241708Sstevel struct iocblk *iocp;
4251708Sstevel int i;
4261708Sstevel #endif
4271708Sstevel
4281708Sstevel ASSERT(sgcn_state == q->q_ptr);
4291708Sstevel
4301708Sstevel if (!mp->b_datap) {
4311708Sstevel cmn_err(CE_PANIC, "sgcn_wput(): null datap");
4321708Sstevel }
4331708Sstevel
4341708Sstevel #ifdef SGCN_DEBUG
4351708Sstevel prom_printf("sgcn_wput(): SGCN wput q=%X mp=%X rd=%X wr=%X type=%X\n",
4367656SSherry.Moore@Sun.COM q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type);
4371708Sstevel #endif
4381708Sstevel
4391708Sstevel switch (mp->b_datap->db_type) {
4401708Sstevel case M_IOCTL:
4411708Sstevel case M_CTL:
4421708Sstevel #ifdef SGCN_DEBUG
4431708Sstevel iocp = (struct iocblk *)mp->b_rptr;
4441708Sstevel prom_printf("sgcn_wput(): M_IOCTL cmd=%X TIOC=%X\n",
4457656SSherry.Moore@Sun.COM iocp->ioc_cmd, TIOC);
4461708Sstevel #endif
4471708Sstevel switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
4481708Sstevel case TCSETSW:
4491708Sstevel case TCSETSF:
4501708Sstevel case TCSETAW:
4511708Sstevel case TCSETAF:
4521708Sstevel case TCSBRK:
4531708Sstevel /*
4541708Sstevel * The change do not take effect until all
4551708Sstevel * output queued before them is drained.
4561708Sstevel * Put this message on the queue, so that
4571708Sstevel * "sgcn_start" will see it when it's done
4581708Sstevel * with the output before it. Poke the start
4591708Sstevel * routine, just in case.
4601708Sstevel */
461*11311SSurya.Prakki@Sun.COM (void) putq(q, mp);
4621708Sstevel sgcn_start();
4631708Sstevel break;
4641708Sstevel default:
4651708Sstevel sgcn_ioctl(q, mp);
4661708Sstevel }
4671708Sstevel break;
4681708Sstevel
4691708Sstevel case M_FLUSH:
4701708Sstevel if (*mp->b_rptr & FLUSHW) {
4711708Sstevel flushq(q, FLUSHDATA);
4721708Sstevel *mp->b_rptr &= ~FLUSHW;
4731708Sstevel }
4741708Sstevel if (*mp->b_rptr & FLUSHR) {
4751708Sstevel flushq(RD(q), FLUSHDATA);
4761708Sstevel qreply(q, mp);
4771708Sstevel } else {
4781708Sstevel freemsg(mp);
4791708Sstevel }
4801708Sstevel break;
4811708Sstevel
4821708Sstevel case M_STOP:
4831708Sstevel sgcn_stopped = TRUE;
4841708Sstevel freemsg(mp);
4851708Sstevel break;
4861708Sstevel
4871708Sstevel case M_START:
4881708Sstevel sgcn_stopped = FALSE;
4891708Sstevel freemsg(mp);
4901708Sstevel qenable(q); /* Start up delayed messages */
4911708Sstevel break;
4921708Sstevel
4931708Sstevel case M_DATA:
4941708Sstevel /*
4951708Sstevel * Queue the message up to be transmitted,
4961708Sstevel * and poke the start routine.
4971708Sstevel */
4981708Sstevel #ifdef SGCN_DEBUG
4991708Sstevel if (mp->b_rptr < mp->b_wptr) {
5001708Sstevel prom_printf("sgcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n",
5017656SSherry.Moore@Sun.COM q, mp, mp->b_rptr, mp->b_wptr);
5021708Sstevel prom_printf("sgcn_wput(): [[[[[");
5031708Sstevel for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) {
5041708Sstevel prom_printf("%c", *(mp->b_rptr+i));
5051708Sstevel }
5061708Sstevel prom_printf("]]]]]\n");
5071708Sstevel }
5081708Sstevel #endif /* SGCN_DEBUG */
5091708Sstevel (void) putq(q, mp);
5101708Sstevel sgcn_start();
5111708Sstevel break;
5121708Sstevel
5131708Sstevel default:
5141708Sstevel freemsg(mp);
5151708Sstevel }
5161708Sstevel
5171708Sstevel return (0);
5181708Sstevel }
5191708Sstevel
5201708Sstevel /*
5211708Sstevel * Process an "ioctl" message sent down to us.
5221708Sstevel */
5231708Sstevel static void
sgcn_ioctl(queue_t * q,mblk_t * mp)5241708Sstevel sgcn_ioctl(queue_t *q, mblk_t *mp)
5251708Sstevel {
5261708Sstevel struct iocblk *iocp;
5271708Sstevel tty_common_t *tty;
5281708Sstevel mblk_t *datamp;
5291708Sstevel int data_size;
5301708Sstevel int error = 0;
5311708Sstevel
5321708Sstevel #ifdef SGCN_DEBUG
5331708Sstevel prom_printf("sgcn_ioctl(): q=%X mp=%X\n", q, mp);
5341708Sstevel #endif
5351708Sstevel iocp = (struct iocblk *)mp->b_rptr;
5361708Sstevel tty = &(sgcn_state->sgcn_tty);
5371708Sstevel
5381708Sstevel if (tty->t_iocpending != NULL) {
5391708Sstevel freemsg(tty->t_iocpending);
5401708Sstevel tty->t_iocpending = NULL;
5411708Sstevel }
5421708Sstevel data_size = ttycommon_ioctl(tty, q, mp, &error);
5431708Sstevel if (data_size != 0) {
5441708Sstevel if (sgcn_state->sgcn_wbufcid)
5451708Sstevel unbufcall(sgcn_state->sgcn_wbufcid);
5461708Sstevel /* call sgcn_reioctl() */
5471708Sstevel sgcn_state->sgcn_wbufcid =
5487656SSherry.Moore@Sun.COM bufcall(data_size, BPRI_HI, sgcn_reioctl, sgcn_state);
5491708Sstevel return;
5501708Sstevel }
5511708Sstevel
5521708Sstevel if (error < 0) {
5531708Sstevel iocp = (struct iocblk *)mp->b_rptr;
5541708Sstevel /*
5551708Sstevel * "ttycommon_ioctl" didn't do anything; we process it here.
5561708Sstevel */
5571708Sstevel error = 0;
5581708Sstevel switch (iocp->ioc_cmd) {
5591708Sstevel case TCSBRK:
5601708Sstevel case TIOCSBRK:
5611708Sstevel case TIOCCBRK:
5621708Sstevel case TIOCMSET:
5631708Sstevel case TIOCMBIS:
5641708Sstevel case TIOCMBIC:
5651708Sstevel if (iocp->ioc_count != TRANSPARENT)
5661708Sstevel mioc2ack(mp, NULL, 0, 0);
5671708Sstevel else
5681708Sstevel mcopyin(mp, NULL, sizeof (int), NULL);
5691708Sstevel break;
5701708Sstevel
5711708Sstevel case TIOCMGET:
5721708Sstevel datamp = allocb(sizeof (int), BPRI_MED);
5731708Sstevel if (datamp == NULL) {
5741708Sstevel error = EAGAIN;
5751708Sstevel break;
5761708Sstevel }
5771708Sstevel
5781708Sstevel *(int *)datamp->b_rptr = 0;
5791708Sstevel
5801708Sstevel if (iocp->ioc_count != TRANSPARENT)
5811708Sstevel mioc2ack(mp, datamp, sizeof (int), 0);
5821708Sstevel else
5831708Sstevel mcopyout(mp, NULL, sizeof (int), NULL, datamp);
5841708Sstevel break;
5851708Sstevel
5861708Sstevel default:
5871708Sstevel error = EINVAL;
5881708Sstevel break;
5891708Sstevel }
5901708Sstevel }
5911708Sstevel if (error != 0) {
5921708Sstevel iocp->ioc_count = 0;
5931708Sstevel iocp->ioc_error = error;
5941708Sstevel mp->b_datap->db_type = M_IOCNAK;
5951708Sstevel }
5961708Sstevel qreply(q, mp);
5971708Sstevel }
5981708Sstevel
5991708Sstevel static void
sgcn_reioctl(void * unit)6001708Sstevel sgcn_reioctl(void *unit)
6011708Sstevel {
6021708Sstevel queue_t *q;
6031708Sstevel mblk_t *mp;
6041708Sstevel sgcn_t *sgcnp = (sgcn_t *)unit;
6051708Sstevel
6061708Sstevel if (!sgcnp->sgcn_wbufcid) {
6071708Sstevel return;
6081708Sstevel }
6091708Sstevel sgcnp->sgcn_wbufcid = 0;
6101708Sstevel if ((q = sgcnp->sgcn_tty.t_writeq) == NULL) {
6111708Sstevel return;
6121708Sstevel }
6131708Sstevel
6141708Sstevel if ((mp = sgcnp->sgcn_tty.t_iocpending) != NULL) {
6151708Sstevel sgcnp->sgcn_tty.t_iocpending = NULL;
6161708Sstevel sgcn_ioctl(q, mp);
6171708Sstevel }
6181708Sstevel }
6191708Sstevel
6201708Sstevel static void
sgcn_start()6211708Sstevel sgcn_start()
6221708Sstevel {
6231708Sstevel
6241708Sstevel queue_t *q;
6251708Sstevel mblk_t *mp;
6261708Sstevel int retval;
6271708Sstevel
6281708Sstevel /*
6291708Sstevel * read stream queue and remove data from the queue and
6301708Sstevel * transmit them if possible
6311708Sstevel */
6321708Sstevel q = sgcn_state->sgcn_writeq;
6331708Sstevel ASSERT(q != NULL);
6341708Sstevel while (mp = getq(q)) {
6351708Sstevel switch (mp->b_datap->db_type) {
6361708Sstevel case M_IOCTL:
6371708Sstevel /*
6381708Sstevel * These are those IOCTLs queued up
6391708Sstevel * do it now
6401708Sstevel */
6411708Sstevel sgcn_ioctl(q, mp);
6421708Sstevel continue;
6431708Sstevel default:
6441708Sstevel /*
6451708Sstevel * M_DATA
6461708Sstevel * Copy it from stream queue buffer to
6471708Sstevel * sgcn buffer
6481708Sstevel */
6491708Sstevel retval = sgcn_transmit(q, mp);
6501708Sstevel
6511708Sstevel if (retval == EBUSY) {
6521708Sstevel /*
6531708Sstevel * Console output buffer is full for
6541708Sstevel * sgcn_timeout_period seconds, assume
6551708Sstevel * SC is dead, drop all console output
6561708Sstevel * data from stream queue.
6571708Sstevel */
6581708Sstevel if (sgcn_state->sgcn_sc_active <
6591708Sstevel gethrestime_sec() - sgcn_timeout_period)
6601708Sstevel sgcn_flush();
6611708Sstevel return;
6621708Sstevel } else if (retval == EAGAIN) {
6631708Sstevel /*
6641708Sstevel * Console output just became full
6651708Sstevel * return
6661708Sstevel */
6671708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
6681708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
6691708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
6701708Sstevel return;
6711708Sstevel } else {
6721708Sstevel /* send more console output */
6731708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
6741708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
6751708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
6761708Sstevel }
6771708Sstevel } /* switch */
6781708Sstevel }
6791708Sstevel
6801708Sstevel }
6811708Sstevel
6821708Sstevel static int
sgcn_transmit(queue_t * q,mblk_t * mp)6831708Sstevel sgcn_transmit(queue_t *q, mblk_t *mp)
6841708Sstevel {
6851708Sstevel caddr_t buf;
6861708Sstevel mblk_t *bp;
6871708Sstevel int len, oldlen;
6881708Sstevel
6891708Sstevel #ifdef SGCN_DEBUG
6901708Sstevel prom_printf("sgcn_transmit(): q=%X mp=%X\n", q, mp);
6911708Sstevel #endif
6921708Sstevel do {
6931708Sstevel bp = mp;
6941708Sstevel oldlen = len = bp->b_wptr - bp->b_rptr;
6951708Sstevel buf = (caddr_t)bp->b_rptr;
6961708Sstevel len = CONSOLE_WRITE(buf, len);
6971708Sstevel if (len > 0)
698*11311SSurya.Prakki@Sun.COM (void) iosram_send_intr(SBBC_CONSOLE_OUT);
6991708Sstevel if (len >= 0 && len < oldlen) {
7001708Sstevel /* IOSRAM is full, we are not done with mp yet */
7011708Sstevel bp->b_rptr += len;
7021708Sstevel (void) putbq(q, mp);
7031708Sstevel if (len)
7041708Sstevel return (EAGAIN);
7051708Sstevel else
7061708Sstevel return (EBUSY);
7071708Sstevel }
7081708Sstevel mp = bp->b_cont;
7091708Sstevel freeb(bp);
7101708Sstevel } while (mp);
7111708Sstevel
7121708Sstevel return (0);
7131708Sstevel }
7141708Sstevel
7151708Sstevel /*
7161708Sstevel * called when SC first establishes console connection
7171708Sstevel * drop all the data on the output queue
7181708Sstevel */
7191708Sstevel static void
sgcn_flush()7201708Sstevel sgcn_flush()
7211708Sstevel {
7221708Sstevel queue_t *q;
7231708Sstevel mblk_t *mp;
7241708Sstevel
7251708Sstevel q = sgcn_state->sgcn_writeq;
7261708Sstevel
7271708Sstevel prom_printf("sgcn_flush(): WARNING console output is dropped "
7287656SSherry.Moore@Sun.COM "time=%lX\n", gethrestime_sec());
7291708Sstevel while (mp = getq(q)) {
7301708Sstevel freemsg(mp);
7311708Sstevel }
7321708Sstevel
7331708Sstevel }
7341708Sstevel
7351708Sstevel uint64_t sgcn_input_dropped;
7361708Sstevel
7371708Sstevel /*
7381708Sstevel * Interrupt handlers
7391708Sstevel * All handlers register with SBBC driver and must follow SBBC interrupt
7401708Sstevel * delivery conventions.
7411708Sstevel */
7421708Sstevel /*
7431708Sstevel * SC sends an interrupt when new data comes in
7441708Sstevel */
7451708Sstevel /* ARGSUSED */
7461708Sstevel void
sgcn_data_in_handler(caddr_t arg)7471708Sstevel sgcn_data_in_handler(caddr_t arg)
7481708Sstevel {
7491708Sstevel caddr_t buf = sgcn_state->sgcn_inbuf;
7501708Sstevel int i, len;
7511708Sstevel mblk_t *mp;
7521708Sstevel
7531708Sstevel /*
7541708Sstevel * change interrupt state so that SBBC won't trigger
7551708Sstevel * another one.
7561708Sstevel */
7571708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_in_lock);
7581708Sstevel sgcn_state->sgcn_sbbc_in_state = SBBC_INTR_RUNNING;
7591708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock);
7601708Sstevel
7611708Sstevel /* update sgcn_state for SC activity information */
7621708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
7631708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
7641708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
7651708Sstevel
7661708Sstevel /* enter our perimeter */
7671708Sstevel entersq(sgcn_state->sgcn_readq->q_syncq, SQ_CALLBACK);
7681708Sstevel
7691708Sstevel for (;;) {
7701708Sstevel
7711708Sstevel /* read from console input IOSRAM */
7721708Sstevel len = CONSOLE_READ(buf, sgcn_state->sgcn_inbuf_size);
7731708Sstevel
7741708Sstevel if (len <= 0) {
7751708Sstevel
7761708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_in_lock);
7771708Sstevel
7781708Sstevel len = CONSOLE_READ(buf, sgcn_state->sgcn_inbuf_size);
7791708Sstevel
7801708Sstevel if (len <= 0) {
7811708Sstevel sgcn_state->sgcn_sbbc_in_state = SBBC_INTR_IDLE;
7821708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock);
7831708Sstevel
7841708Sstevel /* leave our perimeter */
7851708Sstevel leavesq(sgcn_state->sgcn_readq->q_syncq,
7867656SSherry.Moore@Sun.COM SQ_CALLBACK);
7871708Sstevel return;
7881708Sstevel } else {
7891708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock);
7901708Sstevel }
7911708Sstevel
7921708Sstevel }
7931708Sstevel
794*11311SSurya.Prakki@Sun.COM (void) iosram_send_intr(SBBC_CONSOLE_SPACE_IN);
7951708Sstevel
7961708Sstevel if (abort_enable == KIOCABORTALTERNATE) {
7971708Sstevel for (i = 0; i < len; i ++) {
7981708Sstevel if (abort_charseq_recognize(buf[i]))
7991708Sstevel abort_sequence_enter((char *)NULL);
8001708Sstevel }
8011708Sstevel }
8021708Sstevel
8031708Sstevel /* put console input onto stream */
8041708Sstevel if (sgcn_state->sgcn_readq) {
8051708Sstevel if ((mp = allocb(len, BPRI_MED)) == (mblk_t *)NULL) {
8061708Sstevel sgcn_input_dropped += len;
8071708Sstevel cmn_err(CE_WARN,
8081708Sstevel "sgcn_data_in_handler(): allocb failed"
8091708Sstevel " (console input dropped.)");
8101708Sstevel } else {
8111708Sstevel bcopy(buf, mp->b_wptr, len);
8121708Sstevel mp->b_wptr += len;
8131708Sstevel putnext(sgcn_state->sgcn_readq, mp);
8141708Sstevel }
8151708Sstevel }
8161708Sstevel }
8171708Sstevel
8181708Sstevel }
8191708Sstevel
8201708Sstevel /*
8211708Sstevel * SC sends an interrupt when it takes output data
8221708Sstevel * from a full IOSRAM
8231708Sstevel */
8241708Sstevel /* ARGSUSED */
8251708Sstevel void
sgcn_space_2_out_handler(caddr_t arg)8261708Sstevel sgcn_space_2_out_handler(caddr_t arg)
8271708Sstevel {
8281708Sstevel /*
8291708Sstevel * change interrupt state so that SBBC won't trigger
8301708Sstevel * another one.
8311708Sstevel */
8321708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_outspace_lock);
8331708Sstevel sgcn_state->sgcn_sbbc_outspace_state = SBBC_INTR_RUNNING;
8341708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_outspace_lock);
8351708Sstevel
8361708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
8371708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
8381708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
8391708Sstevel
8401708Sstevel if (sgcn_state->sgcn_writeq != NULL)
8411708Sstevel qenable(sgcn_state->sgcn_writeq);
8421708Sstevel
8431708Sstevel /* restore interrupt state */
8441708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_outspace_lock);
8451708Sstevel sgcn_state->sgcn_sbbc_outspace_state = SBBC_INTR_IDLE;
8461708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_outspace_lock);
8471708Sstevel }
8481708Sstevel
8491708Sstevel /*
8501708Sstevel * SC sends an interrupt when it detects BREAK sequence
8511708Sstevel */
8521708Sstevel /* ARGSUSED */
8531708Sstevel void
sgcn_break_handler(caddr_t arg)8541708Sstevel sgcn_break_handler(caddr_t arg)
8551708Sstevel {
8561708Sstevel /*
8571708Sstevel * change interrupt state so that SBBC won't trigger
8581708Sstevel * another one.
8591708Sstevel */
8601708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_brk_lock);
8611708Sstevel sgcn_state->sgcn_sbbc_brk_state = SBBC_INTR_RUNNING;
8621708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_brk_lock);
8631708Sstevel
8641708Sstevel if (abort_enable != KIOCABORTALTERNATE)
8651708Sstevel abort_sequence_enter((char *)NULL);
8661708Sstevel
8671708Sstevel /* restore interrupt state */
8681708Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_brk_lock);
8691708Sstevel sgcn_state->sgcn_sbbc_brk_state = SBBC_INTR_IDLE;
8701708Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_brk_lock);
8711708Sstevel }
8721708Sstevel
8731708Sstevel /*
8741708Sstevel * reporting errors in console driver sgcn.
8751708Sstevel * since we can not trust console driver at this time, we need to
8761708Sstevel * log errors in other system logs
8771708Sstevel * error codes:
8781708Sstevel * EIO - iosram interface failed
8791708Sstevel * EPROTO - IOSRAM is corrupted
8801708Sstevel * EINVAL - invalid argument
8811708Sstevel */
8821708Sstevel #define SGCN_MAX_ERROR 100
8831708Sstevel static void
sgcn_log_error(int when,int what)8841708Sstevel sgcn_log_error(int when, int what)
8851708Sstevel {
8861708Sstevel char error_msg[256], error_code[256];
8871708Sstevel static uint_t error_counter = 0;
8881708Sstevel
8891708Sstevel error_counter ++;
8901708Sstevel
8911708Sstevel if (error_counter > SGCN_MAX_ERROR) {
8921708Sstevel error_counter = 0;
893*11311SSurya.Prakki@Sun.COM (void) strcpy(error_msg, "!Too many sgcn errors");
8941708Sstevel } else {
8951708Sstevel (void) sprintf(error_code, "Error %d", what);
8961708Sstevel
8971708Sstevel (void) sprintf(error_msg, "!%s at %s",
8981708Sstevel (what == EIO) ? "IOSRAM interface failed" :
8991708Sstevel (what == EPROTO) ? "IOSRAM corrupted" :
9001708Sstevel (what == EINVAL) ? "Invalid argument" :
9011708Sstevel error_code,
9021708Sstevel (when == RW_CONSOLE_READ) ? "console input" :
9031708Sstevel (when == RW_CONSOLE_WRITE) ? "console output, dropped" :
9041708Sstevel "console I/O");
9051708Sstevel }
9061708Sstevel
9071708Sstevel cmn_err(CE_WARN, error_msg);
9081708Sstevel }
9091708Sstevel
9101708Sstevel static int
sgcn_read_header(int rw,cnsram_header * header)9111708Sstevel sgcn_read_header(int rw, cnsram_header *header)
9121708Sstevel {
9131708Sstevel int rv;
9141708Sstevel
9151708Sstevel /* check IOSRAM contents and read pointers */
9161708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 0, (caddr_t)header,
9177656SSherry.Moore@Sun.COM sizeof (cnsram_header));
9181708Sstevel if (rv != 0) {
9191708Sstevel return (-1);
9201708Sstevel }
9211708Sstevel
9221708Sstevel /*
9231708Sstevel * Since the header is read in a byte-by-byte fashion
9241708Sstevel * using ddi_rep_get8, we need to re-read the producer
9251708Sstevel * or consumer pointer as integer in case it has changed
9261708Sstevel * after part of the previous value has been read.
9271708Sstevel */
9281708Sstevel if (rw == RW_CONSOLE_READ) {
9291708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY,
9307656SSherry.Moore@Sun.COM OFFSETOF((*header), cnsram_in_wrptr),
9317656SSherry.Moore@Sun.COM POINTER((*header), cnsram_in_wrptr),
9327656SSherry.Moore@Sun.COM sizeof (header->cnsram_in_wrptr));
9331708Sstevel } else if (rw == RW_CONSOLE_WRITE) {
9341708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY,
9357656SSherry.Moore@Sun.COM OFFSETOF((*header), cnsram_out_rdptr),
9367656SSherry.Moore@Sun.COM POINTER((*header), cnsram_out_rdptr),
9377656SSherry.Moore@Sun.COM sizeof (header->cnsram_out_rdptr));
9381708Sstevel } else
9391708Sstevel rv = -1;
9401708Sstevel
9411708Sstevel return (rv);
9421708Sstevel }
9431708Sstevel
9441708Sstevel static int
sgcn_rw(int rw,caddr_t buf,int len)9451708Sstevel sgcn_rw(int rw, caddr_t buf, int len)
9461708Sstevel {
9471708Sstevel cnsram_header header;
9481708Sstevel int rv, size, nbytes;
9491708Sstevel
9501708Sstevel #ifdef SGCN_DEBUG
9511708Sstevel prom_printf("sgcn_rw() rw = %X buf = %p len = %d\n",
9527656SSherry.Moore@Sun.COM rw, buf, len);
9531708Sstevel #endif /* SGCN_DEBUG */
9541708Sstevel if (len == 0)
9551708Sstevel return (0);
9561708Sstevel
9571708Sstevel /* sanity check */
9581708Sstevel if (buf == NULL || len < 0) {
9591708Sstevel sgcn_log_error(rw, EINVAL);
9601708Sstevel return (-1);
9611708Sstevel }
9621708Sstevel
9631708Sstevel /* check IOSRAM contents and read pointers */
9641708Sstevel rv = sgcn_read_header(rw, &header);
9651708Sstevel if (rv != 0) {
9661708Sstevel sgcn_log_error(rw, EIO);
9671708Sstevel return (-1);
9681708Sstevel }
9691708Sstevel if (header.cnsram_magic != CNSRAM_MAGIC) {
9701708Sstevel sgcn_log_error(rw, EPROTO);
9711708Sstevel return (-1);
9721708Sstevel }
9731708Sstevel
9741708Sstevel if (rw == RW_CONSOLE_READ)
9751708Sstevel size = header.cnsram_in_end - header.cnsram_in_begin;
9761708Sstevel else if (rw == RW_CONSOLE_WRITE)
9771708Sstevel size = header.cnsram_out_end - header.cnsram_out_begin;
9781708Sstevel if (size < 0) {
9791708Sstevel sgcn_log_error(rw, EPROTO);
9801708Sstevel return (-1);
9811708Sstevel }
9821708Sstevel
9831708Sstevel if (rw == RW_CONSOLE_READ)
9841708Sstevel nbytes = circular_buffer_read(
9857656SSherry.Moore@Sun.COM header.cnsram_in_begin,
9867656SSherry.Moore@Sun.COM header.cnsram_in_end,
9877656SSherry.Moore@Sun.COM header.cnsram_in_rdptr,
9887656SSherry.Moore@Sun.COM header.cnsram_in_wrptr, buf, len);
9891708Sstevel else if (rw == RW_CONSOLE_WRITE)
9901708Sstevel nbytes = circular_buffer_write(
9917656SSherry.Moore@Sun.COM header.cnsram_out_begin,
9927656SSherry.Moore@Sun.COM header.cnsram_out_end,
9937656SSherry.Moore@Sun.COM header.cnsram_out_rdptr,
9947656SSherry.Moore@Sun.COM header.cnsram_out_wrptr, buf, len);
9951708Sstevel
9961708Sstevel /*
9971708Sstevel * error log was done in circular buffer routines,
9981708Sstevel * no need to call sgcn_log_error() here
9991708Sstevel */
10001708Sstevel if (nbytes < 0)
10011708Sstevel return (-1);
10021708Sstevel
10031708Sstevel if (nbytes == 0)
10041708Sstevel return (0);
10051708Sstevel
10061708Sstevel if (rw == RW_CONSOLE_READ) {
10071708Sstevel header.cnsram_in_rdptr =
10081708Sstevel (header.cnsram_in_rdptr - header.cnsram_in_begin
10097656SSherry.Moore@Sun.COM + nbytes)
10101708Sstevel % size + header.cnsram_in_begin;
10111708Sstevel rv = iosram_write(SBBC_CONSOLE_KEY,
10127656SSherry.Moore@Sun.COM OFFSETOF(header, cnsram_in_rdptr),
10137656SSherry.Moore@Sun.COM POINTER(header, cnsram_in_rdptr),
10147656SSherry.Moore@Sun.COM sizeof (header.cnsram_in_rdptr));
10151708Sstevel } else if (rw == RW_CONSOLE_WRITE) {
10161708Sstevel header.cnsram_out_wrptr =
10171708Sstevel (header.cnsram_out_wrptr - header.cnsram_out_begin
10187656SSherry.Moore@Sun.COM + nbytes)
10191708Sstevel % size + header.cnsram_out_begin;
10201708Sstevel rv = iosram_write(SBBC_CONSOLE_KEY,
10217656SSherry.Moore@Sun.COM OFFSETOF(header, cnsram_out_wrptr),
10227656SSherry.Moore@Sun.COM POINTER(header, cnsram_out_wrptr),
10237656SSherry.Moore@Sun.COM sizeof (header.cnsram_out_wrptr));
10241708Sstevel }
10251708Sstevel if (rv != 0) {
10261708Sstevel sgcn_log_error(rw, EIO);
10271708Sstevel return (-1);
10281708Sstevel }
10291708Sstevel
10301708Sstevel return (nbytes);
10311708Sstevel }
10321708Sstevel
10331708Sstevel /*
10341708Sstevel * Circular buffer interfaces
10351708Sstevel *
10361708Sstevel * See sgcn.h for circular buffer structure
10371708Sstevel *
10381708Sstevel * The circular buffer is empty when read ptr == write ptr
10391708Sstevel * and is full when read ptr is one ahead of write ptr
10401708Sstevel */
10411708Sstevel /*
10421708Sstevel * Write to circular buffer in IOSRAM
10431708Sstevel * input:
10441708Sstevel * buf buffer in main memory, contains data to be written
10451708Sstevel * len length of data in bytes
10461708Sstevel * begin, end, rd, wr buffer pointers
10471708Sstevel * return value:
10481708Sstevel * actual bytes written.
10491708Sstevel */
10501708Sstevel static int
circular_buffer_write(int begin,int end,int rd,int wr,caddr_t buf,int len)10511708Sstevel circular_buffer_write(int begin, int end, int rd, int wr, caddr_t buf, int len)
10521708Sstevel {
10531708Sstevel int size, space, space_at_end;
10541708Sstevel int rv = 0;
10551708Sstevel
10561708Sstevel size = end - begin;
10571708Sstevel if (size <= 0) {
10581708Sstevel rv = EINVAL;
10591708Sstevel goto out;
10601708Sstevel }
10611708Sstevel
10621708Sstevel if ((len = ((len >= size) ? (size-1) : len)) == 0)
10631708Sstevel return (0); /* The buffer's full, so just return 0 now. */
10641708Sstevel
10651708Sstevel space = (rd - wr + size - 1) % size;
10661708Sstevel len = min(len, space);
10671708Sstevel space_at_end = end - wr;
10681708Sstevel
10691708Sstevel if (rd > wr || rd <= wr && space_at_end >= len) { /* one piece */
10701708Sstevel /* write console data */
10711708Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, wr, buf, len);
10721708Sstevel if (rv != 0) goto out;
10731708Sstevel } else { /* break into two pieces because of circular buffer */
10741708Sstevel /* write console data */
10751708Sstevel if (space_at_end) {
10761708Sstevel rv = iosram_write(SBBC_CONSOLE_KEY,
10771708Sstevel wr, buf, space_at_end);
10781708Sstevel if (rv != 0) goto out;
10791708Sstevel }
10801708Sstevel if (len - space_at_end) {
10811708Sstevel rv = iosram_write(SBBC_CONSOLE_KEY,
10821708Sstevel begin, buf+space_at_end, len-space_at_end);
10831708Sstevel if (rv != 0) goto out;
10841708Sstevel }
10851708Sstevel }
10861708Sstevel return (len);
10871708Sstevel out:
10881708Sstevel sgcn_log_error(RW_CONSOLE_WRITE, rv);
10891708Sstevel return (-1);
10901708Sstevel }
10911708Sstevel
10921708Sstevel /*
10931708Sstevel * Read from circular buffer in IOSRAM
10941708Sstevel * input:
10951708Sstevel * buf preallocated buffer in memory
10961708Sstevel * len size of buf
10971708Sstevel * begin, end, rd, wr buffer pointers
10981708Sstevel * return value:
10991708Sstevel * actual bytes read
11001708Sstevel */
11011708Sstevel /* ARGSUSED */
11021708Sstevel static int
circular_buffer_read(int begin,int end,int rd,int wr,caddr_t buf,int len)11031708Sstevel circular_buffer_read(int begin, int end, int rd, int wr, caddr_t buf, int len)
11041708Sstevel {
11051708Sstevel int size, nbytes, nbytes_at_end;
11061708Sstevel int rv = 0;
11071708Sstevel
11081708Sstevel size = end - begin;
11091708Sstevel if (size <= 0) {
11101708Sstevel rv = EINVAL;
11111708Sstevel goto out;
11121708Sstevel }
11131708Sstevel nbytes = (wr - rd + size) % size;
11141708Sstevel
11151708Sstevel nbytes = min(nbytes, len);
11161708Sstevel
11171708Sstevel if (wr > rd) { /* one piece */
11181708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, rd, buf, nbytes);
11191708Sstevel if (rv != 0) goto out;
11201708Sstevel } else { /* break into two pieces because of circular buffer */
11211708Sstevel nbytes_at_end = min(nbytes, end - rd);
11221708Sstevel /* read console data */
11231708Sstevel if (nbytes_at_end) {
11241708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY,
11251708Sstevel rd, buf, nbytes_at_end);
11261708Sstevel if (rv != 0) goto out;
11271708Sstevel }
11281708Sstevel if (nbytes-nbytes_at_end) {
11291708Sstevel rv = iosram_read(SBBC_CONSOLE_KEY,
11301708Sstevel begin, buf+nbytes_at_end, nbytes-nbytes_at_end);
11311708Sstevel if (rv != 0) goto out;
11321708Sstevel }
11331708Sstevel }
11341708Sstevel return (nbytes);
11351708Sstevel out:
11361708Sstevel sgcn_log_error(RW_CONSOLE_READ, rv);
11371708Sstevel return (-1);
11381708Sstevel }
11391708Sstevel
11401708Sstevel /*
11411708Sstevel * Check for abort character sequence, copied from zs_async.c
11421708Sstevel */
11431708Sstevel #define CNTRL(c) ((c)&037)
11441708Sstevel
11451708Sstevel static boolean_t
abort_charseq_recognize(uchar_t ch)11461708Sstevel abort_charseq_recognize(uchar_t ch)
11471708Sstevel {
11481708Sstevel static int state = 0;
11491708Sstevel static char sequence[] = { '\r', '~', CNTRL('b') };
11501708Sstevel
11511708Sstevel if (ch == sequence[state]) {
11521708Sstevel if (++state >= sizeof (sequence)) {
11531708Sstevel state = 0;
11541708Sstevel return (B_TRUE);
11551708Sstevel }
11561708Sstevel } else {
11571708Sstevel state = (ch == sequence[0]) ? 1 : 0;
11581708Sstevel }
11591708Sstevel return (B_FALSE);
11601708Sstevel }
11611708Sstevel
11621708Sstevel static void
sg_abort_seq_handler(char * msg)11631708Sstevel sg_abort_seq_handler(char *msg)
11641708Sstevel {
11651708Sstevel char key_switch;
11661708Sstevel int rv;
11671708Sstevel
11681708Sstevel /* read virtual keyswitch position from IOSRAM */
11691708Sstevel rv = iosram_read(SBBC_KEYSWITCH_KEY, 0, &key_switch, 1);
11701708Sstevel if (rv != 0) {
11711708Sstevel /* default to not secure if read failed */
11721708Sstevel cmn_err(CE_NOTE, "!Read keyswitch failed (%d)", rv);
11731708Sstevel key_switch = 0;
11741708Sstevel }
11751708Sstevel if (key_switch & SG_KEYSWITCH_POSN_SECURE) {
11761708Sstevel cmn_err(CE_NOTE, "!Keyswitch is in secure mode");
11771708Sstevel } else {
11781708Sstevel debug_enter(msg);
11791708Sstevel }
11801708Sstevel }
11811708Sstevel
11821708Sstevel static int
sgcn_rsrv(queue_t * q)11831708Sstevel sgcn_rsrv(queue_t *q)
11841708Sstevel {
11851708Sstevel mblk_t *mp;
11861708Sstevel
11871708Sstevel if (sgcn_stopped == TRUE) {
11881708Sstevel return (0);
11891708Sstevel }
11901708Sstevel
11911708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
11921708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
11931708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
11941708Sstevel
11951708Sstevel while ((mp = getq(q)) != NULL) {
11961708Sstevel if (canputnext(q)) {
11971708Sstevel putnext(q, mp);
11981708Sstevel } else if (mp->b_datap->db_type >= QPCTL) {
1199*11311SSurya.Prakki@Sun.COM (void) putbq(q, mp);
12001708Sstevel }
12011708Sstevel }
12021708Sstevel
12031708Sstevel return (0);
12041708Sstevel }
12051708Sstevel
12061708Sstevel /* ARGSUSED */
12071708Sstevel static int
sgcn_wsrv(queue_t * q)12081708Sstevel sgcn_wsrv(queue_t *q)
12091708Sstevel {
12101708Sstevel if (sgcn_stopped == TRUE)
12111708Sstevel return (0);
12121708Sstevel
12131708Sstevel mutex_enter(&sgcn_state->sgcn_lock);
12141708Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec();
12151708Sstevel mutex_exit(&sgcn_state->sgcn_lock);
12161708Sstevel
12171708Sstevel if (sgcn_state->sgcn_writeq != NULL)
12181708Sstevel sgcn_start();
12191708Sstevel
12201708Sstevel return (0);
12211708Sstevel }
1222