1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License (the "License"). 6*03831d35Sstevel * You may not use this file except in compliance with the License. 7*03831d35Sstevel * 8*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 10*03831d35Sstevel * See the License for the specific language governing permissions 11*03831d35Sstevel * and limitations under the License. 12*03831d35Sstevel * 13*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*03831d35Sstevel * 19*03831d35Sstevel * CDDL HEADER END 20*03831d35Sstevel */ 21*03831d35Sstevel 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*03831d35Sstevel * Use is subject to license terms. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel /* 30*03831d35Sstevel * Serengeti console driver, see sys/sgcn.h for more information 31*03831d35Sstevel * This driver uses the QPAIR form of STREAMS Perimeters to serialize access 32*03831d35Sstevel * to the read and write STREAMS queues. 33*03831d35Sstevel */ 34*03831d35Sstevel 35*03831d35Sstevel #include <sys/errno.h> 36*03831d35Sstevel #include <sys/stat.h> 37*03831d35Sstevel #include <sys/kmem.h> 38*03831d35Sstevel #include <sys/conf.h> 39*03831d35Sstevel #include <sys/termios.h> 40*03831d35Sstevel #include <sys/modctl.h> 41*03831d35Sstevel #include <sys/kbio.h> 42*03831d35Sstevel #include <sys/stropts.h> 43*03831d35Sstevel #include <sys/stream.h> 44*03831d35Sstevel #include <sys/strsun.h> 45*03831d35Sstevel #include <sys/sysmacros.h> 46*03831d35Sstevel #include <sys/promif.h> 47*03831d35Sstevel #include <sys/prom_plat.h> 48*03831d35Sstevel #include <sys/sgsbbc.h> 49*03831d35Sstevel #include <sys/sgsbbc_iosram.h> 50*03831d35Sstevel #include <sys/sgcn.h> 51*03831d35Sstevel #include <sys/serengeti.h> 52*03831d35Sstevel #include <sys/ddi.h> 53*03831d35Sstevel #include <sys/sunddi.h> 54*03831d35Sstevel #include <sys/strsubr.h> 55*03831d35Sstevel 56*03831d35Sstevel /* 57*03831d35Sstevel * Here we define several macros for accessing console IOSRAM 58*03831d35Sstevel */ 59*03831d35Sstevel 60*03831d35Sstevel #define POINTER(base, field) ((caddr_t)&base.field) 61*03831d35Sstevel #define OFFSETOF(base, field) ((caddr_t)&base.field - (caddr_t)&base) 62*03831d35Sstevel 63*03831d35Sstevel #define RW_CONSOLE_READ 0xAAAA 64*03831d35Sstevel #define RW_CONSOLE_WRITE 0xBBBB 65*03831d35Sstevel 66*03831d35Sstevel #define CONSOLE_READ(buf, len) sgcn_rw(RW_CONSOLE_READ, buf, len) 67*03831d35Sstevel #define CONSOLE_WRITE(buf, len) sgcn_rw(RW_CONSOLE_WRITE, buf, len) 68*03831d35Sstevel 69*03831d35Sstevel #define SGCN_MI_IDNUM 0xABCD 70*03831d35Sstevel #define SGCN_MI_HIWAT 2048*2048 71*03831d35Sstevel #define SGCN_MI_LOWAT 128 72*03831d35Sstevel 73*03831d35Sstevel /* dev_ops and cb_ops for device driver */ 74*03831d35Sstevel static int sgcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 75*03831d35Sstevel static int sgcn_attach(dev_info_t *, ddi_attach_cmd_t); 76*03831d35Sstevel static int sgcn_detach(dev_info_t *, ddi_detach_cmd_t); 77*03831d35Sstevel static int sgcn_open(queue_t *, dev_t *, int, int, cred_t *); 78*03831d35Sstevel static int sgcn_close(queue_t *, int, cred_t *); 79*03831d35Sstevel static int sgcn_wput(queue_t *, mblk_t *); 80*03831d35Sstevel static int sgcn_wsrv(queue_t *); 81*03831d35Sstevel static int sgcn_rsrv(queue_t *); 82*03831d35Sstevel 83*03831d35Sstevel /* interrupt handlers */ 84*03831d35Sstevel static void sgcn_data_in_handler(caddr_t); 85*03831d35Sstevel static void sgcn_space_2_out_handler(caddr_t); 86*03831d35Sstevel static void sgcn_break_handler(caddr_t); 87*03831d35Sstevel 88*03831d35Sstevel /* other internal sgcn routines */ 89*03831d35Sstevel static void sgcn_ioctl(queue_t *, mblk_t *); 90*03831d35Sstevel static void sgcn_reioctl(void *); 91*03831d35Sstevel static void sgcn_start(void); 92*03831d35Sstevel static int sgcn_transmit(queue_t *, mblk_t *); 93*03831d35Sstevel static void sgcn_flush(void); 94*03831d35Sstevel static int sgcn_read_header(int, cnsram_header *); 95*03831d35Sstevel static int sgcn_rw(int, caddr_t, int); 96*03831d35Sstevel static void sgcn_log_error(int, int); 97*03831d35Sstevel 98*03831d35Sstevel /* circular buffer routines */ 99*03831d35Sstevel static int circular_buffer_write(int, int, int, int, caddr_t, int); 100*03831d35Sstevel static int circular_buffer_read(int, int, int, int, caddr_t, int); 101*03831d35Sstevel 102*03831d35Sstevel static boolean_t abort_charseq_recognize(uchar_t); 103*03831d35Sstevel static void sg_abort_seq_handler(char *); 104*03831d35Sstevel 105*03831d35Sstevel static sgcn_t *sgcn_state; 106*03831d35Sstevel static uchar_t sgcn_stopped = FALSE; 107*03831d35Sstevel static int sgcn_timeout_period = 20; /* time out in seconds */ 108*03831d35Sstevel 109*03831d35Sstevel /* streams structures */ 110*03831d35Sstevel static struct module_info minfo = { 111*03831d35Sstevel SGCN_MI_IDNUM, /* mi_idnum */ 112*03831d35Sstevel "sgcn", /* mi_idname */ 113*03831d35Sstevel 0, /* mi_minpsz */ 114*03831d35Sstevel INFPSZ, /* mi_maxpsz */ 115*03831d35Sstevel SGCN_MI_HIWAT, /* mi_hiwat */ 116*03831d35Sstevel SGCN_MI_LOWAT /* mi_lowat */ 117*03831d35Sstevel }; 118*03831d35Sstevel 119*03831d35Sstevel static struct qinit rinit = { 120*03831d35Sstevel putq, /* qi_putp */ 121*03831d35Sstevel sgcn_rsrv, /* qi_srvp */ 122*03831d35Sstevel sgcn_open, /* qi_qopen */ 123*03831d35Sstevel sgcn_close, /* qi_qclose */ 124*03831d35Sstevel NULL, /* qi_qadmin */ 125*03831d35Sstevel &minfo, /* qi_minfo */ 126*03831d35Sstevel NULL /* qi_mstat */ 127*03831d35Sstevel }; 128*03831d35Sstevel 129*03831d35Sstevel static struct qinit winit = { 130*03831d35Sstevel sgcn_wput, /* qi_putp */ 131*03831d35Sstevel sgcn_wsrv, /* qi_srvp */ 132*03831d35Sstevel sgcn_open, /* qi_qopen */ 133*03831d35Sstevel sgcn_close, /* qi_qclose */ 134*03831d35Sstevel NULL, /* qi_qadmin */ 135*03831d35Sstevel &minfo, /* qi_minfo */ 136*03831d35Sstevel NULL /* qi_mstat */ 137*03831d35Sstevel }; 138*03831d35Sstevel 139*03831d35Sstevel static struct streamtab sgcnstrinfo = { 140*03831d35Sstevel &rinit, 141*03831d35Sstevel &winit, 142*03831d35Sstevel NULL, 143*03831d35Sstevel NULL 144*03831d35Sstevel }; 145*03831d35Sstevel 146*03831d35Sstevel /* standard device driver structures */ 147*03831d35Sstevel static struct cb_ops sgcn_cb_ops = { 148*03831d35Sstevel nulldev, /* open() */ 149*03831d35Sstevel nulldev, /* close() */ 150*03831d35Sstevel nodev, /* strategy() */ 151*03831d35Sstevel nodev, /* print() */ 152*03831d35Sstevel nodev, /* dump() */ 153*03831d35Sstevel nodev, /* read() */ 154*03831d35Sstevel nodev, /* write() */ 155*03831d35Sstevel nodev, /* ioctl() */ 156*03831d35Sstevel nodev, /* devmap() */ 157*03831d35Sstevel nodev, /* mmap() */ 158*03831d35Sstevel nodev, /* segmap() */ 159*03831d35Sstevel nochpoll, /* poll() */ 160*03831d35Sstevel ddi_prop_op, /* prop_op() */ 161*03831d35Sstevel &sgcnstrinfo, /* cb_str */ 162*03831d35Sstevel D_MP | D_MTQPAIR /* cb_flag */ 163*03831d35Sstevel }; 164*03831d35Sstevel 165*03831d35Sstevel static struct dev_ops sgcn_ops = { 166*03831d35Sstevel DEVO_REV, 167*03831d35Sstevel 0, /* refcnt */ 168*03831d35Sstevel sgcn_getinfo, /* getinfo() */ 169*03831d35Sstevel nulldev, /* identify() */ 170*03831d35Sstevel nulldev, /* probe() */ 171*03831d35Sstevel sgcn_attach, /* attach() */ 172*03831d35Sstevel sgcn_detach, /* detach() */ 173*03831d35Sstevel nodev, /* reset() */ 174*03831d35Sstevel &sgcn_cb_ops, /* cb_ops */ 175*03831d35Sstevel (struct bus_ops *)NULL, /* bus_ops */ 176*03831d35Sstevel NULL /* power() */ 177*03831d35Sstevel }; 178*03831d35Sstevel 179*03831d35Sstevel static struct modldrv modldrv = { 180*03831d35Sstevel &mod_driverops, 181*03831d35Sstevel "Serengeti console driver v%I%", 182*03831d35Sstevel &sgcn_ops 183*03831d35Sstevel }; 184*03831d35Sstevel 185*03831d35Sstevel static struct modlinkage modlinkage = { 186*03831d35Sstevel MODREV_1, 187*03831d35Sstevel (void*)&modldrv, 188*03831d35Sstevel NULL 189*03831d35Sstevel }; 190*03831d35Sstevel 191*03831d35Sstevel 192*03831d35Sstevel /* driver configuration routines */ 193*03831d35Sstevel int 194*03831d35Sstevel _init(void) 195*03831d35Sstevel { 196*03831d35Sstevel int error; 197*03831d35Sstevel 198*03831d35Sstevel sgcn_state = kmem_zalloc(sizeof (sgcn_t), KM_SLEEP); 199*03831d35Sstevel 200*03831d35Sstevel error = mod_install(&modlinkage); 201*03831d35Sstevel 202*03831d35Sstevel if (error == 0) { 203*03831d35Sstevel mutex_init(&sgcn_state->sgcn_lock, NULL, MUTEX_DRIVER, NULL); 204*03831d35Sstevel } else { 205*03831d35Sstevel kmem_free(sgcn_state, sizeof (sgcn_t)); 206*03831d35Sstevel } 207*03831d35Sstevel 208*03831d35Sstevel return (error); 209*03831d35Sstevel } 210*03831d35Sstevel 211*03831d35Sstevel int 212*03831d35Sstevel _fini(void) 213*03831d35Sstevel { 214*03831d35Sstevel /* can't remove console driver */ 215*03831d35Sstevel return (EBUSY); 216*03831d35Sstevel } 217*03831d35Sstevel 218*03831d35Sstevel int 219*03831d35Sstevel _info(struct modinfo *modinfop) 220*03831d35Sstevel { 221*03831d35Sstevel return (mod_info(&modlinkage, modinfop)); 222*03831d35Sstevel } 223*03831d35Sstevel 224*03831d35Sstevel /* 225*03831d35Sstevel * sgcn_attach is called at startup time. 226*03831d35Sstevel * There is only once instance of this driver. 227*03831d35Sstevel */ 228*03831d35Sstevel static int 229*03831d35Sstevel sgcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 230*03831d35Sstevel { 231*03831d35Sstevel extern int ddi_create_internal_pathname( 232*03831d35Sstevel dev_info_t *, char *, int, minor_t); 233*03831d35Sstevel cnsram_header header; 234*03831d35Sstevel int rv; 235*03831d35Sstevel 236*03831d35Sstevel if (cmd != DDI_ATTACH) 237*03831d35Sstevel return (DDI_FAILURE); 238*03831d35Sstevel 239*03831d35Sstevel if (ddi_create_internal_pathname(dip, "sgcn", S_IFCHR, 0) 240*03831d35Sstevel != DDI_SUCCESS) 241*03831d35Sstevel return (DDI_FAILURE); 242*03831d35Sstevel 243*03831d35Sstevel /* prepare some data structures in soft state */ 244*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 245*03831d35Sstevel 246*03831d35Sstevel sgcn_state->sgcn_dip = dip; 247*03831d35Sstevel 248*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 249*03831d35Sstevel 250*03831d35Sstevel /* 251*03831d35Sstevel * We need to verify IOSRAM is intact at startup time. If by 252*03831d35Sstevel * any chance IOSRAM is corrupted, that means SC is not ready. 253*03831d35Sstevel * All we can do is stopping. 254*03831d35Sstevel */ 255*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 0, (caddr_t)&header, 256*03831d35Sstevel sizeof (cnsram_header)); 257*03831d35Sstevel if (rv != 0) 258*03831d35Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Reading from IOSRAM failed"); 259*03831d35Sstevel if (header.cnsram_magic != CNSRAM_MAGIC) 260*03831d35Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM console buffer"); 261*03831d35Sstevel if (!header.cnsram_in_end && !header.cnsram_in_begin) 262*03831d35Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM input buffer"); 263*03831d35Sstevel if (!header.cnsram_out_end && !header.cnsram_out_begin) 264*03831d35Sstevel cmn_err(CE_PANIC, "sgcn_attach(): Wrong IOSRAM output buffer"); 265*03831d35Sstevel /* 266*03831d35Sstevel * XXX need to add extra check for version no. 267*03831d35Sstevel */ 268*03831d35Sstevel 269*03831d35Sstevel /* Allocate console input buffer */ 270*03831d35Sstevel sgcn_state->sgcn_inbuf_size = 271*03831d35Sstevel header.cnsram_in_end - header.cnsram_in_begin; 272*03831d35Sstevel sgcn_state->sgcn_inbuf = 273*03831d35Sstevel kmem_alloc(sgcn_state->sgcn_inbuf_size, KM_SLEEP); 274*03831d35Sstevel #ifdef SGCN_DEBUG 275*03831d35Sstevel prom_printf("Allocated %d(0x%X) bytes for console\n", 276*03831d35Sstevel sgcn_state->sgcn_inbuf_size); 277*03831d35Sstevel #endif 278*03831d35Sstevel 279*03831d35Sstevel (void) prom_serengeti_set_console_input(SGCN_CLNT_STR); 280*03831d35Sstevel 281*03831d35Sstevel abort_seq_handler = sg_abort_seq_handler; 282*03831d35Sstevel 283*03831d35Sstevel #ifdef SGCN_DEBUG 284*03831d35Sstevel prom_printf("sgcn_attach(): SGCN driver attached\n"); 285*03831d35Sstevel #endif 286*03831d35Sstevel return (DDI_SUCCESS); 287*03831d35Sstevel 288*03831d35Sstevel } 289*03831d35Sstevel 290*03831d35Sstevel /* ARGSUSED */ 291*03831d35Sstevel static int 292*03831d35Sstevel sgcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 293*03831d35Sstevel { 294*03831d35Sstevel 295*03831d35Sstevel if (cmd == DDI_DETACH) 296*03831d35Sstevel return (DDI_FAILURE); 297*03831d35Sstevel 298*03831d35Sstevel #ifdef SGCN_DEBUG 299*03831d35Sstevel prom_printf("sgcn_detach(): SGCN driver detached\n"); 300*03831d35Sstevel #endif 301*03831d35Sstevel return (DDI_SUCCESS); 302*03831d35Sstevel } 303*03831d35Sstevel 304*03831d35Sstevel /* ARGSUSED */ 305*03831d35Sstevel static int 306*03831d35Sstevel sgcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 307*03831d35Sstevel { 308*03831d35Sstevel int error = DDI_FAILURE; 309*03831d35Sstevel 310*03831d35Sstevel switch (infocmd) { 311*03831d35Sstevel case DDI_INFO_DEVT2DEVINFO: 312*03831d35Sstevel if (sgcn_state) { 313*03831d35Sstevel *result = (void *) sgcn_state->sgcn_dip; 314*03831d35Sstevel error = DDI_SUCCESS; 315*03831d35Sstevel } 316*03831d35Sstevel break; 317*03831d35Sstevel 318*03831d35Sstevel case DDI_INFO_DEVT2INSTANCE: 319*03831d35Sstevel if (getminor((dev_t)arg) == 0) { 320*03831d35Sstevel *result = (void *)0; 321*03831d35Sstevel error = DDI_SUCCESS; 322*03831d35Sstevel } 323*03831d35Sstevel break; 324*03831d35Sstevel } 325*03831d35Sstevel 326*03831d35Sstevel return (error); 327*03831d35Sstevel } 328*03831d35Sstevel 329*03831d35Sstevel /* streams open & close */ 330*03831d35Sstevel /* ARGSUSED */ 331*03831d35Sstevel static int 332*03831d35Sstevel sgcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 333*03831d35Sstevel { 334*03831d35Sstevel tty_common_t *tty; 335*03831d35Sstevel int unit = getminor(*devp); 336*03831d35Sstevel 337*03831d35Sstevel if (unit != 0) 338*03831d35Sstevel return (ENXIO); 339*03831d35Sstevel 340*03831d35Sstevel /* stream already open */ 341*03831d35Sstevel if (q->q_ptr) { 342*03831d35Sstevel return (DDI_SUCCESS); 343*03831d35Sstevel } 344*03831d35Sstevel 345*03831d35Sstevel if (!sgcn_state) { 346*03831d35Sstevel cmn_err(CE_WARN, "sgcn_open(): sgcn is not configured by\ 347*03831d35Sstevel autoconfig\n"); 348*03831d35Sstevel return (ENXIO); 349*03831d35Sstevel } 350*03831d35Sstevel 351*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 352*03831d35Sstevel tty = &(sgcn_state->sgcn_tty); 353*03831d35Sstevel 354*03831d35Sstevel tty->t_readq = q; 355*03831d35Sstevel tty->t_writeq = WR(q); 356*03831d35Sstevel 357*03831d35Sstevel /* Link the RD and WR Q's */ 358*03831d35Sstevel 359*03831d35Sstevel q->q_ptr = WR(q)->q_ptr = (caddr_t)sgcn_state; 360*03831d35Sstevel sgcn_state->sgcn_readq = RD(q); 361*03831d35Sstevel sgcn_state->sgcn_writeq = WR(q); 362*03831d35Sstevel qprocson(q); 363*03831d35Sstevel 364*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 365*03831d35Sstevel 366*03831d35Sstevel /* initialize interrupt handler */ 367*03831d35Sstevel iosram_reg_intr(SBBC_CONSOLE_IN, 368*03831d35Sstevel (sbbc_intrfunc_t)sgcn_data_in_handler, NULL, 369*03831d35Sstevel &sgcn_state->sgcn_sbbc_in_state, 370*03831d35Sstevel &sgcn_state->sgcn_sbbc_in_lock); 371*03831d35Sstevel iosram_reg_intr(SBBC_CONSOLE_SPACE_OUT, 372*03831d35Sstevel (sbbc_intrfunc_t)sgcn_space_2_out_handler, NULL, 373*03831d35Sstevel &sgcn_state->sgcn_sbbc_outspace_state, 374*03831d35Sstevel &sgcn_state->sgcn_sbbc_outspace_lock); 375*03831d35Sstevel iosram_reg_intr(SBBC_CONSOLE_BRK, 376*03831d35Sstevel (sbbc_intrfunc_t)sgcn_break_handler, NULL, 377*03831d35Sstevel &sgcn_state->sgcn_sbbc_brk_state, 378*03831d35Sstevel &sgcn_state->sgcn_sbbc_brk_lock); 379*03831d35Sstevel 380*03831d35Sstevel return (DDI_SUCCESS); 381*03831d35Sstevel } 382*03831d35Sstevel 383*03831d35Sstevel /* ARGSUSED */ 384*03831d35Sstevel static int 385*03831d35Sstevel sgcn_close(queue_t *q, int flag, cred_t *credp) 386*03831d35Sstevel { 387*03831d35Sstevel int ret; 388*03831d35Sstevel 389*03831d35Sstevel ASSERT(sgcn_state == q->q_ptr); 390*03831d35Sstevel 391*03831d35Sstevel if (sgcn_state->sgcn_wbufcid != 0) { 392*03831d35Sstevel unbufcall(sgcn_state->sgcn_wbufcid); 393*03831d35Sstevel } 394*03831d35Sstevel 395*03831d35Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_BRK); 396*03831d35Sstevel ASSERT(ret == 0); 397*03831d35Sstevel 398*03831d35Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_SPACE_OUT); 399*03831d35Sstevel ASSERT(ret == 0); 400*03831d35Sstevel 401*03831d35Sstevel ret = iosram_unreg_intr(SBBC_CONSOLE_IN); 402*03831d35Sstevel ASSERT(ret == 0); 403*03831d35Sstevel 404*03831d35Sstevel ttycommon_close(&sgcn_state->sgcn_tty); 405*03831d35Sstevel 406*03831d35Sstevel qprocsoff(q); 407*03831d35Sstevel q->q_ptr = WR(q)->q_ptr = NULL; 408*03831d35Sstevel sgcn_state->sgcn_readq = NULL; 409*03831d35Sstevel sgcn_state->sgcn_writeq = NULL; 410*03831d35Sstevel 411*03831d35Sstevel return (DDI_SUCCESS); 412*03831d35Sstevel } 413*03831d35Sstevel 414*03831d35Sstevel /* 415*03831d35Sstevel * Put procedure for write queue. 416*03831d35Sstevel * Respond to M_IOCTL, M_DATA and M_FLUSH messages here; 417*03831d35Sstevel * It put's the data onto internal sgcn_output_q. 418*03831d35Sstevel */ 419*03831d35Sstevel static int 420*03831d35Sstevel sgcn_wput(queue_t *q, mblk_t *mp) 421*03831d35Sstevel { 422*03831d35Sstevel 423*03831d35Sstevel #ifdef SGCN_DEBUG 424*03831d35Sstevel struct iocblk *iocp; 425*03831d35Sstevel int i; 426*03831d35Sstevel #endif 427*03831d35Sstevel 428*03831d35Sstevel ASSERT(sgcn_state == q->q_ptr); 429*03831d35Sstevel 430*03831d35Sstevel if (!mp->b_datap) { 431*03831d35Sstevel cmn_err(CE_PANIC, "sgcn_wput(): null datap"); 432*03831d35Sstevel } 433*03831d35Sstevel 434*03831d35Sstevel #ifdef SGCN_DEBUG 435*03831d35Sstevel prom_printf("sgcn_wput(): SGCN wput q=%X mp=%X rd=%X wr=%X type=%X\n", 436*03831d35Sstevel q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type); 437*03831d35Sstevel #endif 438*03831d35Sstevel 439*03831d35Sstevel switch (mp->b_datap->db_type) { 440*03831d35Sstevel case M_IOCTL: 441*03831d35Sstevel case M_CTL: 442*03831d35Sstevel #ifdef SGCN_DEBUG 443*03831d35Sstevel iocp = (struct iocblk *)mp->b_rptr; 444*03831d35Sstevel prom_printf("sgcn_wput(): M_IOCTL cmd=%X TIOC=%X\n", 445*03831d35Sstevel iocp->ioc_cmd, TIOC); 446*03831d35Sstevel #endif 447*03831d35Sstevel switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 448*03831d35Sstevel case TCSETSW: 449*03831d35Sstevel case TCSETSF: 450*03831d35Sstevel case TCSETAW: 451*03831d35Sstevel case TCSETAF: 452*03831d35Sstevel case TCSBRK: 453*03831d35Sstevel /* 454*03831d35Sstevel * The change do not take effect until all 455*03831d35Sstevel * output queued before them is drained. 456*03831d35Sstevel * Put this message on the queue, so that 457*03831d35Sstevel * "sgcn_start" will see it when it's done 458*03831d35Sstevel * with the output before it. Poke the start 459*03831d35Sstevel * routine, just in case. 460*03831d35Sstevel */ 461*03831d35Sstevel putq(q, mp); 462*03831d35Sstevel sgcn_start(); 463*03831d35Sstevel break; 464*03831d35Sstevel default: 465*03831d35Sstevel sgcn_ioctl(q, mp); 466*03831d35Sstevel } 467*03831d35Sstevel break; 468*03831d35Sstevel 469*03831d35Sstevel case M_FLUSH: 470*03831d35Sstevel if (*mp->b_rptr & FLUSHW) { 471*03831d35Sstevel flushq(q, FLUSHDATA); 472*03831d35Sstevel *mp->b_rptr &= ~FLUSHW; 473*03831d35Sstevel } 474*03831d35Sstevel if (*mp->b_rptr & FLUSHR) { 475*03831d35Sstevel flushq(RD(q), FLUSHDATA); 476*03831d35Sstevel qreply(q, mp); 477*03831d35Sstevel } else { 478*03831d35Sstevel freemsg(mp); 479*03831d35Sstevel } 480*03831d35Sstevel break; 481*03831d35Sstevel 482*03831d35Sstevel case M_STOP: 483*03831d35Sstevel sgcn_stopped = TRUE; 484*03831d35Sstevel freemsg(mp); 485*03831d35Sstevel break; 486*03831d35Sstevel 487*03831d35Sstevel case M_START: 488*03831d35Sstevel sgcn_stopped = FALSE; 489*03831d35Sstevel freemsg(mp); 490*03831d35Sstevel qenable(q); /* Start up delayed messages */ 491*03831d35Sstevel break; 492*03831d35Sstevel 493*03831d35Sstevel case M_DATA: 494*03831d35Sstevel /* 495*03831d35Sstevel * Queue the message up to be transmitted, 496*03831d35Sstevel * and poke the start routine. 497*03831d35Sstevel */ 498*03831d35Sstevel #ifdef SGCN_DEBUG 499*03831d35Sstevel if (mp->b_rptr < mp->b_wptr) { 500*03831d35Sstevel prom_printf("sgcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n", 501*03831d35Sstevel q, mp, mp->b_rptr, mp->b_wptr); 502*03831d35Sstevel prom_printf("sgcn_wput(): [[[[["); 503*03831d35Sstevel for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) { 504*03831d35Sstevel prom_printf("%c", *(mp->b_rptr+i)); 505*03831d35Sstevel } 506*03831d35Sstevel prom_printf("]]]]]\n"); 507*03831d35Sstevel } 508*03831d35Sstevel #endif /* SGCN_DEBUG */ 509*03831d35Sstevel (void) putq(q, mp); 510*03831d35Sstevel sgcn_start(); 511*03831d35Sstevel break; 512*03831d35Sstevel 513*03831d35Sstevel default: 514*03831d35Sstevel freemsg(mp); 515*03831d35Sstevel } 516*03831d35Sstevel 517*03831d35Sstevel return (0); 518*03831d35Sstevel } 519*03831d35Sstevel 520*03831d35Sstevel /* 521*03831d35Sstevel * Process an "ioctl" message sent down to us. 522*03831d35Sstevel */ 523*03831d35Sstevel static void 524*03831d35Sstevel sgcn_ioctl(queue_t *q, mblk_t *mp) 525*03831d35Sstevel { 526*03831d35Sstevel struct iocblk *iocp; 527*03831d35Sstevel tty_common_t *tty; 528*03831d35Sstevel mblk_t *datamp; 529*03831d35Sstevel int data_size; 530*03831d35Sstevel int error = 0; 531*03831d35Sstevel 532*03831d35Sstevel #ifdef SGCN_DEBUG 533*03831d35Sstevel prom_printf("sgcn_ioctl(): q=%X mp=%X\n", q, mp); 534*03831d35Sstevel #endif 535*03831d35Sstevel iocp = (struct iocblk *)mp->b_rptr; 536*03831d35Sstevel tty = &(sgcn_state->sgcn_tty); 537*03831d35Sstevel 538*03831d35Sstevel if (tty->t_iocpending != NULL) { 539*03831d35Sstevel freemsg(tty->t_iocpending); 540*03831d35Sstevel tty->t_iocpending = NULL; 541*03831d35Sstevel } 542*03831d35Sstevel data_size = ttycommon_ioctl(tty, q, mp, &error); 543*03831d35Sstevel if (data_size != 0) { 544*03831d35Sstevel if (sgcn_state->sgcn_wbufcid) 545*03831d35Sstevel unbufcall(sgcn_state->sgcn_wbufcid); 546*03831d35Sstevel /* call sgcn_reioctl() */ 547*03831d35Sstevel sgcn_state->sgcn_wbufcid = 548*03831d35Sstevel bufcall(data_size, BPRI_HI, sgcn_reioctl, sgcn_state); 549*03831d35Sstevel return; 550*03831d35Sstevel } 551*03831d35Sstevel 552*03831d35Sstevel if (error < 0) { 553*03831d35Sstevel iocp = (struct iocblk *)mp->b_rptr; 554*03831d35Sstevel /* 555*03831d35Sstevel * "ttycommon_ioctl" didn't do anything; we process it here. 556*03831d35Sstevel */ 557*03831d35Sstevel error = 0; 558*03831d35Sstevel switch (iocp->ioc_cmd) { 559*03831d35Sstevel case TCSBRK: 560*03831d35Sstevel case TIOCSBRK: 561*03831d35Sstevel case TIOCCBRK: 562*03831d35Sstevel case TIOCMSET: 563*03831d35Sstevel case TIOCMBIS: 564*03831d35Sstevel case TIOCMBIC: 565*03831d35Sstevel if (iocp->ioc_count != TRANSPARENT) 566*03831d35Sstevel mioc2ack(mp, NULL, 0, 0); 567*03831d35Sstevel else 568*03831d35Sstevel mcopyin(mp, NULL, sizeof (int), NULL); 569*03831d35Sstevel break; 570*03831d35Sstevel 571*03831d35Sstevel case TIOCMGET: 572*03831d35Sstevel datamp = allocb(sizeof (int), BPRI_MED); 573*03831d35Sstevel if (datamp == NULL) { 574*03831d35Sstevel error = EAGAIN; 575*03831d35Sstevel break; 576*03831d35Sstevel } 577*03831d35Sstevel 578*03831d35Sstevel *(int *)datamp->b_rptr = 0; 579*03831d35Sstevel 580*03831d35Sstevel if (iocp->ioc_count != TRANSPARENT) 581*03831d35Sstevel mioc2ack(mp, datamp, sizeof (int), 0); 582*03831d35Sstevel else 583*03831d35Sstevel mcopyout(mp, NULL, sizeof (int), NULL, datamp); 584*03831d35Sstevel break; 585*03831d35Sstevel 586*03831d35Sstevel default: 587*03831d35Sstevel error = EINVAL; 588*03831d35Sstevel break; 589*03831d35Sstevel } 590*03831d35Sstevel } 591*03831d35Sstevel if (error != 0) { 592*03831d35Sstevel iocp->ioc_count = 0; 593*03831d35Sstevel iocp->ioc_error = error; 594*03831d35Sstevel mp->b_datap->db_type = M_IOCNAK; 595*03831d35Sstevel } 596*03831d35Sstevel qreply(q, mp); 597*03831d35Sstevel } 598*03831d35Sstevel 599*03831d35Sstevel static void 600*03831d35Sstevel sgcn_reioctl(void *unit) 601*03831d35Sstevel { 602*03831d35Sstevel queue_t *q; 603*03831d35Sstevel mblk_t *mp; 604*03831d35Sstevel sgcn_t *sgcnp = (sgcn_t *)unit; 605*03831d35Sstevel 606*03831d35Sstevel if (!sgcnp->sgcn_wbufcid) { 607*03831d35Sstevel return; 608*03831d35Sstevel } 609*03831d35Sstevel sgcnp->sgcn_wbufcid = 0; 610*03831d35Sstevel if ((q = sgcnp->sgcn_tty.t_writeq) == NULL) { 611*03831d35Sstevel return; 612*03831d35Sstevel } 613*03831d35Sstevel 614*03831d35Sstevel if ((mp = sgcnp->sgcn_tty.t_iocpending) != NULL) { 615*03831d35Sstevel sgcnp->sgcn_tty.t_iocpending = NULL; 616*03831d35Sstevel sgcn_ioctl(q, mp); 617*03831d35Sstevel } 618*03831d35Sstevel } 619*03831d35Sstevel 620*03831d35Sstevel static void 621*03831d35Sstevel sgcn_start() 622*03831d35Sstevel { 623*03831d35Sstevel 624*03831d35Sstevel queue_t *q; 625*03831d35Sstevel mblk_t *mp; 626*03831d35Sstevel int retval; 627*03831d35Sstevel 628*03831d35Sstevel /* 629*03831d35Sstevel * read stream queue and remove data from the queue and 630*03831d35Sstevel * transmit them if possible 631*03831d35Sstevel */ 632*03831d35Sstevel q = sgcn_state->sgcn_writeq; 633*03831d35Sstevel ASSERT(q != NULL); 634*03831d35Sstevel while (mp = getq(q)) { 635*03831d35Sstevel switch (mp->b_datap->db_type) { 636*03831d35Sstevel case M_IOCTL: 637*03831d35Sstevel /* 638*03831d35Sstevel * These are those IOCTLs queued up 639*03831d35Sstevel * do it now 640*03831d35Sstevel */ 641*03831d35Sstevel sgcn_ioctl(q, mp); 642*03831d35Sstevel continue; 643*03831d35Sstevel default: 644*03831d35Sstevel /* 645*03831d35Sstevel * M_DATA 646*03831d35Sstevel * Copy it from stream queue buffer to 647*03831d35Sstevel * sgcn buffer 648*03831d35Sstevel */ 649*03831d35Sstevel retval = sgcn_transmit(q, mp); 650*03831d35Sstevel 651*03831d35Sstevel if (retval == EBUSY) { 652*03831d35Sstevel /* 653*03831d35Sstevel * Console output buffer is full for 654*03831d35Sstevel * sgcn_timeout_period seconds, assume 655*03831d35Sstevel * SC is dead, drop all console output 656*03831d35Sstevel * data from stream queue. 657*03831d35Sstevel */ 658*03831d35Sstevel if (sgcn_state->sgcn_sc_active < 659*03831d35Sstevel gethrestime_sec() - sgcn_timeout_period) 660*03831d35Sstevel sgcn_flush(); 661*03831d35Sstevel return; 662*03831d35Sstevel } else if (retval == EAGAIN) { 663*03831d35Sstevel /* 664*03831d35Sstevel * Console output just became full 665*03831d35Sstevel * return 666*03831d35Sstevel */ 667*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 668*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 669*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 670*03831d35Sstevel return; 671*03831d35Sstevel } else { 672*03831d35Sstevel /* send more console output */ 673*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 674*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 675*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 676*03831d35Sstevel } 677*03831d35Sstevel } /* switch */ 678*03831d35Sstevel } 679*03831d35Sstevel 680*03831d35Sstevel } 681*03831d35Sstevel 682*03831d35Sstevel static int 683*03831d35Sstevel sgcn_transmit(queue_t *q, mblk_t *mp) 684*03831d35Sstevel { 685*03831d35Sstevel caddr_t buf; 686*03831d35Sstevel mblk_t *bp; 687*03831d35Sstevel int len, oldlen; 688*03831d35Sstevel 689*03831d35Sstevel #ifdef SGCN_DEBUG 690*03831d35Sstevel prom_printf("sgcn_transmit(): q=%X mp=%X\n", q, mp); 691*03831d35Sstevel #endif 692*03831d35Sstevel do { 693*03831d35Sstevel bp = mp; 694*03831d35Sstevel oldlen = len = bp->b_wptr - bp->b_rptr; 695*03831d35Sstevel buf = (caddr_t)bp->b_rptr; 696*03831d35Sstevel len = CONSOLE_WRITE(buf, len); 697*03831d35Sstevel if (len > 0) 698*03831d35Sstevel iosram_send_intr(SBBC_CONSOLE_OUT); 699*03831d35Sstevel if (len >= 0 && len < oldlen) { 700*03831d35Sstevel /* IOSRAM is full, we are not done with mp yet */ 701*03831d35Sstevel bp->b_rptr += len; 702*03831d35Sstevel (void) putbq(q, mp); 703*03831d35Sstevel if (len) 704*03831d35Sstevel return (EAGAIN); 705*03831d35Sstevel else 706*03831d35Sstevel return (EBUSY); 707*03831d35Sstevel } 708*03831d35Sstevel mp = bp->b_cont; 709*03831d35Sstevel freeb(bp); 710*03831d35Sstevel } while (mp); 711*03831d35Sstevel 712*03831d35Sstevel return (0); 713*03831d35Sstevel } 714*03831d35Sstevel 715*03831d35Sstevel /* 716*03831d35Sstevel * called when SC first establishes console connection 717*03831d35Sstevel * drop all the data on the output queue 718*03831d35Sstevel */ 719*03831d35Sstevel static void 720*03831d35Sstevel sgcn_flush() 721*03831d35Sstevel { 722*03831d35Sstevel queue_t *q; 723*03831d35Sstevel mblk_t *mp; 724*03831d35Sstevel 725*03831d35Sstevel q = sgcn_state->sgcn_writeq; 726*03831d35Sstevel 727*03831d35Sstevel prom_printf("sgcn_flush(): WARNING console output is dropped " 728*03831d35Sstevel "time=%lX\n", gethrestime_sec()); 729*03831d35Sstevel while (mp = getq(q)) { 730*03831d35Sstevel freemsg(mp); 731*03831d35Sstevel } 732*03831d35Sstevel 733*03831d35Sstevel } 734*03831d35Sstevel 735*03831d35Sstevel uint64_t sgcn_input_dropped; 736*03831d35Sstevel 737*03831d35Sstevel /* 738*03831d35Sstevel * Interrupt handlers 739*03831d35Sstevel * All handlers register with SBBC driver and must follow SBBC interrupt 740*03831d35Sstevel * delivery conventions. 741*03831d35Sstevel */ 742*03831d35Sstevel /* 743*03831d35Sstevel * SC sends an interrupt when new data comes in 744*03831d35Sstevel */ 745*03831d35Sstevel /* ARGSUSED */ 746*03831d35Sstevel void 747*03831d35Sstevel sgcn_data_in_handler(caddr_t arg) 748*03831d35Sstevel { 749*03831d35Sstevel caddr_t buf = sgcn_state->sgcn_inbuf; 750*03831d35Sstevel int i, len; 751*03831d35Sstevel mblk_t *mp; 752*03831d35Sstevel 753*03831d35Sstevel /* 754*03831d35Sstevel * change interrupt state so that SBBC won't trigger 755*03831d35Sstevel * another one. 756*03831d35Sstevel */ 757*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_in_lock); 758*03831d35Sstevel sgcn_state->sgcn_sbbc_in_state = SBBC_INTR_RUNNING; 759*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock); 760*03831d35Sstevel 761*03831d35Sstevel /* update sgcn_state for SC activity information */ 762*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 763*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 764*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 765*03831d35Sstevel 766*03831d35Sstevel /* enter our perimeter */ 767*03831d35Sstevel entersq(sgcn_state->sgcn_readq->q_syncq, SQ_CALLBACK); 768*03831d35Sstevel 769*03831d35Sstevel for (;;) { 770*03831d35Sstevel 771*03831d35Sstevel /* read from console input IOSRAM */ 772*03831d35Sstevel len = CONSOLE_READ(buf, sgcn_state->sgcn_inbuf_size); 773*03831d35Sstevel 774*03831d35Sstevel if (len <= 0) { 775*03831d35Sstevel 776*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_in_lock); 777*03831d35Sstevel 778*03831d35Sstevel len = CONSOLE_READ(buf, sgcn_state->sgcn_inbuf_size); 779*03831d35Sstevel 780*03831d35Sstevel if (len <= 0) { 781*03831d35Sstevel sgcn_state->sgcn_sbbc_in_state = SBBC_INTR_IDLE; 782*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock); 783*03831d35Sstevel 784*03831d35Sstevel /* leave our perimeter */ 785*03831d35Sstevel leavesq(sgcn_state->sgcn_readq->q_syncq, 786*03831d35Sstevel SQ_CALLBACK); 787*03831d35Sstevel return; 788*03831d35Sstevel } else { 789*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_in_lock); 790*03831d35Sstevel } 791*03831d35Sstevel 792*03831d35Sstevel } 793*03831d35Sstevel 794*03831d35Sstevel iosram_send_intr(SBBC_CONSOLE_SPACE_IN); 795*03831d35Sstevel 796*03831d35Sstevel if (abort_enable == KIOCABORTALTERNATE) { 797*03831d35Sstevel for (i = 0; i < len; i ++) { 798*03831d35Sstevel if (abort_charseq_recognize(buf[i])) 799*03831d35Sstevel abort_sequence_enter((char *)NULL); 800*03831d35Sstevel } 801*03831d35Sstevel } 802*03831d35Sstevel 803*03831d35Sstevel /* put console input onto stream */ 804*03831d35Sstevel if (sgcn_state->sgcn_readq) { 805*03831d35Sstevel if ((mp = allocb(len, BPRI_MED)) == (mblk_t *)NULL) { 806*03831d35Sstevel sgcn_input_dropped += len; 807*03831d35Sstevel cmn_err(CE_WARN, 808*03831d35Sstevel "sgcn_data_in_handler(): allocb failed" 809*03831d35Sstevel " (console input dropped.)"); 810*03831d35Sstevel } else { 811*03831d35Sstevel bcopy(buf, mp->b_wptr, len); 812*03831d35Sstevel mp->b_wptr += len; 813*03831d35Sstevel putnext(sgcn_state->sgcn_readq, mp); 814*03831d35Sstevel } 815*03831d35Sstevel } 816*03831d35Sstevel } 817*03831d35Sstevel 818*03831d35Sstevel } 819*03831d35Sstevel 820*03831d35Sstevel /* 821*03831d35Sstevel * SC sends an interrupt when it takes output data 822*03831d35Sstevel * from a full IOSRAM 823*03831d35Sstevel */ 824*03831d35Sstevel /* ARGSUSED */ 825*03831d35Sstevel void 826*03831d35Sstevel sgcn_space_2_out_handler(caddr_t arg) 827*03831d35Sstevel { 828*03831d35Sstevel /* 829*03831d35Sstevel * change interrupt state so that SBBC won't trigger 830*03831d35Sstevel * another one. 831*03831d35Sstevel */ 832*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_outspace_lock); 833*03831d35Sstevel sgcn_state->sgcn_sbbc_outspace_state = SBBC_INTR_RUNNING; 834*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_outspace_lock); 835*03831d35Sstevel 836*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 837*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 838*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 839*03831d35Sstevel 840*03831d35Sstevel if (sgcn_state->sgcn_writeq != NULL) 841*03831d35Sstevel qenable(sgcn_state->sgcn_writeq); 842*03831d35Sstevel 843*03831d35Sstevel /* restore interrupt state */ 844*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_outspace_lock); 845*03831d35Sstevel sgcn_state->sgcn_sbbc_outspace_state = SBBC_INTR_IDLE; 846*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_outspace_lock); 847*03831d35Sstevel } 848*03831d35Sstevel 849*03831d35Sstevel /* 850*03831d35Sstevel * SC sends an interrupt when it detects BREAK sequence 851*03831d35Sstevel */ 852*03831d35Sstevel /* ARGSUSED */ 853*03831d35Sstevel void 854*03831d35Sstevel sgcn_break_handler(caddr_t arg) 855*03831d35Sstevel { 856*03831d35Sstevel /* 857*03831d35Sstevel * change interrupt state so that SBBC won't trigger 858*03831d35Sstevel * another one. 859*03831d35Sstevel */ 860*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_brk_lock); 861*03831d35Sstevel sgcn_state->sgcn_sbbc_brk_state = SBBC_INTR_RUNNING; 862*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_brk_lock); 863*03831d35Sstevel 864*03831d35Sstevel if (abort_enable != KIOCABORTALTERNATE) 865*03831d35Sstevel abort_sequence_enter((char *)NULL); 866*03831d35Sstevel 867*03831d35Sstevel /* restore interrupt state */ 868*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_sbbc_brk_lock); 869*03831d35Sstevel sgcn_state->sgcn_sbbc_brk_state = SBBC_INTR_IDLE; 870*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_sbbc_brk_lock); 871*03831d35Sstevel } 872*03831d35Sstevel 873*03831d35Sstevel /* 874*03831d35Sstevel * reporting errors in console driver sgcn. 875*03831d35Sstevel * since we can not trust console driver at this time, we need to 876*03831d35Sstevel * log errors in other system logs 877*03831d35Sstevel * error codes: 878*03831d35Sstevel * EIO - iosram interface failed 879*03831d35Sstevel * EPROTO - IOSRAM is corrupted 880*03831d35Sstevel * EINVAL - invalid argument 881*03831d35Sstevel */ 882*03831d35Sstevel #define SGCN_MAX_ERROR 100 883*03831d35Sstevel static void 884*03831d35Sstevel sgcn_log_error(int when, int what) 885*03831d35Sstevel { 886*03831d35Sstevel char error_msg[256], error_code[256]; 887*03831d35Sstevel static uint_t error_counter = 0; 888*03831d35Sstevel 889*03831d35Sstevel error_counter ++; 890*03831d35Sstevel 891*03831d35Sstevel if (error_counter > SGCN_MAX_ERROR) { 892*03831d35Sstevel error_counter = 0; 893*03831d35Sstevel strcpy(error_msg, "!Too many sgcn errors"); 894*03831d35Sstevel } else { 895*03831d35Sstevel (void) sprintf(error_code, "Error %d", what); 896*03831d35Sstevel 897*03831d35Sstevel (void) sprintf(error_msg, "!%s at %s", 898*03831d35Sstevel (what == EIO) ? "IOSRAM interface failed" : 899*03831d35Sstevel (what == EPROTO) ? "IOSRAM corrupted" : 900*03831d35Sstevel (what == EINVAL) ? "Invalid argument" : 901*03831d35Sstevel error_code, 902*03831d35Sstevel (when == RW_CONSOLE_READ) ? "console input" : 903*03831d35Sstevel (when == RW_CONSOLE_WRITE) ? "console output, dropped" : 904*03831d35Sstevel "console I/O"); 905*03831d35Sstevel } 906*03831d35Sstevel 907*03831d35Sstevel cmn_err(CE_WARN, error_msg); 908*03831d35Sstevel } 909*03831d35Sstevel 910*03831d35Sstevel static int 911*03831d35Sstevel sgcn_read_header(int rw, cnsram_header *header) 912*03831d35Sstevel { 913*03831d35Sstevel int rv; 914*03831d35Sstevel 915*03831d35Sstevel /* check IOSRAM contents and read pointers */ 916*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 0, (caddr_t)header, 917*03831d35Sstevel sizeof (cnsram_header)); 918*03831d35Sstevel if (rv != 0) { 919*03831d35Sstevel return (-1); 920*03831d35Sstevel } 921*03831d35Sstevel 922*03831d35Sstevel /* 923*03831d35Sstevel * Since the header is read in a byte-by-byte fashion 924*03831d35Sstevel * using ddi_rep_get8, we need to re-read the producer 925*03831d35Sstevel * or consumer pointer as integer in case it has changed 926*03831d35Sstevel * after part of the previous value has been read. 927*03831d35Sstevel */ 928*03831d35Sstevel if (rw == RW_CONSOLE_READ) { 929*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 930*03831d35Sstevel OFFSETOF((*header), cnsram_in_wrptr), 931*03831d35Sstevel POINTER((*header), cnsram_in_wrptr), 932*03831d35Sstevel sizeof (header->cnsram_in_wrptr)); 933*03831d35Sstevel } else if (rw == RW_CONSOLE_WRITE) { 934*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 935*03831d35Sstevel OFFSETOF((*header), cnsram_out_rdptr), 936*03831d35Sstevel POINTER((*header), cnsram_out_rdptr), 937*03831d35Sstevel sizeof (header->cnsram_out_rdptr)); 938*03831d35Sstevel } else 939*03831d35Sstevel rv = -1; 940*03831d35Sstevel 941*03831d35Sstevel return (rv); 942*03831d35Sstevel } 943*03831d35Sstevel 944*03831d35Sstevel static int 945*03831d35Sstevel sgcn_rw(int rw, caddr_t buf, int len) 946*03831d35Sstevel { 947*03831d35Sstevel cnsram_header header; 948*03831d35Sstevel int rv, size, nbytes; 949*03831d35Sstevel 950*03831d35Sstevel #ifdef SGCN_DEBUG 951*03831d35Sstevel prom_printf("sgcn_rw() rw = %X buf = %p len = %d\n", 952*03831d35Sstevel rw, buf, len); 953*03831d35Sstevel #endif /* SGCN_DEBUG */ 954*03831d35Sstevel if (len == 0) 955*03831d35Sstevel return (0); 956*03831d35Sstevel 957*03831d35Sstevel /* sanity check */ 958*03831d35Sstevel if (buf == NULL || len < 0) { 959*03831d35Sstevel sgcn_log_error(rw, EINVAL); 960*03831d35Sstevel return (-1); 961*03831d35Sstevel } 962*03831d35Sstevel 963*03831d35Sstevel /* check IOSRAM contents and read pointers */ 964*03831d35Sstevel rv = sgcn_read_header(rw, &header); 965*03831d35Sstevel if (rv != 0) { 966*03831d35Sstevel sgcn_log_error(rw, EIO); 967*03831d35Sstevel return (-1); 968*03831d35Sstevel } 969*03831d35Sstevel if (header.cnsram_magic != CNSRAM_MAGIC) { 970*03831d35Sstevel sgcn_log_error(rw, EPROTO); 971*03831d35Sstevel return (-1); 972*03831d35Sstevel } 973*03831d35Sstevel 974*03831d35Sstevel if (rw == RW_CONSOLE_READ) 975*03831d35Sstevel size = header.cnsram_in_end - header.cnsram_in_begin; 976*03831d35Sstevel else if (rw == RW_CONSOLE_WRITE) 977*03831d35Sstevel size = header.cnsram_out_end - header.cnsram_out_begin; 978*03831d35Sstevel if (size < 0) { 979*03831d35Sstevel sgcn_log_error(rw, EPROTO); 980*03831d35Sstevel return (-1); 981*03831d35Sstevel } 982*03831d35Sstevel 983*03831d35Sstevel if (rw == RW_CONSOLE_READ) 984*03831d35Sstevel nbytes = circular_buffer_read( 985*03831d35Sstevel header.cnsram_in_begin, 986*03831d35Sstevel header.cnsram_in_end, 987*03831d35Sstevel header.cnsram_in_rdptr, 988*03831d35Sstevel header.cnsram_in_wrptr, buf, len); 989*03831d35Sstevel else if (rw == RW_CONSOLE_WRITE) 990*03831d35Sstevel nbytes = circular_buffer_write( 991*03831d35Sstevel header.cnsram_out_begin, 992*03831d35Sstevel header.cnsram_out_end, 993*03831d35Sstevel header.cnsram_out_rdptr, 994*03831d35Sstevel header.cnsram_out_wrptr, buf, len); 995*03831d35Sstevel 996*03831d35Sstevel /* 997*03831d35Sstevel * error log was done in circular buffer routines, 998*03831d35Sstevel * no need to call sgcn_log_error() here 999*03831d35Sstevel */ 1000*03831d35Sstevel if (nbytes < 0) 1001*03831d35Sstevel return (-1); 1002*03831d35Sstevel 1003*03831d35Sstevel if (nbytes == 0) 1004*03831d35Sstevel return (0); 1005*03831d35Sstevel 1006*03831d35Sstevel if (rw == RW_CONSOLE_READ) { 1007*03831d35Sstevel header.cnsram_in_rdptr = 1008*03831d35Sstevel (header.cnsram_in_rdptr - header.cnsram_in_begin 1009*03831d35Sstevel + nbytes) 1010*03831d35Sstevel % size + header.cnsram_in_begin; 1011*03831d35Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, 1012*03831d35Sstevel OFFSETOF(header, cnsram_in_rdptr), 1013*03831d35Sstevel POINTER(header, cnsram_in_rdptr), 1014*03831d35Sstevel sizeof (header.cnsram_in_rdptr)); 1015*03831d35Sstevel } else if (rw == RW_CONSOLE_WRITE) { 1016*03831d35Sstevel header.cnsram_out_wrptr = 1017*03831d35Sstevel (header.cnsram_out_wrptr - header.cnsram_out_begin 1018*03831d35Sstevel + nbytes) 1019*03831d35Sstevel % size + header.cnsram_out_begin; 1020*03831d35Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, 1021*03831d35Sstevel OFFSETOF(header, cnsram_out_wrptr), 1022*03831d35Sstevel POINTER(header, cnsram_out_wrptr), 1023*03831d35Sstevel sizeof (header.cnsram_out_wrptr)); 1024*03831d35Sstevel } 1025*03831d35Sstevel if (rv != 0) { 1026*03831d35Sstevel sgcn_log_error(rw, EIO); 1027*03831d35Sstevel return (-1); 1028*03831d35Sstevel } 1029*03831d35Sstevel 1030*03831d35Sstevel return (nbytes); 1031*03831d35Sstevel } 1032*03831d35Sstevel 1033*03831d35Sstevel /* 1034*03831d35Sstevel * Circular buffer interfaces 1035*03831d35Sstevel * 1036*03831d35Sstevel * See sgcn.h for circular buffer structure 1037*03831d35Sstevel * 1038*03831d35Sstevel * The circular buffer is empty when read ptr == write ptr 1039*03831d35Sstevel * and is full when read ptr is one ahead of write ptr 1040*03831d35Sstevel */ 1041*03831d35Sstevel /* 1042*03831d35Sstevel * Write to circular buffer in IOSRAM 1043*03831d35Sstevel * input: 1044*03831d35Sstevel * buf buffer in main memory, contains data to be written 1045*03831d35Sstevel * len length of data in bytes 1046*03831d35Sstevel * begin, end, rd, wr buffer pointers 1047*03831d35Sstevel * return value: 1048*03831d35Sstevel * actual bytes written. 1049*03831d35Sstevel */ 1050*03831d35Sstevel static int 1051*03831d35Sstevel circular_buffer_write(int begin, int end, int rd, int wr, caddr_t buf, int len) 1052*03831d35Sstevel { 1053*03831d35Sstevel int size, space, space_at_end; 1054*03831d35Sstevel int rv = 0; 1055*03831d35Sstevel 1056*03831d35Sstevel size = end - begin; 1057*03831d35Sstevel if (size <= 0) { 1058*03831d35Sstevel rv = EINVAL; 1059*03831d35Sstevel goto out; 1060*03831d35Sstevel } 1061*03831d35Sstevel 1062*03831d35Sstevel if ((len = ((len >= size) ? (size-1) : len)) == 0) 1063*03831d35Sstevel return (0); /* The buffer's full, so just return 0 now. */ 1064*03831d35Sstevel 1065*03831d35Sstevel space = (rd - wr + size - 1) % size; 1066*03831d35Sstevel len = min(len, space); 1067*03831d35Sstevel space_at_end = end - wr; 1068*03831d35Sstevel 1069*03831d35Sstevel if (rd > wr || rd <= wr && space_at_end >= len) { /* one piece */ 1070*03831d35Sstevel /* write console data */ 1071*03831d35Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, wr, buf, len); 1072*03831d35Sstevel if (rv != 0) goto out; 1073*03831d35Sstevel } else { /* break into two pieces because of circular buffer */ 1074*03831d35Sstevel /* write console data */ 1075*03831d35Sstevel if (space_at_end) { 1076*03831d35Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, 1077*03831d35Sstevel wr, buf, space_at_end); 1078*03831d35Sstevel if (rv != 0) goto out; 1079*03831d35Sstevel } 1080*03831d35Sstevel if (len - space_at_end) { 1081*03831d35Sstevel rv = iosram_write(SBBC_CONSOLE_KEY, 1082*03831d35Sstevel begin, buf+space_at_end, len-space_at_end); 1083*03831d35Sstevel if (rv != 0) goto out; 1084*03831d35Sstevel } 1085*03831d35Sstevel } 1086*03831d35Sstevel return (len); 1087*03831d35Sstevel out: 1088*03831d35Sstevel sgcn_log_error(RW_CONSOLE_WRITE, rv); 1089*03831d35Sstevel return (-1); 1090*03831d35Sstevel } 1091*03831d35Sstevel 1092*03831d35Sstevel /* 1093*03831d35Sstevel * Read from circular buffer in IOSRAM 1094*03831d35Sstevel * input: 1095*03831d35Sstevel * buf preallocated buffer in memory 1096*03831d35Sstevel * len size of buf 1097*03831d35Sstevel * begin, end, rd, wr buffer pointers 1098*03831d35Sstevel * return value: 1099*03831d35Sstevel * actual bytes read 1100*03831d35Sstevel */ 1101*03831d35Sstevel /* ARGSUSED */ 1102*03831d35Sstevel static int 1103*03831d35Sstevel circular_buffer_read(int begin, int end, int rd, int wr, caddr_t buf, int len) 1104*03831d35Sstevel { 1105*03831d35Sstevel int size, nbytes, nbytes_at_end; 1106*03831d35Sstevel int rv = 0; 1107*03831d35Sstevel 1108*03831d35Sstevel size = end - begin; 1109*03831d35Sstevel if (size <= 0) { 1110*03831d35Sstevel rv = EINVAL; 1111*03831d35Sstevel goto out; 1112*03831d35Sstevel } 1113*03831d35Sstevel nbytes = (wr - rd + size) % size; 1114*03831d35Sstevel 1115*03831d35Sstevel nbytes = min(nbytes, len); 1116*03831d35Sstevel 1117*03831d35Sstevel if (wr > rd) { /* one piece */ 1118*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, rd, buf, nbytes); 1119*03831d35Sstevel if (rv != 0) goto out; 1120*03831d35Sstevel } else { /* break into two pieces because of circular buffer */ 1121*03831d35Sstevel nbytes_at_end = min(nbytes, end - rd); 1122*03831d35Sstevel /* read console data */ 1123*03831d35Sstevel if (nbytes_at_end) { 1124*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 1125*03831d35Sstevel rd, buf, nbytes_at_end); 1126*03831d35Sstevel if (rv != 0) goto out; 1127*03831d35Sstevel } 1128*03831d35Sstevel if (nbytes-nbytes_at_end) { 1129*03831d35Sstevel rv = iosram_read(SBBC_CONSOLE_KEY, 1130*03831d35Sstevel begin, buf+nbytes_at_end, nbytes-nbytes_at_end); 1131*03831d35Sstevel if (rv != 0) goto out; 1132*03831d35Sstevel } 1133*03831d35Sstevel } 1134*03831d35Sstevel return (nbytes); 1135*03831d35Sstevel out: 1136*03831d35Sstevel sgcn_log_error(RW_CONSOLE_READ, rv); 1137*03831d35Sstevel return (-1); 1138*03831d35Sstevel } 1139*03831d35Sstevel 1140*03831d35Sstevel /* 1141*03831d35Sstevel * Check for abort character sequence, copied from zs_async.c 1142*03831d35Sstevel */ 1143*03831d35Sstevel #define CNTRL(c) ((c)&037) 1144*03831d35Sstevel 1145*03831d35Sstevel static boolean_t 1146*03831d35Sstevel abort_charseq_recognize(uchar_t ch) 1147*03831d35Sstevel { 1148*03831d35Sstevel static int state = 0; 1149*03831d35Sstevel static char sequence[] = { '\r', '~', CNTRL('b') }; 1150*03831d35Sstevel 1151*03831d35Sstevel if (ch == sequence[state]) { 1152*03831d35Sstevel if (++state >= sizeof (sequence)) { 1153*03831d35Sstevel state = 0; 1154*03831d35Sstevel return (B_TRUE); 1155*03831d35Sstevel } 1156*03831d35Sstevel } else { 1157*03831d35Sstevel state = (ch == sequence[0]) ? 1 : 0; 1158*03831d35Sstevel } 1159*03831d35Sstevel return (B_FALSE); 1160*03831d35Sstevel } 1161*03831d35Sstevel 1162*03831d35Sstevel static void 1163*03831d35Sstevel sg_abort_seq_handler(char *msg) 1164*03831d35Sstevel { 1165*03831d35Sstevel char key_switch; 1166*03831d35Sstevel int rv; 1167*03831d35Sstevel 1168*03831d35Sstevel /* read virtual keyswitch position from IOSRAM */ 1169*03831d35Sstevel rv = iosram_read(SBBC_KEYSWITCH_KEY, 0, &key_switch, 1); 1170*03831d35Sstevel if (rv != 0) { 1171*03831d35Sstevel /* default to not secure if read failed */ 1172*03831d35Sstevel cmn_err(CE_NOTE, "!Read keyswitch failed (%d)", rv); 1173*03831d35Sstevel key_switch = 0; 1174*03831d35Sstevel } 1175*03831d35Sstevel if (key_switch & SG_KEYSWITCH_POSN_SECURE) { 1176*03831d35Sstevel cmn_err(CE_NOTE, "!Keyswitch is in secure mode"); 1177*03831d35Sstevel } else { 1178*03831d35Sstevel debug_enter(msg); 1179*03831d35Sstevel } 1180*03831d35Sstevel } 1181*03831d35Sstevel 1182*03831d35Sstevel static int 1183*03831d35Sstevel sgcn_rsrv(queue_t *q) 1184*03831d35Sstevel { 1185*03831d35Sstevel mblk_t *mp; 1186*03831d35Sstevel 1187*03831d35Sstevel if (sgcn_stopped == TRUE) { 1188*03831d35Sstevel return (0); 1189*03831d35Sstevel } 1190*03831d35Sstevel 1191*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 1192*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 1193*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 1194*03831d35Sstevel 1195*03831d35Sstevel while ((mp = getq(q)) != NULL) { 1196*03831d35Sstevel if (canputnext(q)) { 1197*03831d35Sstevel putnext(q, mp); 1198*03831d35Sstevel } else if (mp->b_datap->db_type >= QPCTL) { 1199*03831d35Sstevel putbq(q, mp); 1200*03831d35Sstevel } 1201*03831d35Sstevel } 1202*03831d35Sstevel 1203*03831d35Sstevel return (0); 1204*03831d35Sstevel } 1205*03831d35Sstevel 1206*03831d35Sstevel /* ARGSUSED */ 1207*03831d35Sstevel static int 1208*03831d35Sstevel sgcn_wsrv(queue_t *q) 1209*03831d35Sstevel { 1210*03831d35Sstevel if (sgcn_stopped == TRUE) 1211*03831d35Sstevel return (0); 1212*03831d35Sstevel 1213*03831d35Sstevel mutex_enter(&sgcn_state->sgcn_lock); 1214*03831d35Sstevel sgcn_state->sgcn_sc_active = gethrestime_sec(); 1215*03831d35Sstevel mutex_exit(&sgcn_state->sgcn_lock); 1216*03831d35Sstevel 1217*03831d35Sstevel if (sgcn_state->sgcn_writeq != NULL) 1218*03831d35Sstevel sgcn_start(); 1219*03831d35Sstevel 1220*03831d35Sstevel return (0); 1221*03831d35Sstevel } 1222