Home | History | Annotate | Download | only in io
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1991     heppo  * Common Development and Distribution License (the "License").
      6  1991     heppo  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21  1991     heppo 
     22     0    stevel /*
     23  9250   Zachary  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0    stevel  * Use is subject to license terms.
     25     0    stevel  */
     26     0    stevel 
     27     0    stevel 
     28     0    stevel /*
     29     0    stevel  * sun4v console driver
     30     0    stevel  */
     31     0    stevel 
     32     0    stevel #include <sys/errno.h>
     33     0    stevel #include <sys/stat.h>
     34     0    stevel #include <sys/kmem.h>
     35     0    stevel #include <sys/conf.h>
     36     0    stevel #include <sys/termios.h>
     37     0    stevel #include <sys/modctl.h>
     38     0    stevel #include <sys/kbio.h>
     39     0    stevel #include <sys/stropts.h>
     40     0    stevel #include <sys/stream.h>
     41     0    stevel #include <sys/strsun.h>
     42     0    stevel #include <sys/sysmacros.h>
     43     0    stevel #include <sys/promif.h>
     44     0    stevel #include <sys/ddi.h>
     45     0    stevel #include <sys/sunddi.h>
     46     0    stevel #include <sys/cyclic.h>
     47     0    stevel #include <sys/intr.h>
     48     0    stevel #include <sys/spl.h>
     49     0    stevel #include <sys/qcn.h>
     50     0    stevel #include <sys/hypervisor_api.h>
     51  2282  jb145095 #include <sys/hsvc.h>
     52  2282  jb145095 #include <sys/machsystm.h>
     53  5974   jm22469 #include <sys/consdev.h>
     54     0    stevel 
     55     0    stevel /* dev_ops and cb_ops for device driver */
     56     0    stevel static int qcn_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
     57     0    stevel static int qcn_attach(dev_info_t *, ddi_attach_cmd_t);
     58     0    stevel static int qcn_detach(dev_info_t *, ddi_detach_cmd_t);
     59     0    stevel static int qcn_open(queue_t *, dev_t *, int, int, cred_t *);
     60     0    stevel static int qcn_close(queue_t *, int, cred_t *);
     61     0    stevel static int qcn_wput(queue_t *, mblk_t *);
     62     0    stevel static int qcn_wsrv(queue_t *);
     63     0    stevel static int qcn_rsrv(queue_t *);
     64     0    stevel 
     65     0    stevel /* other internal qcn routines */
     66     0    stevel static void qcn_ioctl(queue_t *, mblk_t *);
     67     0    stevel static void qcn_reioctl(void *);
     68     0    stevel static void qcn_ack(mblk_t *, mblk_t *, uint_t);
     69     0    stevel static void qcn_start(void);
     70  2282  jb145095 static int qcn_transmit_write(queue_t *, mblk_t *);
     71  2282  jb145095 static int qcn_transmit_putchr(queue_t *, mblk_t *);
     72  2282  jb145095 static void qcn_receive_read(void);
     73  2282  jb145095 static void qcn_receive_getchr(void);
     74     0    stevel static void qcn_flush(void);
     75     0    stevel static uint_t qcn_hi_intr(caddr_t arg);
     76     0    stevel static uint_t qcn_soft_intr(caddr_t arg1, caddr_t arg2);
     77  5974   jm22469 
     78  5974   jm22469 /* functions required for polled io */
     79  5974   jm22469 static boolean_t qcn_polledio_ischar(cons_polledio_arg_t arg);
     80  5974   jm22469 static int qcn_polledio_getchar(cons_polledio_arg_t arg);
     81  5974   jm22469 static void qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c);
     82  5974   jm22469 static void qcn_polledio_enter(cons_polledio_arg_t arg);
     83  5974   jm22469 static void qcn_polledio_exit(cons_polledio_arg_t arg);
     84  5974   jm22469 
     85     0    stevel 
     86     0    stevel static boolean_t abort_charseq_recognize(uchar_t);
     87     0    stevel 
     88     0    stevel static qcn_t *qcn_state;
     89     0    stevel static uchar_t qcn_stopped = B_FALSE;
     90     0    stevel static int qcn_timeout_period = 20;	/* time out in seconds */
     91     0    stevel size_t qcn_input_dropped;	/* dropped input character counter */
     92     0    stevel 
     93     0    stevel #ifdef QCN_POLLING
     94     0    stevel static void qcn_poll_handler(void *unused);
     95  2954  jb145095 static cyc_time_t qcn_poll_time;
     96     0    stevel static cyc_handler_t qcn_poll_cychandler = {
     97     0    stevel 	qcn_poll_handler,
     98     0    stevel 	NULL,
     99     0    stevel 	CY_LOW_LEVEL		/* XXX need softint to make this high */
    100     0    stevel };
    101     0    stevel static cyclic_id_t qcn_poll_cycid = CYCLIC_NONE;
    102  2954  jb145095 static uint64_t	qcn_poll_interval = 5;  /* milli sec */
    103  1991     heppo static uint64_t sb_interval = 0;
    104  1991     heppo uint_t qcn_force_polling = 0;
    105     0    stevel #endif
    106     0    stevel 
    107     0    stevel #define	QCN_MI_IDNUM		0xABCE
    108     0    stevel #define	QCN_MI_HIWAT		8192
    109     0    stevel #define	QCN_MI_LOWAT		128
    110     0    stevel 
    111     0    stevel /* streams structures */
    112     0    stevel static struct module_info minfo = {
    113     0    stevel 	QCN_MI_IDNUM,	/* mi_idnum		*/
    114     0    stevel 	"qcn",		/* mi_idname		*/
    115     0    stevel 	0,		/* mi_minpsz		*/
    116     0    stevel 	INFPSZ,		/* mi_maxpsz		*/
    117     0    stevel 	QCN_MI_HIWAT,	/* mi_hiwat		*/
    118     0    stevel 	QCN_MI_LOWAT	/* mi_lowat		*/
    119     0    stevel };
    120     0    stevel 
    121     0    stevel static struct qinit rinit = {
    122     0    stevel 	putq,		/* qi_putp		*/
    123     0    stevel 	qcn_rsrv,	/* qi_srvp		*/
    124     0    stevel 	qcn_open,	/* qi_qopen		*/
    125     0    stevel 	qcn_close,	/* qi_qclose		*/
    126     0    stevel 	NULL,		/* qi_qadmin		*/
    127     0    stevel 	&minfo,		/* qi_minfo		*/
    128     0    stevel 	NULL		/* qi_mstat		*/
    129     0    stevel };
    130     0    stevel 
    131     0    stevel static struct qinit winit = {
    132     0    stevel 	qcn_wput,	/* qi_putp		*/
    133     0    stevel 	qcn_wsrv,	/* qi_srvp		*/
    134     0    stevel 	qcn_open,	/* qi_qopen		*/
    135     0    stevel 	qcn_close,	/* qi_qclose		*/
    136     0    stevel 	NULL,		/* qi_qadmin		*/
    137     0    stevel 	&minfo,		/* qi_minfo		*/
    138     0    stevel 	NULL		/* qi_mstat		*/
    139     0    stevel };
    140     0    stevel 
    141     0    stevel static struct streamtab qcnstrinfo = {
    142     0    stevel 	&rinit,
    143     0    stevel 	&winit,
    144     0    stevel 	NULL,
    145     0    stevel 	NULL
    146     0    stevel };
    147     0    stevel 
    148     0    stevel /* standard device driver structures */
    149     0    stevel static struct cb_ops qcn_cb_ops = {
    150     0    stevel 	nulldev,		/* open()		*/
    151     0    stevel 	nulldev,		/* close()		*/
    152     0    stevel 	nodev,			/* strategy()		*/
    153     0    stevel 	nodev,			/* print()		*/
    154     0    stevel 	nodev,			/* dump()		*/
    155     0    stevel 	nodev,			/* read()		*/
    156     0    stevel 	nodev,			/* write()		*/
    157     0    stevel 	nodev,			/* ioctl()		*/
    158     0    stevel 	nodev,			/* devmap()		*/
    159     0    stevel 	nodev,			/* mmap()		*/
    160     0    stevel 	nodev,			/* segmap()		*/
    161     0    stevel 	nochpoll,		/* poll()		*/
    162     0    stevel 	ddi_prop_op,		/* prop_op()		*/
    163     0    stevel 	&qcnstrinfo,		/* cb_str		*/
    164     0    stevel 	D_NEW | D_MP		/* cb_flag		*/
    165     0    stevel };
    166     0    stevel 
    167     0    stevel static struct dev_ops qcn_ops = {
    168     0    stevel 	DEVO_REV,
    169     0    stevel 	0,			/* refcnt		*/
    170     0    stevel 	qcn_getinfo,		/* getinfo()		*/
    171     0    stevel 	nulldev,		/* identify()		*/
    172     0    stevel 	nulldev,		/* probe()		*/
    173     0    stevel 	qcn_attach,		/* attach()		*/
    174     0    stevel 	qcn_detach,		/* detach()		*/
    175     0    stevel 	nodev,			/* reset()		*/
    176     0    stevel 	&qcn_cb_ops,		/* cb_ops		*/
    177     0    stevel 	(struct bus_ops *)NULL,	/* bus_ops		*/
    178  7656    Sherry 	NULL,			/* power()		*/
    179  7656    Sherry 	ddi_quiesce_not_needed,		/* quiesce()		*/
    180     0    stevel };
    181     0    stevel 
    182     0    stevel static struct modldrv modldrv = {
    183     0    stevel 	&mod_driverops,
    184  7656    Sherry 	"sun4v console driver",
    185     0    stevel 	&qcn_ops
    186     0    stevel };
    187     0    stevel 
    188     0    stevel static struct modlinkage modlinkage = {
    189     0    stevel 	MODREV_1,
    190     0    stevel 	(void*)&modldrv,
    191     0    stevel 	NULL
    192     0    stevel };
    193     0    stevel 
    194     0    stevel /* driver configuration routines */
    195     0    stevel int
    196     0    stevel _init(void)
    197     0    stevel {
    198     0    stevel 	int error;
    199  2282  jb145095 	uint64_t	major, minor;
    200     0    stevel 
    201     0    stevel 	qcn_state = kmem_zalloc(sizeof (qcn_t), KM_SLEEP);
    202  2282  jb145095 	qcn_state->qcn_ring = contig_mem_alloc(RINGSIZE);
    203  2282  jb145095 	if (qcn_state->qcn_ring == NULL)
    204  2282  jb145095 		cmn_err(CE_PANIC, "console ring allocation failed");
    205     0    stevel 
    206     0    stevel 	error = mod_install(&modlinkage);
    207  2282  jb145095 	if (error != 0) {
    208  2282  jb145095 		contig_mem_free(qcn_state->qcn_ring, RINGSIZE);
    209     0    stevel 		kmem_free(qcn_state, sizeof (qcn_t));
    210  2282  jb145095 		return (error);
    211  2282  jb145095 	}
    212  2282  jb145095 	/*
    213  2282  jb145095 	 * check minor number to see if CONS_WRITE is supported
    214  2282  jb145095 	 * if so, set up real address of the buffers for hv calls.
    215  2282  jb145095 	 */
    216     0    stevel 
    217  2282  jb145095 	if (((hsvc_version(HSVC_GROUP_CORE, &major, &minor) == 0) &&
    218  7656    Sherry 	    (major == QCN_API_MAJOR) && (minor >= QCN_API_MINOR))) {
    219  2282  jb145095 		qcn_state->cons_write_buffer =
    220  7656    Sherry 		    contig_mem_alloc(CONS_WR_BUF_SIZE);
    221  2282  jb145095 		if (qcn_state->cons_write_buffer != NULL) {
    222  2282  jb145095 			qcn_state->cons_write_buf_ra =
    223  7656    Sherry 			    va_to_pa(qcn_state->cons_write_buffer);
    224  2282  jb145095 			qcn_state->cons_transmit = qcn_transmit_write;
    225  2282  jb145095 			qcn_state->cons_receive = qcn_receive_read;
    226  2282  jb145095 			qcn_state->cons_read_buf_ra =
    227  7656    Sherry 			    va_to_pa((char *)RING_ADDR(qcn_state));
    228  2282  jb145095 		}
    229  2282  jb145095 	}
    230  2282  jb145095 	if (qcn_state->cons_transmit == NULL) {
    231  2282  jb145095 		qcn_state->cons_transmit = qcn_transmit_putchr;
    232  2282  jb145095 		qcn_state->cons_receive = qcn_receive_getchr;
    233  2282  jb145095 	}
    234  2282  jb145095 	return (0);
    235     0    stevel }
    236     0    stevel 
    237     0    stevel int
    238     0    stevel _fini(void)
    239     0    stevel {
    240     0    stevel 	/* can't remove console driver */
    241     0    stevel 	return (EBUSY);
    242     0    stevel }
    243     0    stevel 
    244     0    stevel int
    245     0    stevel _info(struct modinfo *modinfop)
    246     0    stevel {
    247     0    stevel 	return (mod_info(&modlinkage, modinfop));
    248     0    stevel }
    249     0    stevel 
    250     0    stevel static int
    251     0    stevel qcn_add_intrs(void)
    252     0    stevel {
    253     0    stevel 	dev_info_t	*devinfo = qcn_state->qcn_dip;
    254     0    stevel 	int		actual, count = 0;
    255     0    stevel 	int 		x, y, rc, inum = 0;
    256     0    stevel 
    257     0    stevel 
    258     0    stevel 	/* get number of interrupts */
    259     0    stevel 	rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count);
    260     0    stevel 	if ((rc != DDI_SUCCESS) || (count == 0)) {
    261     0    stevel 		return (DDI_FAILURE);
    262     0    stevel 	}
    263     0    stevel 
    264     0    stevel 	/* Allocate an array of interrupt handles */
    265     0    stevel 	qcn_state->qcn_intr_size = count * sizeof (ddi_intr_handle_t);
    266     0    stevel 	qcn_state->qcn_htable = kmem_zalloc(qcn_state->qcn_intr_size, KM_SLEEP);
    267     0    stevel 
    268     0    stevel 	/* call ddi_intr_alloc() */
    269     0    stevel 	rc = ddi_intr_alloc(devinfo, qcn_state->qcn_htable,
    270     0    stevel 	    DDI_INTR_TYPE_FIXED, inum, count, &actual,
    271     0    stevel 	    DDI_INTR_ALLOC_STRICT);
    272     0    stevel 
    273     0    stevel 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
    274     0    stevel 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    275     0    stevel 		return (DDI_FAILURE);
    276     0    stevel 	}
    277     0    stevel 
    278     0    stevel 	if (actual < count) {
    279     0    stevel 		for (x = 0; x < actual; x++) {
    280     0    stevel 			(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    281     0    stevel 		}
    282     0    stevel 
    283     0    stevel 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    284     0    stevel 		return (DDI_FAILURE);
    285     0    stevel 	}
    286     0    stevel 
    287     0    stevel 	qcn_state->qcn_intr_cnt = actual;
    288     0    stevel 
    289     0    stevel 	/* Get intr priority */
    290     0    stevel 	if (ddi_intr_get_pri(qcn_state->qcn_htable[0],
    291     0    stevel 	    &qcn_state->qcn_intr_pri) != DDI_SUCCESS) {
    292     0    stevel 		for (x = 0; x < actual; x++) {
    293     0    stevel 			(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    294     0    stevel 		}
    295     0    stevel 
    296     0    stevel 		kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    297     0    stevel 		return (DDI_FAILURE);
    298     0    stevel 	}
    299     0    stevel 
    300     0    stevel 	/* Call ddi_intr_add_handler() */
    301     0    stevel 	for (x = 0; x < actual; x++) {
    302     0    stevel 		if (ddi_intr_add_handler(qcn_state->qcn_htable[x],
    303     0    stevel 		    (ddi_intr_handler_t *)qcn_hi_intr,
    304     0    stevel 		    (caddr_t)qcn_state, NULL) != DDI_SUCCESS) {
    305     0    stevel 
    306     0    stevel 			for (y = 0; y < x; y++) {
    307     0    stevel 				(void) ddi_intr_remove_handler(
    308     0    stevel 				    qcn_state->qcn_htable[y]);
    309     0    stevel 			}
    310     0    stevel 
    311     0    stevel 			for (y = 0; y < actual; y++) {
    312     0    stevel 				(void) ddi_intr_free(qcn_state->qcn_htable[y]);
    313     0    stevel 			}
    314     0    stevel 
    315     0    stevel 			kmem_free(qcn_state->qcn_htable,
    316     0    stevel 			    qcn_state->qcn_intr_size);
    317     0    stevel 			return (DDI_FAILURE);
    318     0    stevel 		}
    319     0    stevel 	}
    320     0    stevel 
    321     0    stevel 	return (DDI_SUCCESS);
    322     0    stevel }
    323     0    stevel 
    324     0    stevel static void
    325     0    stevel qcn_remove_intrs(void)
    326     0    stevel {
    327     0    stevel 	int x;
    328     0    stevel 	for (x = 0; x < qcn_state->qcn_intr_cnt; x++) {
    329     0    stevel 		(void) ddi_intr_disable(qcn_state->qcn_htable[x]);
    330     0    stevel 		(void) ddi_intr_remove_handler(qcn_state->qcn_htable[x]);
    331     0    stevel 		(void) ddi_intr_free(qcn_state->qcn_htable[x]);
    332     0    stevel 	}
    333   288      arao 	kmem_free(qcn_state->qcn_htable, qcn_state->qcn_intr_size);
    334     0    stevel }
    335     0    stevel 
    336     0    stevel static void
    337     0    stevel qcn_intr_enable(void)
    338     0    stevel {
    339     0    stevel 	int x;
    340     0    stevel 
    341     0    stevel 	for (x = 0; x < qcn_state->qcn_intr_cnt; x++) {
    342     0    stevel 		(void) ddi_intr_enable(qcn_state->qcn_htable[x]);
    343     0    stevel 	}
    344     0    stevel }
    345     0    stevel 
    346     0    stevel /*
    347     0    stevel  * qcn_attach is called at startup time.
    348     0    stevel  * There is only once instance of this driver.
    349     0    stevel  */
    350     0    stevel static int
    351     0    stevel qcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    352     0    stevel {
    353     0    stevel 	extern int ddi_create_internal_pathname(dev_info_t *, char *,
    354     0    stevel 	    int, minor_t);
    355     0    stevel 	uint_t soft_prip;
    356     0    stevel 
    357     0    stevel #ifdef QCN_POLLING
    358     0    stevel 	char *binding_name;
    359     0    stevel #endif
    360     0    stevel 	if (cmd != DDI_ATTACH)
    361     0    stevel 		return (DDI_FAILURE);
    362     0    stevel 
    363     0    stevel 	if (ddi_create_internal_pathname(dip, "qcn",
    364     0    stevel 	    S_IFCHR, 0) != DDI_SUCCESS)
    365     0    stevel 		return (DDI_FAILURE);
    366     0    stevel 
    367     0    stevel 	qcn_state->qcn_soft_pend = 0;
    368     0    stevel 	qcn_state->qcn_hangup = 0;
    369     0    stevel 	qcn_state->qcn_rbuf_overflow = 0;
    370     0    stevel 
    371     0    stevel 	/* prepare some data structures in soft state */
    372     0    stevel 
    373     0    stevel 	qcn_state->qcn_dip = dip;
    374     0    stevel 
    375     0    stevel 	qcn_state->qcn_polling = 0;
    376     0    stevel 
    377     0    stevel #ifdef QCN_POLLING
    378     0    stevel 	/*
    379     0    stevel 	 * This test is for the sole purposes of allowing
    380     0    stevel 	 * the console to work on older firmware releases.
    381     0    stevel 	 */
    382     0    stevel 	binding_name = ddi_binding_name(qcn_state->qcn_dip);
    383  1991     heppo 	if ((strcmp(binding_name, "qcn") == 0) ||
    384  1991     heppo 	    (qcn_force_polling))
    385     0    stevel 		qcn_state->qcn_polling = 1;
    386     0    stevel 
    387     0    stevel 	if (qcn_state->qcn_polling) {
    388     0    stevel 		qcn_poll_time.cyt_when = 0ull;
    389     0    stevel 		qcn_poll_time.cyt_interval =
    390     0    stevel 		    qcn_poll_interval * 1000ull * 1000ull;
    391     0    stevel 		mutex_enter(&cpu_lock);
    392     0    stevel 		qcn_poll_cycid = cyclic_add(&qcn_poll_cychandler,
    393     0    stevel 		    &qcn_poll_time);
    394     0    stevel 		mutex_exit(&cpu_lock);
    395     0    stevel 	}
    396     0    stevel #endif
    397     0    stevel 
    398     0    stevel 	if (!qcn_state->qcn_polling) {
    399     0    stevel 		if (qcn_add_intrs() != DDI_SUCCESS) {
    400     0    stevel 			cmn_err(CE_WARN, "qcn_attach: add_intr failed\n");
    401     0    stevel 			return (DDI_FAILURE);
    402     0    stevel 		}
    403     0    stevel 		if (ddi_intr_add_softint(dip, &qcn_state->qcn_softint_hdl,
    404     0    stevel 		    DDI_INTR_SOFTPRI_MAX, qcn_soft_intr,
    405     0    stevel 		    (caddr_t)qcn_state) != DDI_SUCCESS) {
    406     0    stevel 			cmn_err(CE_WARN, "qcn_attach: add_soft_intr failed\n");
    407     0    stevel 			qcn_remove_intrs();
    408     0    stevel 			return (DDI_FAILURE);
    409     0    stevel 		}
    410     0    stevel 		if (ddi_intr_get_softint_pri(qcn_state->qcn_softint_hdl,
    411     0    stevel 		    &soft_prip) != DDI_SUCCESS) {
    412     0    stevel 			cmn_err(CE_WARN, "qcn_attach: softint_pri failed\n");
    413   288      arao 			(void) ddi_intr_remove_softint(
    414   288      arao 			    qcn_state->qcn_softint_hdl);
    415     0    stevel 			qcn_remove_intrs();
    416     0    stevel 			return (DDI_FAILURE);
    417     0    stevel 		}
    418     0    stevel 
    419  2954  jb145095 	mutex_init(&qcn_state->qcn_hi_lock, NULL, MUTEX_DRIVER,
    420  2954  jb145095 	    (void *)(uintptr_t)(qcn_state->qcn_intr_pri));
    421     0    stevel 	}
    422     0    stevel 
    423     0    stevel 	mutex_init(&qcn_state->qcn_lock, NULL, MUTEX_DRIVER, NULL);
    424  5974   jm22469 
    425  5974   jm22469 	/*
    426  5974   jm22469 	 * Fill in the polled I/O structure.
    427  5974   jm22469 	 */
    428  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_version = CONSPOLLEDIO_V1;
    429  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_argument =
    430  5974   jm22469 	    (cons_polledio_arg_t)qcn_state;
    431  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_putchar = qcn_polledio_putchar;
    432  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_getchar = qcn_polledio_getchar;
    433  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_ischar = qcn_polledio_ischar;
    434  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_enter = qcn_polledio_enter;
    435  5974   jm22469 	qcn_state->qcn_polledio.cons_polledio_exit = qcn_polledio_exit;
    436     0    stevel 
    437     0    stevel 	/*
    438     0    stevel 	 *  Enable  interrupts
    439     0    stevel 	 */
    440     0    stevel 	if (!qcn_state->qcn_polling) {
    441     0    stevel 		qcn_intr_enable();
    442     0    stevel 	}
    443     0    stevel #ifdef QCN_DEBUG
    444     0    stevel 	prom_printf("qcn_attach(): qcn driver attached\n");
    445     0    stevel #endif
    446     0    stevel 
    447     0    stevel 	return (DDI_SUCCESS);
    448     0    stevel 
    449     0    stevel }
    450     0    stevel 
    451     0    stevel /* ARGSUSED */
    452     0    stevel static int
    453     0    stevel qcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    454     0    stevel {
    455     0    stevel 
    456     0    stevel 	if (cmd != DDI_DETACH)
    457     0    stevel 		return (DDI_FAILURE);
    458     0    stevel 
    459     0    stevel 
    460     0    stevel #ifdef QCN_DEBUG
    461     0    stevel 	prom_printf("qcn_detach(): QCN driver detached\n");
    462     0    stevel #endif
    463     0    stevel 
    464     0    stevel #ifdef QCN_POLLING
    465     0    stevel 	if (qcn_state->qcn_polling) {
    466     0    stevel 		mutex_enter(&cpu_lock);
    467     0    stevel 		if (qcn_poll_cycid != CYCLIC_NONE)
    468     0    stevel 			cyclic_remove(qcn_poll_cycid);
    469     0    stevel 		qcn_poll_cycid = CYCLIC_NONE;
    470     0    stevel 		mutex_exit(&cpu_lock);
    471     0    stevel 	}
    472     0    stevel #endif
    473     0    stevel 
    474  2954  jb145095 	if (!qcn_state->qcn_polling)
    475     0    stevel 		qcn_remove_intrs();
    476     0    stevel 
    477     0    stevel 	return (DDI_SUCCESS);
    478     0    stevel }
    479     0    stevel 
    480     0    stevel /* ARGSUSED */
    481     0    stevel static int
    482     0    stevel qcn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
    483     0    stevel {
    484     0    stevel 	int error = DDI_FAILURE;
    485     0    stevel 	int instance = 0;
    486     0    stevel 	switch (infocmd) {
    487     0    stevel 	case DDI_INFO_DEVT2DEVINFO:
    488     0    stevel 		if (qcn_state) {
    489     0    stevel #ifdef QCN_DEBUG
    490     0    stevel 			prom_printf("qcn_getinfo(): devt2dip %lx\n", arg);
    491     0    stevel #endif
    492     0    stevel 			*result = (void *)qcn_state->qcn_dip;
    493     0    stevel 			error = DDI_SUCCESS;
    494     0    stevel 		}
    495     0    stevel 		break;
    496     0    stevel 
    497     0    stevel 	case DDI_INFO_DEVT2INSTANCE:
    498     0    stevel #ifdef QCN_DEBUG
    499     0    stevel 		prom_printf("qcn_getinfo(): devt2instance %lx\n", arg);
    500     0    stevel #endif
    501     0    stevel 		if (getminor((dev_t)arg) == 0) {
    502   911   iskreen 			*result = (void *)(uintptr_t)instance;
    503     0    stevel 			error = DDI_SUCCESS;
    504     0    stevel 		}
    505     0    stevel 		break;
    506     0    stevel 	}
    507     0    stevel 
    508     0    stevel 	return (error);
    509     0    stevel }
    510     0    stevel 
    511     0    stevel /* streams open & close */
    512     0    stevel /* ARGSUSED */
    513     0    stevel static int
    514     0    stevel qcn_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
    515     0    stevel {
    516     0    stevel 	tty_common_t *tty;
    517     0    stevel 	int unit = getminor(*devp);
    518     0    stevel 
    519     0    stevel #ifdef QCN_DEBUG
    520     0    stevel 	prom_printf("qcn_open(): minor %x\n", unit);
    521     0    stevel #endif
    522     0    stevel 
    523     0    stevel 	if (unit != 0)
    524     0    stevel 		return (ENXIO);
    525     0    stevel 
    526     0    stevel 	/* stream already open */
    527     0    stevel 	if (q->q_ptr != NULL)
    528     0    stevel 		return (DDI_SUCCESS);
    529     0    stevel 
    530     0    stevel 	if (!qcn_state) {
    531     0    stevel 		cmn_err(CE_WARN, "qcn_open: console was not configured by "
    532     0    stevel 		    "autoconfig\n");
    533     0    stevel 		return (ENXIO);
    534     0    stevel 	}
    535     0    stevel 
    536     0    stevel 	mutex_enter(&qcn_state->qcn_lock);
    537     0    stevel 	tty = &(qcn_state->qcn_tty);
    538     0    stevel 
    539     0    stevel 	tty->t_readq = q;
    540     0    stevel 	tty->t_writeq = WR(q);
    541     0    stevel 
    542     0    stevel 	/* Link the RD and WR Q's */
    543     0    stevel 	q->q_ptr = WR(q)->q_ptr = (caddr_t)qcn_state;
    544     0    stevel 	qcn_state->qcn_readq = RD(q);
    545     0    stevel 	qcn_state->qcn_writeq = WR(q);
    546     0    stevel 	qprocson(q);
    547     0    stevel 
    548     0    stevel 	mutex_exit(&qcn_state->qcn_lock);
    549     0    stevel 
    550     0    stevel #ifdef QCN_DEBUG
    551     0    stevel 	prom_printf("qcn_open: opened as dev %lx\n", *devp);
    552     0    stevel #endif
    553     0    stevel 
    554     0    stevel 	return (DDI_SUCCESS);
    555     0    stevel }
    556     0    stevel 
    557     0    stevel /* ARGSUSED */
    558     0    stevel static int
    559     0    stevel qcn_close(queue_t *q, int flag, cred_t *credp)
    560     0    stevel {
    561     0    stevel 
    562     0    stevel 	ASSERT(qcn_state == q->q_ptr);
    563     0    stevel 
    564     0    stevel 	if (qcn_state->qcn_wbufcid != 0) {
    565     0    stevel 		unbufcall(qcn_state->qcn_wbufcid);
    566     0    stevel 	}
    567     0    stevel 	ttycommon_close(&qcn_state->qcn_tty);
    568     0    stevel 
    569     0    stevel 	qprocsoff(q);
    570     0    stevel 	q->q_ptr = WR(q)->q_ptr = NULL;
    571     0    stevel 	qcn_state->qcn_readq = NULL;
    572     0    stevel 	qcn_state->qcn_writeq = NULL;
    573     0    stevel 
    574     0    stevel 	return (DDI_SUCCESS);
    575     0    stevel }
    576     0    stevel 
    577     0    stevel /*
    578     0    stevel  * Put procedure for write queue.
    579     0    stevel  * Respond to M_IOCTL, M_DATA and M_FLUSH messages here;
    580     0    stevel  * It put's the data onto internal qcn_output_q.
    581     0    stevel  */
    582     0    stevel static int
    583     0    stevel qcn_wput(queue_t *q, mblk_t *mp)
    584     0    stevel {
    585     0    stevel 
    586     0    stevel #ifdef QCN_DEBUG
    587     0    stevel 	struct iocblk *iocp;
    588     0    stevel 	int i;
    589     0    stevel #endif
    590     0    stevel 
    591     0    stevel 	ASSERT(qcn_state == q->q_ptr);
    592     0    stevel 
    593     0    stevel 	if (!mp->b_datap) {
    594     0    stevel 		cmn_err(CE_PANIC, "qcn_wput: null datap");
    595     0    stevel 	}
    596     0    stevel 
    597     0    stevel #ifdef QCN_DEBUG
    598     0    stevel 	prom_printf("qcn_wput(): QCN wput q=%X mp=%X rd=%X wr=%X type=%X\n",
    599  7656    Sherry 	    q, mp, mp->b_rptr, mp->b_wptr, mp->b_datap->db_type);
    600     0    stevel #endif
    601     0    stevel 
    602     0    stevel 	mutex_enter(&qcn_state->qcn_lock);
    603     0    stevel 
    604     0    stevel 	switch (mp->b_datap->db_type) {
    605     0    stevel 	case M_IOCTL:
    606     0    stevel 	case M_CTL:
    607     0    stevel #ifdef QCN_DEBUG
    608     0    stevel 		iocp = (struct iocblk *)mp->b_rptr;
    609     0    stevel 		prom_printf("qcn_wput(): M_IOCTL cmd=%X TIOC=%X\n",
    610     0    stevel 		    iocp->ioc_cmd, TIOC);
    611     0    stevel #endif
    612     0    stevel 		switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
    613     0    stevel 		case TCSETSW:
    614     0    stevel 		case TCSETSF:
    615     0    stevel 		case TCSETAW:
    616     0    stevel 		case TCSETAF:
    617     0    stevel 		case TCSBRK:
    618     0    stevel 			/*
    619     0    stevel 			 * The change do not take effect until all
    620     0    stevel 			 * output queued before them is drained.
    621     0    stevel 			 * Put this message on the queue, so that
    622     0    stevel 			 * "qcn_start" will see it when it's done
    623     0    stevel 			 * with the output before it. Poke the start
    624     0    stevel 			 * routine, just in case.
    625     0    stevel 			 */
    626     0    stevel 			(void) putq(q, mp);
    627     0    stevel 			qcn_start();
    628     0    stevel 			break;
    629     0    stevel 		default:
    630  3419  jb145095 			mutex_exit(&qcn_state->qcn_lock);
    631     0    stevel 			qcn_ioctl(q, mp);
    632  3419  jb145095 			mutex_enter(&qcn_state->qcn_lock);
    633     0    stevel 		}
    634     0    stevel 		break;
    635     0    stevel 
    636     0    stevel 	case M_FLUSH:
    637     0    stevel 		if (*mp->b_rptr & FLUSHW) {
    638     0    stevel 			flushq(q, FLUSHDATA);
    639     0    stevel 			*mp->b_rptr &= ~FLUSHW;
    640     0    stevel 		}
    641     0    stevel 		if (*mp->b_rptr & FLUSHR) {
    642     0    stevel 			flushq(RD(q), FLUSHDATA);
    643     0    stevel 			qreply(q, mp);
    644     0    stevel 		} else {
    645     0    stevel 			freemsg(mp);
    646     0    stevel 		}
    647     0    stevel 		break;
    648     0    stevel 
    649     0    stevel 	case M_STOP:
    650     0    stevel 		qcn_stopped = B_TRUE;
    651     0    stevel 		freemsg(mp);
    652     0    stevel 		break;
    653     0    stevel 
    654     0    stevel 	case M_START:
    655     0    stevel 		qcn_stopped = B_FALSE;
    656     0    stevel 		freemsg(mp);
    657     0    stevel 		qenable(q);	/* Start up delayed messages */
    658     0    stevel 		break;
    659     0    stevel 
    660     0    stevel 	case M_DATA:
    661     0    stevel 		/*
    662     0    stevel 		 * Queue the message up to be transmitted,
    663     0    stevel 		 * and poke the start routine.
    664     0    stevel 		 */
    665     0    stevel #ifdef QCN_DEBUG
    666     0    stevel 		if (mp->b_rptr < mp->b_wptr) {
    667     0    stevel 		prom_printf("qcn_wput(): DATA q=%X mp=%X rd=%X wr=%X\n",
    668  7656    Sherry 		    q, mp, mp->b_rptr, mp->b_wptr);
    669     0    stevel 		prom_printf("qcn_wput(): [");
    670     0    stevel 		for (i = 0; i < mp->b_wptr-mp->b_rptr; i++) {
    671     0    stevel 			prom_printf("%c", *(mp->b_rptr+i));
    672     0    stevel 		}
    673     0    stevel 		prom_printf("]\n");
    674     0    stevel 		}
    675     0    stevel #endif /* QCN_DEBUG */
    676     0    stevel 		(void) putq(q, mp);
    677     0    stevel 		qcn_start();
    678     0    stevel 		break;
    679     0    stevel 
    680     0    stevel 	default:
    681     0    stevel 		freemsg(mp);
    682     0    stevel 	}
    683     0    stevel 
    684     0    stevel 	mutex_exit(&qcn_state->qcn_lock);
    685  3419  jb145095 
    686     0    stevel 	return (0);
    687     0    stevel }
    688     0    stevel 
    689     0    stevel /*
    690     0    stevel  * Process an "ioctl" message sent down to us.
    691     0    stevel  */
    692     0    stevel static void
    693     0    stevel qcn_ioctl(queue_t *q, mblk_t *mp)
    694     0    stevel {
    695     0    stevel 	struct iocblk	*iocp;
    696     0    stevel 	tty_common_t	*tty;
    697     0    stevel 	mblk_t		*datamp;
    698     0    stevel 	int		data_size;
    699     0    stevel 	int		error = 0;
    700     0    stevel 
    701     0    stevel #ifdef QCN_DEBUG
    702     0    stevel 	prom_printf("qcn_ioctl(): q=%X mp=%X\n", q, mp);
    703     0    stevel #endif
    704     0    stevel 
    705     0    stevel 	iocp = (struct iocblk *)mp->b_rptr;
    706  5974   jm22469 
    707     0    stevel 	tty = &(qcn_state->qcn_tty);
    708     0    stevel 
    709     0    stevel 	if (tty->t_iocpending != NULL) {
    710     0    stevel 		freemsg(tty->t_iocpending);
    711     0    stevel 		tty->t_iocpending = NULL;
    712     0    stevel 	}
    713  5974   jm22469 
    714  5974   jm22469 	/*
    715  5974   jm22469 	 * Handle the POLLEDIO ioctls now because ttycommon_ioctl
    716  5974   jm22469 	 * (below) frees up the message block (mp->b_cont) which
    717  5974   jm22469 	 * contains the pointer used to pass back results.
    718  5974   jm22469 	 */
    719  5974   jm22469 	switch (iocp->ioc_cmd) {
    720  5974   jm22469 	case CONSOPENPOLLEDIO:
    721  5974   jm22469 		error = miocpullup(mp, sizeof (struct cons_polledio *));
    722  5974   jm22469 		if (error != 0)
    723  5974   jm22469 			break;
    724  5974   jm22469 
    725  5974   jm22469 		*(struct cons_polledio **)mp->b_cont->b_rptr =
    726  5974   jm22469 		    &qcn_state->qcn_polledio;
    727  5974   jm22469 
    728  5974   jm22469 		mp->b_datap->db_type = M_IOCACK;
    729  5974   jm22469 		break;
    730  5974   jm22469 
    731  5974   jm22469 	case CONSCLOSEPOLLEDIO:
    732  5974   jm22469 		mp->b_datap->db_type = M_IOCACK;
    733  5974   jm22469 		iocp->ioc_error = 0;
    734  5974   jm22469 		iocp->ioc_rval = 0;
    735  5974   jm22469 		break;
    736  5974   jm22469 
    737  5974   jm22469 	default:
    738  5974   jm22469 		data_size = ttycommon_ioctl(tty, q, mp, &error);
    739  5974   jm22469 		if (data_size != 0) {
    740  5974   jm22469 			if (qcn_state->qcn_wbufcid)
    741  5974   jm22469 				unbufcall(qcn_state->qcn_wbufcid);
    742  5974   jm22469 			/* call qcn_reioctl() */
    743  5974   jm22469 			qcn_state->qcn_wbufcid =
    744  5974   jm22469 			    bufcall(data_size, BPRI_HI, qcn_reioctl, qcn_state);
    745  5974   jm22469 			return;
    746  5974   jm22469 		}
    747     0    stevel 	}
    748  3419  jb145095 
    749  3419  jb145095 	mutex_enter(&qcn_state->qcn_lock);
    750     0    stevel 
    751     0    stevel 	if (error < 0) {
    752     0    stevel 		iocp = (struct iocblk *)mp->b_rptr;
    753     0    stevel 		/*
    754     0    stevel 		 * "ttycommon_ioctl" didn't do anything; we process it here.
    755     0    stevel 		 */
    756     0    stevel 		error = 0;
    757     0    stevel 		switch (iocp->ioc_cmd) {
    758     0    stevel 		case TCSBRK:
    759     0    stevel 		case TIOCSBRK:
    760     0    stevel 		case TIOCCBRK:
    761     0    stevel 		case TIOCMSET:
    762     0    stevel 		case TIOCMBIS:
    763     0    stevel 		case TIOCMBIC:
    764     0    stevel 			if (iocp->ioc_count != TRANSPARENT)
    765     0    stevel 				qcn_ack(mp, NULL, 0);
    766     0    stevel 			else
    767     0    stevel 				mcopyin(mp, NULL, sizeof (int), NULL);
    768     0    stevel 			break;
    769     0    stevel 
    770     0    stevel 		case TIOCMGET:
    771     0    stevel 			datamp = allocb(sizeof (int), BPRI_MED);
    772     0    stevel 			if (datamp == NULL) {
    773     0    stevel 				error = EAGAIN;
    774     0    stevel 				break;
    775     0    stevel 			}
    776     0    stevel 
    777     0    stevel 			*(int *)datamp->b_rptr = 0;
    778     0    stevel 
    779     0    stevel 			if (iocp->ioc_count != TRANSPARENT)
    780     0    stevel 				qcn_ack(mp, datamp, sizeof (int));
    781     0    stevel 			else
    782     0    stevel 				mcopyout(mp, NULL, sizeof (int), NULL, datamp);
    783     0    stevel 			break;
    784     0    stevel 
    785     0    stevel 		default:
    786     0    stevel 			error = EINVAL;
    787     0    stevel 			break;
    788     0    stevel 		}
    789     0    stevel 	}
    790     0    stevel 	if (error != 0) {
    791     0    stevel 		iocp->ioc_count = 0;
    792     0    stevel 		iocp->ioc_error = error;
    793     0    stevel 		mp->b_datap->db_type = M_IOCNAK;
    794     0    stevel 	}
    795  3419  jb145095 	mutex_exit(&qcn_state->qcn_lock);
    796     0    stevel 	qreply(q, mp);
    797     0    stevel }
    798     0    stevel 
    799     0    stevel static void
    800     0    stevel qcn_reioctl(void *unit)
    801     0    stevel {
    802     0    stevel 	queue_t		*q;
    803     0    stevel 	mblk_t		*mp;
    804     0    stevel 	qcn_t		*qcnp = (qcn_t *)unit;
    805     0    stevel 
    806     0    stevel 	if (!qcnp->qcn_wbufcid)
    807     0    stevel 		return;
    808     0    stevel 
    809     0    stevel 	qcnp->qcn_wbufcid = 0;
    810     0    stevel 	if ((q = qcnp->qcn_tty.t_writeq) == NULL)
    811     0    stevel 		return;
    812     0    stevel 
    813     0    stevel 	if ((mp = qcnp->qcn_tty.t_iocpending) == NULL)
    814     0    stevel 		return;
    815     0    stevel 
    816     0    stevel 	qcnp->qcn_tty.t_iocpending = NULL;
    817     0    stevel 	qcn_ioctl(q, mp);
    818     0    stevel }
    819     0    stevel 
    820     0    stevel static void
    821     0    stevel qcn_ack(mblk_t *mp, mblk_t *dp, uint_t size)
    822     0    stevel {
    823     0    stevel 	struct iocblk  *iocp = (struct iocblk *)mp->b_rptr;
    824     0    stevel 
    825     0    stevel 	mp->b_datap->db_type = M_IOCACK;
    826     0    stevel 	iocp->ioc_count = size;
    827     0    stevel 	iocp->ioc_error = 0;
    828     0    stevel 	iocp->ioc_rval = 0;
    829     0    stevel 	if (mp->b_cont != NULL)
    830     0    stevel 		freeb(mp->b_cont);
    831     0    stevel 	if (dp != NULL) {
    832     0    stevel 		mp->b_cont = dp;
    833     0    stevel 		dp->b_wptr += size;
    834     0    stevel 	} else
    835     0    stevel 		mp->b_cont = NULL;
    836     0    stevel }
    837     0    stevel 
    838     0    stevel static void
    839     0    stevel qcn_start(void)
    840     0    stevel {
    841     0    stevel 
    842     0    stevel 	queue_t *q;
    843     0    stevel 	mblk_t *mp;
    844     0    stevel 	int rv;
    845     0    stevel 
    846     0    stevel 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
    847     0    stevel 
    848     0    stevel 	/*
    849     0    stevel 	 * read stream queue and remove data from the queue and
    850     0    stevel 	 * transmit them if possible
    851     0    stevel 	 */
    852     0    stevel 	q = qcn_state->qcn_writeq;
    853     0    stevel 	ASSERT(q != NULL);
    854     0    stevel 	while (mp = getq(q)) {
    855     0    stevel 		if (mp->b_datap->db_type == M_IOCTL) {
    856     0    stevel 			/*
    857     0    stevel 			 * These are those IOCTLs queued up
    858     0    stevel 			 * do it now
    859     0    stevel 			 */
    860  3419  jb145095 			mutex_exit(&qcn_state->qcn_lock);
    861     0    stevel 			qcn_ioctl(q, mp);
    862  3419  jb145095 			mutex_enter(&qcn_state->qcn_lock);
    863     0    stevel 			continue;
    864     0    stevel 		}
    865     0    stevel 		/*
    866     0    stevel 		 * M_DATA
    867     0    stevel 		 */
    868  2282  jb145095 		rv = qcn_state->cons_transmit(q, mp);
    869     0    stevel 		if (rv == EBUSY || rv == EAGAIN)
    870     0    stevel 			return;
    871     0    stevel 	}
    872     0    stevel }
    873     0    stevel 
    874     0    stevel static int
    875  2282  jb145095 qcn_transmit_write(queue_t *q, mblk_t *mp)
    876     0    stevel {
    877  2282  jb145095 	mblk_t		*bp;
    878  2282  jb145095 	size_t		len;
    879  2282  jb145095 	uint64_t	i;
    880  2282  jb145095 	uint64_t	retval = 0;
    881     0    stevel 
    882     0    stevel #ifdef QCN_DEBUG
    883  2282  jb145095 	prom_printf("qcn_transmit_write(): q=%X mp=%X\n", q, mp);
    884     0    stevel #endif
    885  2282  jb145095 
    886  2282  jb145095 	while (mp) {
    887  2282  jb145095 		bp = mp;
    888  2282  jb145095 		len = bp->b_wptr - bp->b_rptr;
    889  2282  jb145095 		/*
    890  2282  jb145095 		 * Use the console write call to send a block of characters to
    891  2282  jb145095 		 * the console.
    892  2282  jb145095 		 */
    893  2282  jb145095 		i = (len > CONS_WR_BUF_SIZE) ? CONS_WR_BUF_SIZE : len;
    894  2282  jb145095 		bcopy(bp->b_rptr, qcn_state->cons_write_buffer, i);
    895  2282  jb145095 		retval = hv_cnwrite(qcn_state->cons_write_buf_ra, i, &i);
    896  2282  jb145095 
    897  2282  jb145095 		if (retval == H_EOK) {
    898  2282  jb145095 			len -= i;
    899  2282  jb145095 			bp->b_rptr += i;
    900  2282  jb145095 			/*
    901  2282  jb145095 			 * if we have finished with this buf, free
    902  2282  jb145095 			 * and get the next buf if present.
    903  2282  jb145095 			 */
    904  2282  jb145095 			if (len == 0) {
    905  2282  jb145095 				mp = bp->b_cont;
    906  2282  jb145095 				freeb(bp);
    907  2282  jb145095 			}
    908  2282  jb145095 		} else {
    909  2282  jb145095 			(void) putbq(q, mp);
    910  2282  jb145095 
    911  2282  jb145095 			switch (retval) {
    912  2282  jb145095 
    913  2282  jb145095 			case H_EWOULDBLOCK :
    914  2282  jb145095 				/*
    915  2282  jb145095 				 * hypervisor cannot process the request -
    916  2282  jb145095 				 * channel busy.  Try again later.
    917  2282  jb145095 				 */
    918  2282  jb145095 				return (EAGAIN);
    919  2282  jb145095 
    920  2282  jb145095 			case H_EIO :
    921  2282  jb145095 				return (EIO);
    922  2282  jb145095 			default :
    923  2282  jb145095 				return (ENXIO);
    924  2282  jb145095 			}
    925  2282  jb145095 		}
    926  2282  jb145095 	}
    927  2282  jb145095 	return (0);
    928  2282  jb145095 }
    929  2282  jb145095 
    930  2282  jb145095 static int
    931  2282  jb145095 qcn_transmit_putchr(queue_t *q, mblk_t *mp)
    932  2282  jb145095 {
    933  2282  jb145095 	caddr_t		buf;
    934  2282  jb145095 	mblk_t		*bp;
    935  2282  jb145095 	size_t		len;
    936  2282  jb145095 	uint64_t	i;
    937  2282  jb145095 
    938  2282  jb145095 #ifdef QCN_DEBUG
    939  2282  jb145095 	prom_printf("qcn_transmit_putchr(): q=%X mp=%X\n", q, mp);
    940  2282  jb145095 #endif
    941  2282  jb145095 	while (mp) {
    942     0    stevel 		bp = mp;
    943     0    stevel 		len = bp->b_wptr - bp->b_rptr;
    944     0    stevel 		buf = (caddr_t)bp->b_rptr;
    945     0    stevel 		for (i = 0; i < len; i++) {
    946  2954  jb145095 			if (hv_cnputchar(buf[i]) == H_EWOULDBLOCK)
    947  2531   narayan 				break;
    948     0    stevel 		}
    949     0    stevel 		if (i != len) {
    950     0    stevel 			bp->b_rptr += i;
    951     0    stevel 			(void) putbq(q, mp);
    952     0    stevel 			return (EAGAIN);
    953     0    stevel 		}
    954     0    stevel 		mp = bp->b_cont;
    955     0    stevel 		freeb(bp);
    956  2282  jb145095 	}
    957     0    stevel 	return (0);
    958     0    stevel }
    959     0    stevel 
    960     0    stevel /*
    961     0    stevel  * called when SC first establishes console connection
    962     0    stevel  * drop all the data on the output queue
    963     0    stevel  */
    964     0    stevel static void
    965     0    stevel qcn_flush(void)
    966     0    stevel {
    967     0    stevel 	queue_t *q;
    968     0    stevel 	mblk_t *mp;
    969     0    stevel 
    970     0    stevel 	ASSERT(MUTEX_HELD(&qcn_state->qcn_lock));
    971     0    stevel 
    972     0    stevel 	q = qcn_state->qcn_writeq;
    973     0    stevel 
    974   911   iskreen 	prom_printf("qcn_flush(): WARNING console output is dropped time=%lx\n",
    975     0    stevel 	    gethrestime_sec());
    976     0    stevel 	while (mp = getq(q))
    977     0    stevel 		freemsg(mp);
    978     0    stevel }
    979     0    stevel 
    980     0    stevel static void
    981     0    stevel qcn_trigger_softint(void)
    982     0    stevel {
    983  2282  jb145095 	/*
    984  2282  jb145095 	 * if we are not currently servicing a software interrupt
    985  2282  jb145095 	 * (qcn_soft_pend == 0), trigger the service routine to run.
    986  2282  jb145095 	 */
    987  2432  jb145095 	if (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_DO) ==
    988  7656    Sherry 	    QCN_SP_IDL) {
    989  2282  jb145095 		(void) ddi_intr_trigger_softint(
    990  7656    Sherry 		    qcn_state->qcn_softint_hdl, NULL);
    991     0    stevel 	}
    992     0    stevel }
    993     0    stevel 
    994     0    stevel /*ARGSUSED*/
    995     0    stevel static uint_t
    996     0    stevel qcn_soft_intr(caddr_t arg1, caddr_t arg2)
    997     0    stevel {
    998     0    stevel 	mblk_t *mp;
    999     0    stevel 	int	cc;
   1000  2282  jb145095 	int	overflow_check;
   1001     0    stevel 
   1002  2282  jb145095 	do {
   1003  2432  jb145095 		(void) atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IP);
   1004  2282  jb145095 		mutex_enter(&qcn_state->qcn_hi_lock);
   1005  3419  jb145095 		cc = RING_CNT(qcn_state);
   1006  3419  jb145095 		mutex_exit(&qcn_state->qcn_hi_lock);
   1007  3419  jb145095 		if (cc <= 0) {
   1008  2282  jb145095 			goto out;
   1009  2282  jb145095 		}
   1010  2282  jb145095 
   1011  2282  jb145095 		if ((mp = allocb(cc, BPRI_MED)) == NULL) {
   1012  3419  jb145095 			mutex_enter(&qcn_state->qcn_hi_lock);
   1013  2282  jb145095 			qcn_input_dropped += cc;
   1014  2282  jb145095 			mutex_exit(&qcn_state->qcn_hi_lock);
   1015  2282  jb145095 			cmn_err(CE_WARN, "qcn_intr: allocb"
   1016  2282  jb145095 			    "failed (console input dropped)");
   1017  2282  jb145095 			goto out;
   1018  2282  jb145095 		}
   1019  2282  jb145095 
   1020  3419  jb145095 		mutex_enter(&qcn_state->qcn_hi_lock);
   1021  2282  jb145095 		do {
   1022  2282  jb145095 			/* put console input onto stream */
   1023  2282  jb145095 			*(char *)mp->b_wptr++ = RING_GET(qcn_state);
   1024  2282  jb145095 		} while (--cc);
   1025  2282  jb145095 
   1026  2282  jb145095 		if ((overflow_check = qcn_state->qcn_rbuf_overflow) != 0) {
   1027  2282  jb145095 			qcn_state->qcn_rbuf_overflow = 0;
   1028  2282  jb145095 		}
   1029     0    stevel 		mutex_exit(&qcn_state->qcn_hi_lock);
   1030     0    stevel 
   1031  2282  jb145095 		if (overflow_check) {
   1032  2282  jb145095 			cmn_err(CE_WARN, "qcn: Ring buffer overflow\n");
   1033  2282  jb145095 		}
   1034     0    stevel 
   1035  2282  jb145095 		if (qcn_state->qcn_readq) {
   1036  2282  jb145095 			putnext(qcn_state->qcn_readq, mp);
   1037  2282  jb145095 		}
   1038  2282  jb145095 out:
   1039  2954  jb145095 		/*
   1040  2954  jb145095 		 * If there are pending transmits because hypervisor
   1041  2954  jb145095 		 * returned EWOULDBLOCK poke start now.
   1042  2954  jb145095 		 */
   1043  2954  jb145095 
   1044  2954  jb145095 		if (qcn_state->qcn_writeq != NULL) {
   1045  2954  jb145095 			if (qcn_state->qcn_hangup) {
   1046  2954  jb145095 				(void) putctl(qcn_state->qcn_readq, M_HANGUP);
   1047  2282  jb145095 				flushq(qcn_state->qcn_writeq, FLUSHDATA);
   1048  2954  jb145095 				qcn_state->qcn_hangup = 0;
   1049  2954  jb145095 			} else {
   1050  2954  jb145095 				mutex_enter(&qcn_state->qcn_lock);
   1051  2954  jb145095 				qcn_start();
   1052  2954  jb145095 				mutex_exit(&qcn_state->qcn_lock);
   1053  2282  jb145095 			}
   1054     0    stevel 		}
   1055  2432  jb145095 		/*
   1056  2432  jb145095 		 * now loop if another interrupt came in (qcn_trigger_softint
   1057  2432  jb145095 		 * called) while we were processing the loop
   1058  2432  jb145095 		 */
   1059  2432  jb145095 	} while (atomic_swap_uint(&qcn_state->qcn_soft_pend, QCN_SP_IDL) ==
   1060  7656    Sherry 	    QCN_SP_DO);
   1061     0    stevel 	return (DDI_INTR_CLAIMED);
   1062     0    stevel }
   1063     0    stevel 
   1064     0    stevel /*ARGSUSED*/
   1065     0    stevel static uint_t
   1066     0    stevel qcn_hi_intr(caddr_t arg)
   1067     0    stevel {
   1068  2282  jb145095 	mutex_enter(&qcn_state->qcn_hi_lock);
   1069     0    stevel 
   1070  2282  jb145095 	qcn_state->cons_receive();
   1071     0    stevel 
   1072     0    stevel 	mutex_exit(&qcn_state->qcn_hi_lock);
   1073     0    stevel 	qcn_trigger_softint();
   1074     0    stevel 
   1075     0    stevel 	return (DDI_INTR_CLAIMED);
   1076  2282  jb145095 }
   1077  2282  jb145095 
   1078  2282  jb145095 static void
   1079  2282  jb145095 qcn_receive_read(void)
   1080  2282  jb145095 {
   1081  2282  jb145095 	int64_t rv;
   1082  2282  jb145095 	uint8_t *bufp;
   1083  2282  jb145095 	int64_t	retcount = 0;
   1084  2282  jb145095 	int	i;
   1085  2282  jb145095 
   1086  2282  jb145095 	do {
   1087  2282  jb145095 		/*
   1088  2282  jb145095 		 * Maximize available buffer size
   1089  2282  jb145095 		 */
   1090  2282  jb145095 		if (RING_CNT(qcn_state) <= 0) {
   1091  2282  jb145095 			RING_INIT(qcn_state);
   1092  2282  jb145095 		}
   1093  2282  jb145095 		rv = hv_cnread(qcn_state->cons_read_buf_ra +
   1094  7656    Sherry 		    RING_POFF(qcn_state),
   1095  7656    Sherry 		    RING_LEFT(qcn_state),
   1096  7656    Sherry 		    &retcount);
   1097  2282  jb145095 		bufp = RING_ADDR(qcn_state);
   1098  2282  jb145095 		if (rv == H_EOK) {
   1099  2282  jb145095 			/*
   1100  2282  jb145095 			 * if the alternate break sequence is enabled, test
   1101  2282  jb145095 			 * the buffer for the sequence and if it is there,
   1102  2282  jb145095 			 * enter the debugger.
   1103  2282  jb145095 			 */
   1104  2282  jb145095 			if (abort_enable == KIOCABORTALTERNATE) {
   1105  2282  jb145095 				for (i = 0; i < retcount; i++) {
   1106  2282  jb145095 					if (abort_charseq_recognize(*bufp++)) {
   1107  2282  jb145095 						abort_sequence_enter(
   1108  7656    Sherry 						    (char *)NULL);
   1109  2282  jb145095 					}
   1110  2282  jb145095 				}
   1111  2282  jb145095 			}
   1112  2282  jb145095 
   1113  2282  jb145095 			/* put console input onto stream */
   1114  2282  jb145095 			if (retcount > 0) {
   1115  2282  jb145095 				/*
   1116  2282  jb145095 				 * the characters are already in the ring,
   1117  2282  jb145095 				 * just update the pointer so the characters
   1118  2282  jb145095 				 * can be retrieved.
   1119  2282  jb145095 				 */
   1120  2282  jb145095 				RING_UPD(qcn_state, retcount);
   1121  2282  jb145095 			}
   1122  2282  jb145095 		} else {
   1123  2282  jb145095 			switch (rv) {
   1124  2282  jb145095 
   1125  2282  jb145095 			case H_EWOULDBLOCK :
   1126  2282  jb145095 				/*
   1127  2282  jb145095 				 * hypervisor cannot handle the request.
   1128  2282  jb145095 				 * Try again later.
   1129  2282  jb145095 				 */
   1130  2282  jb145095 				break;
   1131  2282  jb145095 
   1132  2282  jb145095 
   1133  2282  jb145095 			case H_BREAK :
   1134  2282  jb145095 				/*
   1135  9250   Zachary 				 * on break enter the debugger
   1136  2282  jb145095 				 */
   1137  9250   Zachary 				abort_sequence_enter((char *)NULL);
   1138  2282  jb145095 				break;
   1139  2282  jb145095 
   1140  2282  jb145095 			case H_HUP :
   1141  2282  jb145095 				qcn_state->qcn_hangup = 1;
   1142  2282  jb145095 				break;
   1143  2282  jb145095 
   1144  2282  jb145095 			default :
   1145  2282  jb145095 				break;
   1146  2282  jb145095 			}
   1147  2282  jb145095 		}
   1148  2282  jb145095 	} while (rv == H_EOK);
   1149  2282  jb145095 }
   1150  2282  jb145095 
   1151  2282  jb145095 static void
   1152  2282  jb145095 qcn_receive_getchr(void)
   1153  2282  jb145095 {
   1154  2282  jb145095 	int64_t rv;
   1155  2282  jb145095 	uint8_t	buf;
   1156  2282  jb145095 
   1157  2282  jb145095 	do {
   1158  2282  jb145095 		rv = hv_cngetchar(&buf);
   1159  2282  jb145095 		if (rv == H_EOK) {
   1160  2282  jb145095 			if (abort_enable == KIOCABORTALTERNATE) {
   1161  2282  jb145095 				if (abort_charseq_recognize(buf)) {
   1162  2282  jb145095 					abort_sequence_enter((char *)NULL);
   1163  2282  jb145095 				}
   1164  2282  jb145095 			}
   1165  2282  jb145095 
   1166  2282  jb145095 			/* put console input onto stream */
   1167  2282  jb145095 			if (RING_POK(qcn_state, 1)) {
   1168  2282  jb145095 				RING_PUT(qcn_state, buf);
   1169  2282  jb145095 			} else {
   1170  2282  jb145095 				qcn_state->qcn_rbuf_overflow++;
   1171  2282  jb145095 			}
   1172  2282  jb145095 		} else {
   1173  2282  jb145095 			if (rv == H_BREAK) {
   1174  9250   Zachary 				abort_sequence_enter((char *)NULL);
   1175  2282  jb145095 			}
   1176  2282  jb145095 
   1177  2282  jb145095 			if (rv == H_HUP)  {
   1178  2282  jb145095 				qcn_state->qcn_hangup = 1;
   1179  2282  jb145095 			}
   1180  2282  jb145095 			return;
   1181  2282  jb145095 		}
   1182  2282  jb145095 	} while (rv == H_EOK);
   1183     0    stevel }
   1184     0    stevel 
   1185     0    stevel #ifdef QCN_POLLING
   1186     0    stevel /*ARGSUSED*/
   1187     0    stevel static void
   1188     0    stevel qcn_poll_handler(void *unused)
   1189     0    stevel {
   1190     0    stevel 	mblk_t *mp;
   1191     0    stevel 	int64_t rv;
   1192     0    stevel 	uint8_t buf;
   1193     0    stevel 	int qcn_writeq_flush = 0;
   1194     0    stevel 
   1195     0    stevel 	/* LINTED: E_CONSTANT_CONDITION */
   1196     0    stevel 	while (1) {
   1197     0    stevel 		rv = hv_cngetchar(&buf);
   1198     0    stevel 		if (rv == H_BREAK) {
   1199  9250   Zachary 			abort_sequence_enter((char *)NULL);
   1200     0    stevel 		}
   1201     0    stevel 
   1202     0    stevel 		if (rv == H_HUP)  {
   1203     0    stevel 			if (qcn_state->qcn_readq) {
   1204     0    stevel 				(void) putctl(qcn_state->qcn_readq, M_HANGUP);
   1205     0    stevel 				qcn_writeq_flush = 1;
   1206     0    stevel 			}
   1207     0    stevel 			goto out;
   1208     0    stevel 		}
   1209     0    stevel 
   1210     0    stevel 		if (rv != H_EOK)
   1211     0    stevel 			goto out;
   1212     0    stevel 
   1213     0    stevel 		if (abort_enable == KIOCABORTALTERNATE) {
   1214     0    stevel 			if (abort_charseq_recognize(buf)) {
   1215     0    stevel 				abort_sequence_enter((char *)NULL);
   1216     0    stevel 			}
   1217     0    stevel 		}
   1218     0    stevel 
   1219     0    stevel 		/* put console input onto stream */
   1220     0    stevel 		if (qcn_state->qcn_readq) {
   1221     0    stevel 			if ((mp = allocb(1, BPRI_MED)) == NULL) {
   1222     0    stevel 				qcn_input_dropped++;
   1223     0    stevel 				cmn_err(CE_WARN, "qcn_intr: allocb"
   1224     0    stevel 				    "failed (console input dropped)");
   1225     0    stevel 				return;
   1226     0    stevel 			}
   1227     0    stevel 			*(char *)mp->b_wptr++ = buf;
   1228     0    stevel 			putnext(qcn_state->qcn_readq, mp);
   1229     0    stevel 		}
   1230     0    stevel 	}
   1231     0    stevel out:
   1232     0    stevel /*
   1233     0    stevel  * If there are pending transmits because hypervisor
   1234     0    stevel  * returned EWOULDBLOCK poke start now.
   1235     0    stevel  */
   1236     0    stevel 
   1237     0    stevel 	mutex_enter(&qcn_state->qcn_lock);
   1238     0    stevel 	if (qcn_state->qcn_writeq != NULL) {
   1239     0    stevel 		if (qcn_writeq_flush) {
   1240     0    stevel 			flushq(qcn_state->qcn_writeq, FLUSHDATA);
   1241     0    stevel 		} else {
   1242     0    stevel 			qcn_start();
   1243     0    stevel 		}
   1244     0    stevel 	}
   1245     0    stevel 	mutex_exit(&qcn_state->qcn_lock);
   1246     0    stevel }
   1247     0    stevel #endif
   1248     0    stevel 
   1249     0    stevel /*
   1250     0    stevel  * Check for abort character sequence, copied from zs_async.c
   1251     0    stevel  */
   1252     0    stevel #define	CNTRL(c) ((c)&037)
   1253     0    stevel 
   1254     0    stevel static boolean_t
   1255     0    stevel abort_charseq_recognize(uchar_t ch)
   1256     0    stevel {
   1257     0    stevel 	static int state = 0;
   1258     0    stevel 	static char sequence[] = { '\r', '~', CNTRL('b') };
   1259     0    stevel 
   1260     0    stevel 	if (ch == sequence[state]) {
   1261     0    stevel 		if (++state >= sizeof (sequence)) {
   1262     0    stevel 			state = 0;
   1263     0    stevel 			return (B_TRUE);
   1264     0    stevel 		}
   1265     0    stevel 	} else {
   1266     0    stevel 		state = (ch == sequence[0]) ? 1 : 0;
   1267     0    stevel 	}
   1268     0    stevel 	return (B_FALSE);
   1269     0    stevel }
   1270     0    stevel 
   1271     0    stevel 
   1272     0    stevel static int
   1273     0    stevel qcn_rsrv(queue_t *q)
   1274     0    stevel {
   1275     0    stevel 	mblk_t	*mp;
   1276     0    stevel 
   1277     0    stevel 	if (qcn_stopped == B_TRUE)
   1278     0    stevel 		return (0);
   1279     0    stevel 
   1280     0    stevel 	mutex_enter(&qcn_state->qcn_lock);
   1281     0    stevel 
   1282     0    stevel 	while ((mp = getq(q)) != NULL) {
   1283     0    stevel 		if (canputnext(q))
   1284     0    stevel 			putnext(q, mp);
   1285     0    stevel 		else if (mp->b_datap->db_type >= QPCTL)
   1286     0    stevel 			(void) putbq(q, mp);
   1287     0    stevel 	}
   1288     0    stevel 
   1289     0    stevel 	mutex_exit(&qcn_state->qcn_lock);
   1290     0    stevel 
   1291     0    stevel 	return (0);
   1292     0    stevel }
   1293     0    stevel 
   1294     0    stevel /* ARGSUSED */
   1295     0    stevel static int
   1296     0    stevel qcn_wsrv(queue_t *q)
   1297     0    stevel {
   1298     0    stevel 	if (qcn_stopped == B_TRUE)
   1299     0    stevel 		return (0);
   1300     0    stevel 
   1301     0    stevel 	mutex_enter(&qcn_state->qcn_lock);
   1302     0    stevel 
   1303     0    stevel 	if (qcn_state->qcn_writeq != NULL)
   1304     0    stevel 		qcn_start();
   1305     0    stevel 
   1306     0    stevel 	mutex_exit(&qcn_state->qcn_lock);
   1307     0    stevel 
   1308     0    stevel 	return (0);
   1309     0    stevel }
   1310  5974   jm22469 
   1311  5974   jm22469 static boolean_t
   1312  5974   jm22469 qcn_polledio_ischar(cons_polledio_arg_t arg)
   1313  5974   jm22469 {
   1314  5974   jm22469 	qcn_t *state = (qcn_t *)arg;
   1315  5974   jm22469 
   1316  5974   jm22469 	if (state->qcn_char_available)
   1317  5974   jm22469 		return (B_TRUE);
   1318  5974   jm22469 
   1319  5974   jm22469 	return (state->qcn_char_available =
   1320  5974   jm22469 	    (hv_cngetchar(&state->qcn_hold_char) == H_EOK));
   1321  5974   jm22469 }
   1322  5974   jm22469 
   1323  5974   jm22469 
   1324  5974   jm22469 static int
   1325  5974   jm22469 qcn_polledio_getchar(cons_polledio_arg_t arg)
   1326  5974   jm22469 {
   1327  5974   jm22469 	qcn_t *state = (qcn_t *)arg;
   1328  5974   jm22469 
   1329  5974   jm22469 	while (!qcn_polledio_ischar(arg))
   1330  5974   jm22469 		drv_usecwait(10);
   1331  5974   jm22469 
   1332  5974   jm22469 	state->qcn_char_available = B_FALSE;
   1333  5974   jm22469 
   1334  5974   jm22469 	return ((int)state->qcn_hold_char);
   1335  5974   jm22469 }
   1336  5974   jm22469 
   1337  5974   jm22469 static void
   1338  5974   jm22469 qcn_polledio_putchar(cons_polledio_arg_t arg, uchar_t c)
   1339  5974   jm22469 {
   1340  5974   jm22469 	if (c == '\n')
   1341  5974   jm22469 		qcn_polledio_putchar(arg, '\r');
   1342  5974   jm22469 
   1343  5974   jm22469 	while (hv_cnputchar((uint8_t)c) == H_EWOULDBLOCK)
   1344  5974   jm22469 		drv_usecwait(10);
   1345  5974   jm22469 }
   1346  5974   jm22469 
   1347  5974   jm22469 static void
   1348  5974   jm22469 qcn_polledio_enter(cons_polledio_arg_t arg)
   1349  5974   jm22469 {
   1350  5974   jm22469 	qcn_t *state = (qcn_t *)arg;
   1351  5974   jm22469 
   1352  5974   jm22469 	state->qcn_char_available = B_FALSE;
   1353  5974   jm22469 }
   1354  5974   jm22469 
   1355  5974   jm22469 /* ARGSUSED */
   1356  5974   jm22469 static void
   1357  5974   jm22469 qcn_polledio_exit(cons_polledio_arg_t arg)
   1358  5974   jm22469 {
   1359  5974   jm22469 }
   1360