11991Sheppo /*
21991Sheppo * CDDL HEADER START
31991Sheppo *
41991Sheppo * The contents of this file are subject to the terms of the
51991Sheppo * Common Development and Distribution License (the "License").
61991Sheppo * You may not use this file except in compliance with the License.
71991Sheppo *
81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo * or http://www.opensolaris.org/os/licensing.
101991Sheppo * See the License for the specific language governing permissions
111991Sheppo * and limitations under the License.
121991Sheppo *
131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo *
191991Sheppo * CDDL HEADER END
201991Sheppo */
211991Sheppo
221991Sheppo /*
23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
241991Sheppo * Use is subject to license terms.
251991Sheppo */
261991Sheppo
271991Sheppo
281991Sheppo #include <sys/types.h>
291991Sheppo #include <sys/file.h>
301991Sheppo #include <sys/errno.h>
311991Sheppo #include <sys/uio.h>
321991Sheppo #include <sys/open.h>
331991Sheppo #include <sys/cred.h>
341991Sheppo #include <sys/kmem.h>
351991Sheppo #include <sys/conf.h>
361991Sheppo #include <sys/cmn_err.h>
371991Sheppo #include <sys/ksynch.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */
401991Sheppo #include <sys/debug.h>
411991Sheppo #include <sys/promif.h>
421991Sheppo #include <sys/ddi.h>
431991Sheppo #include <sys/sunddi.h>
441991Sheppo #include <sys/cyclic.h>
451991Sheppo #include <sys/termio.h>
461991Sheppo #include <sys/intr.h>
471991Sheppo #include <sys/ivintr.h>
481991Sheppo #include <sys/note.h>
491991Sheppo #include <sys/stat.h>
501991Sheppo #include <sys/fcntl.h>
511991Sheppo #include <sys/sysmacros.h>
521991Sheppo
531991Sheppo #include <sys/ldc.h>
541991Sheppo #include <sys/mdeg.h>
551991Sheppo #include <sys/vcc_impl.h>
561991Sheppo
573297Ssb155480 #define VCC_LDC_RETRIES 5
583297Ssb155480 #define VCC_LDC_DELAY 1000 /* usec */
593297Ssb155480
601991Sheppo /*
611991Sheppo * Function prototypes.
621991Sheppo */
631991Sheppo
641991Sheppo /* DDI entrypoints */
651991Sheppo static int vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
661991Sheppo static int vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
671991Sheppo static int vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred);
681991Sheppo static int vcc_close(dev_t dev, int flag, int otyp, cred_t *cred);
691991Sheppo static int vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
701991Sheppo cred_t *credp, int *rvalp);
711991Sheppo static int vcc_read(dev_t dev, struct uio *uiop, cred_t *credp);
721991Sheppo static int vcc_write(dev_t dev, struct uio *uiop, cred_t *credp);
731991Sheppo static int vcc_chpoll(dev_t dev, short events, int anyyet,
741991Sheppo short *reventsp, struct pollhead **phpp);
751991Sheppo static int vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
761991Sheppo void *arg, void **resultp);
771991Sheppo
781991Sheppo /* callback functions */
791991Sheppo static uint_t vcc_ldc_cb(uint64_t event, caddr_t arg);
801991Sheppo static int vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
811991Sheppo
821991Sheppo /* Internal functions */
831991Sheppo static int i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport);
841991Sheppo static int i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port,
851991Sheppo uint_t portno, char *domain_name);
861991Sheppo static int i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id);
871991Sheppo static int i_vcc_reset_events(vcc_t *vccp);
881991Sheppo static int i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports,
891991Sheppo caddr_t buf, int mode);
901991Sheppo static int i_vcc_del_cons_ok(vcc_t *vccp, caddr_t buf, int mode);
911991Sheppo static int i_vcc_close_port(vcc_port_t *vport);
921991Sheppo static int i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf);
932748Slm66018 static int i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz);
941991Sheppo
951991Sheppo static void *vcc_ssp;
961991Sheppo
971991Sheppo static struct cb_ops vcc_cb_ops = {
981991Sheppo vcc_open, /* open */
991991Sheppo vcc_close, /* close */
1001991Sheppo nodev, /* strategy */
1011991Sheppo nodev, /* print */
1021991Sheppo nodev, /* dump */
1031991Sheppo vcc_read, /* read */
1041991Sheppo vcc_write, /* write */
1051991Sheppo vcc_ioctl, /* ioctl */
1061991Sheppo nodev, /* devmap */
1071991Sheppo nodev, /* mmap */
1081991Sheppo ddi_segmap, /* segmap */
1091991Sheppo vcc_chpoll, /* chpoll */
1101991Sheppo ddi_prop_op, /* prop_op */
1111991Sheppo NULL, /* stream */
1121991Sheppo D_NEW | D_MP /* flags */
1131991Sheppo };
1141991Sheppo
1151991Sheppo
1161991Sheppo static struct dev_ops vcc_ops = {
1171991Sheppo DEVO_REV, /* rev */
1181991Sheppo 0, /* ref count */
1191991Sheppo vcc_getinfo, /* getinfo */
1201991Sheppo nulldev, /* identify */
1211991Sheppo nulldev, /* probe */
1221991Sheppo vcc_attach, /* attach */
1231991Sheppo vcc_detach, /* detach */
1241991Sheppo nodev, /* reset */
1251991Sheppo &vcc_cb_ops, /* cb_ops */
126*7656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* bus_ops */
127*7656SSherry.Moore@Sun.COM NULL, /* power */
128*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1291991Sheppo };
1301991Sheppo
1311991Sheppo extern struct mod_ops mod_driverops;
1321991Sheppo
1331991Sheppo #define VCC_CHANNEL_ENDPOINT "channel-endpoint"
1341991Sheppo #define VCC_ID_PROP "id"
1351991Sheppo
1361991Sheppo /*
1371991Sheppo * This is the string displayed by modinfo(1m).
1381991Sheppo */
139*7656SSherry.Moore@Sun.COM static char vcc_ident[] = "sun4v Virtual Console Concentrator Driver";
1401991Sheppo
1411991Sheppo static struct modldrv md = {
1421991Sheppo &mod_driverops, /* Type - it is a driver */
1431991Sheppo vcc_ident, /* Name of the module */
1441991Sheppo &vcc_ops, /* driver specfic opts */
1451991Sheppo };
1461991Sheppo
1471991Sheppo static struct modlinkage ml = {
1481991Sheppo MODREV_1,
1491991Sheppo &md,
1501991Sheppo NULL
1511991Sheppo };
1521991Sheppo
1531991Sheppo /*
1541991Sheppo * Matching criteria passed to the MDEG to register interest
1551991Sheppo * in changes to 'virtual-device-port' nodes identified by their
1561991Sheppo * 'id' property.
1571991Sheppo */
1581991Sheppo static md_prop_match_t vcc_port_prop_match[] = {
1591991Sheppo { MDET_PROP_VAL, "id" },
1601991Sheppo { MDET_LIST_END, NULL }
1611991Sheppo };
1621991Sheppo
1631991Sheppo static mdeg_node_match_t vcc_port_match = {"virtual-device-port",
1641991Sheppo vcc_port_prop_match};
1651991Sheppo
1661991Sheppo /*
1671991Sheppo * Specification of an MD node passed to the MDEG to filter any
1681991Sheppo * 'virtual-device-port' nodes that do not belong to the specified node.
1691991Sheppo * This template is copied for each vldc instance and filled in with
1701991Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG.
1711991Sheppo */
1721991Sheppo static mdeg_prop_spec_t vcc_prop_template[] = {
1731991Sheppo { MDET_PROP_STR, "name", "virtual-console-concentrator" },
1741991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL },
1751991Sheppo { MDET_LIST_END, NULL, NULL }
1761991Sheppo };
1771991Sheppo
1781991Sheppo #define VCC_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val);
1791991Sheppo
1801991Sheppo
1811991Sheppo #ifdef DEBUG
1821991Sheppo
1831991Sheppo /*
1841991Sheppo * Print debug messages
1851991Sheppo *
1861991Sheppo * set vldcdbg to 0xf to enable all messages
1871991Sheppo *
1881991Sheppo * 0x8 - Errors
1891991Sheppo * 0x4 - Warnings
1901991Sheppo * 0x2 - All debug messages (most verbose)
1911991Sheppo * 0x1 - Minimal debug messages
1921991Sheppo */
1931991Sheppo
1941991Sheppo int vccdbg = 0x8;
1951991Sheppo
1961991Sheppo static void
vccdebug(const char * fmt,...)1971991Sheppo vccdebug(const char *fmt, ...)
1981991Sheppo {
1991991Sheppo char buf[512];
2001991Sheppo va_list ap;
2011991Sheppo
2021991Sheppo va_start(ap, fmt);
2031991Sheppo (void) vsprintf(buf, fmt, ap);
2041991Sheppo va_end(ap);
2051991Sheppo
2061991Sheppo cmn_err(CE_CONT, "%s\n", buf);
2071991Sheppo }
2081991Sheppo
2091991Sheppo #define D1 \
2101991Sheppo if (vccdbg & 0x01) \
2111991Sheppo vccdebug
2121991Sheppo
2131991Sheppo #define D2 \
2141991Sheppo if (vccdbg & 0x02) \
2151991Sheppo vccdebug
2161991Sheppo
2171991Sheppo #define DWARN \
2181991Sheppo if (vccdbg & 0x04) \
2191991Sheppo vccdebug
2201991Sheppo
2211991Sheppo #else
2221991Sheppo
2231991Sheppo #define D1
2241991Sheppo #define D2
2251991Sheppo #define DWARN
2261991Sheppo
2271991Sheppo #endif
2281991Sheppo
2291991Sheppo /* _init(9E): initialize the loadable module */
2301991Sheppo int
_init(void)2311991Sheppo _init(void)
2321991Sheppo {
2331991Sheppo int error;
2341991Sheppo
2351991Sheppo /* init the soft state structure */
2361991Sheppo error = ddi_soft_state_init(&vcc_ssp, sizeof (vcc_t), 1);
2371991Sheppo if (error != 0) {
2381991Sheppo return (error);
2391991Sheppo }
2401991Sheppo
2411991Sheppo /* Link the driver into the system */
2421991Sheppo error = mod_install(&ml);
2431991Sheppo
2441991Sheppo return (error);
2451991Sheppo
2461991Sheppo }
2471991Sheppo
2481991Sheppo /* _info(9E): return information about the loadable module */
2491991Sheppo int
_info(struct modinfo * modinfop)2501991Sheppo _info(struct modinfo *modinfop)
2511991Sheppo {
2521991Sheppo /* Report status of the dynamically loadable driver module */
2531991Sheppo return (mod_info(&ml, modinfop));
2541991Sheppo }
2551991Sheppo
2561991Sheppo /* _fini(9E): prepare the module for unloading. */
2571991Sheppo int
_fini(void)2581991Sheppo _fini(void)
2591991Sheppo {
2601991Sheppo int error;
2611991Sheppo
2621991Sheppo /* Unlink the driver module from the system */
2631991Sheppo if ((error = mod_remove(&ml)) == 0) {
2641991Sheppo /*
2651991Sheppo * We have successfully "removed" the driver.
2661991Sheppo * destroy soft state
2671991Sheppo */
2681991Sheppo ddi_soft_state_fini(&vcc_ssp);
2691991Sheppo }
2701991Sheppo
2711991Sheppo return (error);
2721991Sheppo }
2731991Sheppo
2741991Sheppo /* getinfo(9E) */
2751991Sheppo static int
vcc_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)2761991Sheppo vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
2771991Sheppo {
2781991Sheppo _NOTE(ARGUNUSED(dip))
2791991Sheppo
2801991Sheppo int instance = VCCINST(getminor((dev_t)arg));
2811991Sheppo vcc_t *vccp = NULL;
2821991Sheppo
2831991Sheppo switch (cmd) {
2841991Sheppo
2851991Sheppo case DDI_INFO_DEVT2DEVINFO:
2861991Sheppo if ((vccp = ddi_get_soft_state(vcc_ssp, instance)) == NULL) {
2871991Sheppo *resultp = NULL;
2881991Sheppo return (DDI_FAILURE);
2891991Sheppo }
2901991Sheppo *resultp = vccp->dip;
2911991Sheppo return (DDI_SUCCESS);
2921991Sheppo
2931991Sheppo case DDI_INFO_DEVT2INSTANCE:
2941991Sheppo *resultp = (void *)(uintptr_t)instance;
2951991Sheppo return (DDI_SUCCESS);
2961991Sheppo
2971991Sheppo default:
2981991Sheppo *resultp = NULL;
2991991Sheppo return (DDI_FAILURE);
3001991Sheppo }
3011991Sheppo }
3021991Sheppo
3031991Sheppo /*
3041991Sheppo * There are two cases that need special blocking. One of them is to block
3051991Sheppo * a minor node without a port and another is to block application other
3061991Sheppo * than vntsd.
3071991Sheppo *
3081991Sheppo * A minor node can exist in the file system without associated with a port
3091991Sheppo * because when a port is deleted, ddi_remove_minor does not unlink it.
3101991Sheppo * Clients might try to open a minor node even after the corresponding port
3111991Sheppo * node has been removed. To identify and block these calls,
3121991Sheppo * we need to validate the association between a port and its minor node.
3131991Sheppo *
3141991Sheppo * An application other than vntsd can access a console port as long
3151991Sheppo * as vntsd is not using the port. A port opened by an application other
3161991Sheppo * than vntsd will be closed when vntsd wants to use the port.
3171991Sheppo * However, other application could use same file descriptor
3181991Sheppo * access vcc cb_ops. So we need to identify and block caller other
3191991Sheppo * than vntsd, when vntsd is using the port.
3201991Sheppo */
3211991Sheppo static int
i_vcc_can_use_port(vcc_minor_t * minorp,vcc_port_t * vport)3221991Sheppo i_vcc_can_use_port(vcc_minor_t *minorp, vcc_port_t *vport)
3231991Sheppo {
3241991Sheppo if (vport->minorp != minorp) {
3251991Sheppo /* port config changed */
3261991Sheppo return (ENXIO);
3271991Sheppo }
3281991Sheppo
3291991Sheppo if (vport->valid_pid == VCC_NO_PID_BLOCKING) {
3301991Sheppo /* no blocking needed */
3311991Sheppo return (0);
3321991Sheppo }
3331991Sheppo
3341991Sheppo if (vport->valid_pid != ddi_get_pid()) {
3351991Sheppo return (EIO);
3361991Sheppo }
3371991Sheppo
3381991Sheppo return (0);
3391991Sheppo }
3401991Sheppo
3411991Sheppo
3421991Sheppo /* Syncronization between thread using cv_wait */
3431991Sheppo static int
i_vcc_wait_port_status(vcc_port_t * vport,kcondvar_t * cv,uint32_t status)3441991Sheppo i_vcc_wait_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status)
3451991Sheppo {
3461991Sheppo
3471991Sheppo int rv;
3481991Sheppo
3491991Sheppo ASSERT(mutex_owned(&vport->lock));
3501991Sheppo
3511991Sheppo for (; ; ) {
3521991Sheppo
3531991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
3541991Sheppo /* port has been deleted */
3551991Sheppo D1("i_vcc_wait_port_status: port%d deleted\n",
3561991Sheppo vport->number);
3571991Sheppo return (EIO);
3581991Sheppo }
3591991Sheppo
3601991Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) {
3611991Sheppo D1("i_vcc_wait_port_status: port%d is closed \n",
3621991Sheppo vport->number);
3631991Sheppo return (EIO);
3641991Sheppo }
3651991Sheppo
3661991Sheppo if (vport->status & VCC_PORT_LDC_LINK_DOWN) {
3671991Sheppo return (EIO);
3681991Sheppo }
3691991Sheppo
3701991Sheppo if ((vport->valid_pid != VCC_NO_PID_BLOCKING) &&
3711991Sheppo (vport->valid_pid != ddi_get_pid())) {
3721991Sheppo return (EIO);
3731991Sheppo }
3741991Sheppo
3751991Sheppo if ((vport->status & status) == status) {
3761991Sheppo return (0);
3771991Sheppo }
3781991Sheppo
3791991Sheppo if (!ddi_can_receive_sig()) {
3801991Sheppo return (EIO);
3811991Sheppo }
3821991Sheppo
3831991Sheppo rv = cv_wait_sig(cv, &vport->lock);
3841991Sheppo if (rv == 0) {
3851991Sheppo D1("i_vcc_wait_port_status: port%d get intr \n",
3861991Sheppo vport->number);
3871991Sheppo /* got signal */
3881991Sheppo return (EINTR);
3891991Sheppo }
3901991Sheppo }
3911991Sheppo
3921991Sheppo }
3931991Sheppo
3941991Sheppo /* Syncronization between threads, signal state change */
3951991Sheppo static void
i_vcc_set_port_status(vcc_port_t * vport,kcondvar_t * cv,uint32_t status)3961991Sheppo i_vcc_set_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status)
3971991Sheppo {
3981991Sheppo
3991991Sheppo mutex_enter(&vport->lock);
4001991Sheppo vport->status |= status;
4011991Sheppo cv_broadcast(cv);
4021991Sheppo mutex_exit(&vport->lock);
4031991Sheppo }
4041991Sheppo
4051991Sheppo /* initialize a ldc channel */
4061991Sheppo static int
i_vcc_ldc_init(vcc_t * vccp,vcc_port_t * vport)4071991Sheppo i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport)
4081991Sheppo {
4091991Sheppo ldc_attr_t attr;
4101991Sheppo int rv = EIO;
4111991Sheppo
4121991Sheppo ASSERT(mutex_owned(&vport->lock));
4131991Sheppo ASSERT(vport->ldc_id != VCC_INVALID_CHANNEL);
4141991Sheppo
4151991Sheppo /* initialize the channel */
4161991Sheppo attr.devclass = LDC_DEV_SERIAL;
4171991Sheppo attr.instance = ddi_get_instance(vccp->dip);
4182410Slm66018 attr.mtu = VCC_MTU_SZ;
4191991Sheppo attr.mode = LDC_MODE_RAW;
4201991Sheppo
4211991Sheppo if ((rv = ldc_init(vport->ldc_id, &attr, &(vport->ldc_handle))) != 0) {
4223151Ssg70180 cmn_err(CE_CONT, "i_vcc_ldc_init: port %d ldc channel %ld"
4233151Ssg70180 " failed ldc_init %d \n", vport->number, vport->ldc_id, rv);
4241991Sheppo vport->ldc_id = VCC_INVALID_CHANNEL;
4251991Sheppo return (rv);
4261991Sheppo }
4271991Sheppo
4281991Sheppo /* register it */
4291991Sheppo if ((rv = ldc_reg_callback(vport->ldc_handle, vcc_ldc_cb,
430*7656SSherry.Moore@Sun.COM (caddr_t)vport)) != 0) {
4311991Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_register_cb"
432*7656SSherry.Moore@Sun.COM "failed\n", vport->number);
4331991Sheppo (void) ldc_fini(vport->ldc_handle);
4341991Sheppo vport->ldc_id = VCC_INVALID_CHANNEL;
4351991Sheppo return (rv);
4361991Sheppo }
4371991Sheppo
4381991Sheppo /* open and bring channel up */
4391991Sheppo if ((rv = ldc_open(vport->ldc_handle)) != 0) {
4401991Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d inv channel 0x%lx\n",
4411991Sheppo vport->number, vport->ldc_id);
4421991Sheppo (void) ldc_unreg_callback(vport->ldc_handle);
4431991Sheppo (void) ldc_fini(vport->ldc_handle);
4441991Sheppo vport->ldc_id = VCC_INVALID_CHANNEL;
4451991Sheppo return (rv);
4461991Sheppo }
4471991Sheppo
4481991Sheppo /* init the channel status */
4491991Sheppo if ((rv = ldc_status(vport->ldc_handle, &vport->ldc_status)) != 0) {
4501991Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_status failed\n",
4511991Sheppo vport->number);
4521991Sheppo (void) ldc_close(vport->ldc_handle);
4531991Sheppo (void) ldc_unreg_callback(vport->ldc_handle);
4541991Sheppo (void) ldc_fini(vport->ldc_handle);
4551991Sheppo vport->ldc_id = VCC_INVALID_CHANNEL;
4561991Sheppo return (rv);
4571991Sheppo }
4581991Sheppo
4591991Sheppo return (0);
4601991Sheppo }
4611991Sheppo
4621991Sheppo /* release a ldc channel */
4633297Ssb155480 static void
i_vcc_ldc_fini(vcc_port_t * vport)4641991Sheppo i_vcc_ldc_fini(vcc_port_t *vport)
4651991Sheppo {
4661991Sheppo int rv = EIO;
4671991Sheppo vcc_msg_t buf;
4682748Slm66018 size_t sz;
4693297Ssb155480 int retry = 0;
4701991Sheppo
4711991Sheppo D1("i_vcc_ldc_fini: port@%lld, ldc_id%%llx\n", vport->number,
4721991Sheppo vport->ldc_id);
4731991Sheppo
4741991Sheppo ASSERT(mutex_owned(&vport->lock));
4751991Sheppo
4761991Sheppo /* wait for write available */
4771991Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv,
4781991Sheppo VCC_PORT_USE_WRITE_LDC);
4793297Ssb155480
4803297Ssb155480 if (rv == 0) {
4813297Ssb155480 vport->status &= ~VCC_PORT_USE_WRITE_LDC;
4823297Ssb155480
4833297Ssb155480 /* send a HUP message */
4843297Ssb155480 buf.type = LDC_CONSOLE_CTRL;
4853297Ssb155480 buf.ctrl_msg = LDC_CONSOLE_HUP;
4863297Ssb155480 buf.size = 0;
4873297Ssb155480
4883297Ssb155480 /*
4893297Ssb155480 * ignore write error since we still want to clean up
4903297Ssb155480 * ldc channel.
4913297Ssb155480 */
4923297Ssb155480 (void) i_vcc_write_ldc(vport, &buf);
4933297Ssb155480
4943297Ssb155480 mutex_exit(&vport->lock);
4953297Ssb155480 i_vcc_set_port_status(vport, &vport->write_cv,
4963297Ssb155480 VCC_PORT_USE_WRITE_LDC);
4973297Ssb155480 mutex_enter(&vport->lock);
4981991Sheppo }
4991991Sheppo
5002748Slm66018 /* flush ldc channel */
5012748Slm66018 rv = i_vcc_wait_port_status(vport, &vport->read_cv,
5022748Slm66018 VCC_PORT_USE_READ_LDC);
5033297Ssb155480
5043297Ssb155480 if (rv == 0) {
5053297Ssb155480 vport->status &= ~VCC_PORT_USE_READ_LDC;
5063297Ssb155480 do {
5073297Ssb155480 sz = sizeof (buf);
5083297Ssb155480 rv = i_vcc_read_ldc(vport, (char *)&buf, &sz);
5093297Ssb155480 } while (rv == 0 && sz > 0);
5103297Ssb155480
5113297Ssb155480 vport->status |= VCC_PORT_USE_READ_LDC;
5123297Ssb155480
5132748Slm66018 }
5142748Slm66018
5153297Ssb155480 /*
5163297Ssb155480 * ignore read error since we still want to clean up
5173297Ssb155480 * ldc channel.
5183297Ssb155480 */
5192748Slm66018
5201991Sheppo (void) ldc_set_cb_mode(vport->ldc_handle, LDC_CB_DISABLE);
5213297Ssb155480
5223297Ssb155480 /* close LDC channel - retry on EAGAIN */
5233297Ssb155480 while ((rv = ldc_close(vport->ldc_handle)) == EAGAIN) {
5243297Ssb155480
5253297Ssb155480 if (++retry > VCC_LDC_RETRIES) {
5263297Ssb155480 cmn_err(CE_CONT, "i_vcc_ldc_fini: cannot close channel"
5273297Ssb155480 " %ld\n", vport->ldc_id);
5283297Ssb155480 break;
5293297Ssb155480 }
5303297Ssb155480
5313297Ssb155480 drv_usecwait(VCC_LDC_DELAY);
5321991Sheppo }
5331991Sheppo
5343297Ssb155480 if (rv == 0) {
5353297Ssb155480 (void) ldc_unreg_callback(vport->ldc_handle);
5363297Ssb155480 (void) ldc_fini(vport->ldc_handle);
5373297Ssb155480 } else {
5383297Ssb155480 /*
5393297Ssb155480 * Closing the LDC channel has failed. Ideally we should
5403297Ssb155480 * fail here but there is no Zeus level infrastructure
5413297Ssb155480 * to handle this. The MD has already been changed and
5423297Ssb155480 * we have to do the close. So we try to do as much
5433297Ssb155480 * clean up as we can.
5443297Ssb155480 */
5453297Ssb155480 while (ldc_unreg_callback(vport->ldc_handle) == EAGAIN)
5463297Ssb155480 drv_usecwait(VCC_LDC_DELAY);
5471991Sheppo }
5481991Sheppo
5491991Sheppo }
5501991Sheppo
5511991Sheppo /* read data from ldc channel */
5521991Sheppo
5531991Sheppo static int
i_vcc_read_ldc(vcc_port_t * vport,char * data_buf,size_t * sz)5541991Sheppo i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz)
5551991Sheppo {
5561991Sheppo
5571991Sheppo int rv;
5581991Sheppo size_t size;
5591991Sheppo size_t space_left = *sz;
5601991Sheppo vcc_msg_t buf;
5611991Sheppo int i;
5621991Sheppo
5631991Sheppo
5641991Sheppo
5651991Sheppo
5661991Sheppo /* make sure holding read lock */
5671991Sheppo ASSERT((vport->status & VCC_PORT_USE_READ_LDC) == 0);
5681991Sheppo ASSERT(space_left >= VCC_MTU_SZ);
5691991Sheppo
5701991Sheppo *sz = 0;
5711991Sheppo while (space_left >= VCC_MTU_SZ) {
5721991Sheppo size = sizeof (buf);
5731991Sheppo
5741991Sheppo rv = ldc_read(vport->ldc_handle, (caddr_t)&buf, &size);
5751991Sheppo
5761991Sheppo if (rv) {
5771991Sheppo return (rv);
5781991Sheppo }
5791991Sheppo
5801991Sheppo
5811991Sheppo /*
5821991Sheppo * FIXME: ldc_read should not reaturn 0 with
5831991Sheppo * either size == 0, buf.size == 0 or size < VCC_HDR_SZ
5841991Sheppo */
5851991Sheppo if (size == 0) {
5861991Sheppo if (*sz > 0) {
5871991Sheppo return (0);
5881991Sheppo }
5891991Sheppo return (EAGAIN);
5901991Sheppo }
5911991Sheppo
5921991Sheppo if (size < VCC_HDR_SZ) {
5931991Sheppo return (EIO);
5941991Sheppo }
5951991Sheppo
5961991Sheppo /*
5971991Sheppo * only data is expected from console - otherwise
5981991Sheppo * return error
5991991Sheppo */
6001991Sheppo if (buf.type != LDC_CONSOLE_DATA) {
6011991Sheppo return (EIO);
6021991Sheppo }
6031991Sheppo
6041991Sheppo if (buf.size == 0) {
6051991Sheppo if (*sz > 0) {
6061991Sheppo return (0);
6071991Sheppo }
6081991Sheppo return (EAGAIN);
6091991Sheppo }
6101991Sheppo
6111991Sheppo /* copy data */
6121991Sheppo for (i = 0; i < buf.size; i++, (*sz)++) {
6131991Sheppo data_buf[*sz] = buf.data[i];
6141991Sheppo }
6151991Sheppo
6161991Sheppo space_left -= buf.size;
6171991Sheppo }
6181991Sheppo
6191991Sheppo return (0);
6201991Sheppo }
6211991Sheppo
6221991Sheppo /* callback from ldc */
6231991Sheppo static uint_t
vcc_ldc_cb(uint64_t event,caddr_t arg)6241991Sheppo vcc_ldc_cb(uint64_t event, caddr_t arg)
6251991Sheppo {
6261991Sheppo
6271991Sheppo vcc_port_t *vport = (vcc_port_t *)arg;
6282410Slm66018 boolean_t hasdata;
6291991Sheppo
6301991Sheppo /*
6311991Sheppo * do not need to hold lock because if ldc calls back, the
6321991Sheppo * ldc_handle must be valid.
6331991Sheppo */
6341991Sheppo D2("vcc_ldc_cb: callback invoked port=%d events=%llx\n",
6351991Sheppo vport->number, event);
6361991Sheppo
6371991Sheppo /* check event from ldc */
6381991Sheppo if (event & LDC_EVT_WRITE) {
6391991Sheppo /* channel has space for write */
6401991Sheppo
6411991Sheppo i_vcc_set_port_status(vport, &vport->write_cv,
642*7656SSherry.Moore@Sun.COM VCC_PORT_LDC_WRITE_READY);
6431991Sheppo return (LDC_SUCCESS);
6441991Sheppo }
6451991Sheppo
6461991Sheppo if (event & LDC_EVT_READ) {
6471991Sheppo
6481991Sheppo /* channel has data for read */
6492410Slm66018 (void) ldc_chkq(vport->ldc_handle, &hasdata);
6502410Slm66018 if (!hasdata) {
6511991Sheppo /* data already read */
6521991Sheppo return (LDC_SUCCESS);
6531991Sheppo }
6541991Sheppo
6551991Sheppo i_vcc_set_port_status(vport, &vport->read_cv,
656*7656SSherry.Moore@Sun.COM VCC_PORT_LDC_DATA_READY);
6571991Sheppo return (LDC_SUCCESS);
6581991Sheppo }
6591991Sheppo
6601991Sheppo if (event & LDC_EVT_DOWN) {
6611991Sheppo /* channel is down */
6621991Sheppo i_vcc_set_port_status(vport, &vport->write_cv,
663*7656SSherry.Moore@Sun.COM VCC_PORT_LDC_LINK_DOWN);
6641991Sheppo cv_broadcast(&vport->read_cv);
6651991Sheppo
6661991Sheppo }
6671991Sheppo
6681991Sheppo return (LDC_SUCCESS);
6691991Sheppo
6701991Sheppo }
6711991Sheppo
6721991Sheppo
6731991Sheppo /* configure a vcc port with ldc channel */
6741991Sheppo static int
i_vcc_config_port(vcc_t * vccp,uint_t portno,uint64_t ldc_id)6751991Sheppo i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id)
6761991Sheppo {
6771991Sheppo int rv = EIO;
6781991Sheppo vcc_port_t *vport;
6791991Sheppo
6801991Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
6811991Sheppo cmn_err(CE_CONT, "i_vcc_config_port: invalid port number %d\n",
6821991Sheppo portno);
6831991Sheppo return (EINVAL);
6841991Sheppo }
6851991Sheppo
6861991Sheppo vport = &(vccp->port[portno]);
6871991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
6881991Sheppo cmn_err(CE_CONT, "i_vcc_config_port: port@%d does not exist\n",
6891991Sheppo portno);
6901991Sheppo return (EINVAL);
6911991Sheppo }
6921991Sheppo
6931991Sheppo
6941991Sheppo if (vport->ldc_id != VCC_INVALID_CHANNEL) {
6951991Sheppo cmn_err(CE_CONT, "i_vcc_config_port: port@%d channel already"
6961991Sheppo "configured\n", portno);
6971991Sheppo return (EINVAL);
6981991Sheppo }
6991991Sheppo
7001991Sheppo mutex_enter(&vport->lock);
7011991Sheppo
7021991Sheppo /* store the ldc ID */
7031991Sheppo vport->ldc_id = ldc_id;
7041991Sheppo /* check if someone has already opened this port */
7051991Sheppo if (vport->status & VCC_PORT_OPEN) {
7061991Sheppo
7071991Sheppo if ((rv = i_vcc_ldc_init(vccp, vport)) != 0) {
7081991Sheppo mutex_exit(&vport->lock);
7091991Sheppo return (rv);
7101991Sheppo }
7111991Sheppo
7121991Sheppo /* mark port as ready */
7131991Sheppo vport->status |= VCC_PORT_LDC_CHANNEL_READY;
7141991Sheppo cv_broadcast(&vport->read_cv);
7151991Sheppo cv_broadcast(&vport->write_cv);
7161991Sheppo }
7171991Sheppo
7181991Sheppo mutex_exit(&vport->lock);
7191991Sheppo
7201991Sheppo D1("i_vcc_config_port: port@%d ldc=%d, domain=%s",
7211991Sheppo vport->number, vport->ldc_id, vport->minorp->domain_name);
7221991Sheppo
7231991Sheppo return (0);
7241991Sheppo }
7251991Sheppo
7261991Sheppo /* add a vcc console port */
7271991Sheppo static int
i_vcc_add_port(vcc_t * vccp,char * group_name,uint64_t tcp_port,uint_t portno,char * domain_name)7281991Sheppo i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port,
7291991Sheppo uint_t portno, char *domain_name)
7301991Sheppo {
7311991Sheppo int instance;
7321991Sheppo int rv = MDEG_FAILURE;
7331991Sheppo minor_t minor;
7341991Sheppo vcc_port_t *vport;
7351991Sheppo uint_t minor_idx;
7361991Sheppo char name[MAXPATHLEN];
7371991Sheppo
7381991Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
7391991Sheppo DWARN("i_vcc_add_port: invalid port number %d\n", portno);
7401991Sheppo return (MDEG_FAILURE);
7411991Sheppo }
7421991Sheppo
7431991Sheppo vport = &(vccp->port[portno]);
7441991Sheppo if (vport->status & VCC_PORT_AVAIL) {
7451991Sheppo /* this port already exists */
7461991Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid port - port@%d "
747*7656SSherry.Moore@Sun.COM "exists\n", portno);
7481991Sheppo return (MDEG_FAILURE);
7491991Sheppo }
7501991Sheppo
7511991Sheppo vport->number = portno;
7521991Sheppo vport->ldc_id = VCC_INVALID_CHANNEL;
7531991Sheppo
7541991Sheppo if (domain_name == NULL) {
7551991Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid domain name\n");
7561991Sheppo return (MDEG_FAILURE);
7571991Sheppo }
7581991Sheppo
7591991Sheppo if (group_name == NULL) {
7601991Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid group name\n");
7611991Sheppo return (MDEG_FAILURE);
7621991Sheppo }
7631991Sheppo
7641991Sheppo /* look up minor number */
7651991Sheppo for (minor_idx = 0; minor_idx < vccp->minors_assigned; minor_idx++) {
7661991Sheppo if (strcmp(vccp->minor_tbl[minor_idx].domain_name,
767*7656SSherry.Moore@Sun.COM domain_name) == 0) {
7681991Sheppo /* found previous assigned minor number */
7691991Sheppo break;
7701991Sheppo }
7711991Sheppo }
7721991Sheppo
7731991Sheppo if (minor_idx == vccp->minors_assigned) {
7741991Sheppo /* end of lookup - assign new minor number */
7751991Sheppo if (minor_idx == VCC_MAX_PORTS) {
7761991Sheppo cmn_err(CE_CONT, "i_vcc_add_port:"
7771991Sheppo "too many minornodes (%d)\n",
7781991Sheppo minor_idx);
7791991Sheppo return (MDEG_FAILURE);
7801991Sheppo }
7811991Sheppo
7821991Sheppo (void) strlcpy(vccp->minor_tbl[minor_idx].domain_name,
7831991Sheppo domain_name, MAXPATHLEN);
7841991Sheppo
7851991Sheppo vccp->minors_assigned++;
7861991Sheppo }
7871991Sheppo
7881991Sheppo vport->minorp = &vccp->minor_tbl[minor_idx];
7891991Sheppo vccp->minor_tbl[minor_idx].portno = portno;
7901991Sheppo
7911991Sheppo (void) strlcpy(vport->group_name, group_name, MAXPATHLEN);
7921991Sheppo
7931991Sheppo vport->tcp_port = tcp_port;
7941991Sheppo D1("i_vcc_add_port:@%d domain=%s, group=%s, tcp=%lld",
7951991Sheppo vport->number, vport->minorp->domain_name,
7961991Sheppo vport->group_name, vport->tcp_port);
7971991Sheppo
7981991Sheppo
7991991Sheppo /*
8001991Sheppo * Create a minor node. The minor number is
8011991Sheppo * (instance << VCC_INST_SHIFT) | minor_idx
8021991Sheppo */
8031991Sheppo instance = ddi_get_instance(vccp->dip);
8041991Sheppo
8051991Sheppo minor = (instance << VCC_INST_SHIFT) | (minor_idx);
8061991Sheppo
8071991Sheppo (void) snprintf(name, MAXPATHLEN - 1, "%s%s", VCC_MINOR_NAME_PREFIX,
8081991Sheppo domain_name);
8091991Sheppo
8101991Sheppo rv = ddi_create_minor_node(vccp->dip, name, S_IFCHR, minor,
8111991Sheppo DDI_NT_SERIAL, 0);
8121991Sheppo
8131991Sheppo if (rv != DDI_SUCCESS) {
8141991Sheppo vccp->minors_assigned--;
8151991Sheppo return (MDEG_FAILURE);
8161991Sheppo }
8171991Sheppo
8181991Sheppo mutex_enter(&vport->lock);
8191991Sheppo vport->status = VCC_PORT_AVAIL | VCC_PORT_ADDED;
8201991Sheppo mutex_exit(&vport->lock);
8211991Sheppo
8221991Sheppo
8231991Sheppo return (MDEG_SUCCESS);
8241991Sheppo }
8251991Sheppo
8261991Sheppo /* delete a port */
8271991Sheppo static int
i_vcc_delete_port(vcc_t * vccp,vcc_port_t * vport)8281991Sheppo i_vcc_delete_port(vcc_t *vccp, vcc_port_t *vport)
8291991Sheppo {
8301991Sheppo
8311991Sheppo char name[MAXPATHLEN];
8321991Sheppo int rv;
8331991Sheppo
8341991Sheppo
8351991Sheppo ASSERT(mutex_owned(&vport->lock));
8361991Sheppo
8371991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
8381991Sheppo D1("vcc_del_port port already deleted \n");
8391991Sheppo return (0);
8401991Sheppo }
8411991Sheppo
8421991Sheppo if (vport->status & VCC_PORT_OPEN) {
8431991Sheppo /* do not block mdeg callback */
8441991Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING;
8451991Sheppo rv = i_vcc_close_port(vport);
8461991Sheppo }
8471991Sheppo
8481991Sheppo /* remove minor node */
8491991Sheppo (void) snprintf(name, MAXPATHLEN-1, "%s%s", VCC_MINOR_NAME_PREFIX,
8501991Sheppo vport->minorp->domain_name);
8511991Sheppo
8521991Sheppo ddi_remove_minor_node(vccp->dip, name);
8531991Sheppo
8541991Sheppo /* let read and write thread know */
8551991Sheppo cv_broadcast(&vport->read_cv);
8561991Sheppo cv_broadcast(&vport->write_cv);
8571991Sheppo vport->status = 0;
8581991Sheppo return (rv);
8591991Sheppo
8601991Sheppo
8611991Sheppo }
8621991Sheppo
8631991Sheppo /* register callback to MDEG */
8641991Sheppo static int
i_vcc_mdeg_register(vcc_t * vccp,int instance)8651991Sheppo i_vcc_mdeg_register(vcc_t *vccp, int instance)
8661991Sheppo {
8671991Sheppo mdeg_prop_spec_t *pspecp;
8681991Sheppo mdeg_node_spec_t *ispecp;
8691991Sheppo mdeg_handle_t mdeg_hdl;
8701991Sheppo int sz;
8711991Sheppo int rv;
8721991Sheppo
8731991Sheppo /*
8741991Sheppo * Allocate and initialize a per-instance copy
8751991Sheppo * of the global property spec array that will
8761991Sheppo * uniquely identify this vcc instance.
8771991Sheppo */
8781991Sheppo sz = sizeof (vcc_prop_template);
8791991Sheppo pspecp = kmem_alloc(sz, KM_SLEEP);
8801991Sheppo
8811991Sheppo bcopy(vcc_prop_template, pspecp, sz);
8821991Sheppo
8831991Sheppo VCC_SET_MDEG_PROP_INST(pspecp, instance);
8841991Sheppo
8851991Sheppo /* initialize the complete prop spec structure */
8861991Sheppo ispecp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP);
8871991Sheppo ispecp->namep = "virtual-device";
8881991Sheppo ispecp->specp = pspecp;
8891991Sheppo
8901991Sheppo /* perform the registration */
8911991Sheppo rv = mdeg_register(ispecp, &vcc_port_match, vcc_mdeg_cb,
8921991Sheppo vccp, &mdeg_hdl);
8931991Sheppo
8941991Sheppo if (rv != MDEG_SUCCESS) {
8951991Sheppo cmn_err(CE_CONT, "i_vcc_mdeg_register:"
8961991Sheppo "mdeg_register failed (%d)\n", rv);
8971991Sheppo kmem_free(ispecp, sizeof (mdeg_node_spec_t));
8981991Sheppo kmem_free(pspecp, sz);
8991991Sheppo return (DDI_FAILURE);
9001991Sheppo }
9011991Sheppo
9021991Sheppo /* save off data that will be needed later */
9031991Sheppo vccp->md_ispecp = (void *)ispecp;
9041991Sheppo vccp->mdeg_hdl = mdeg_hdl;
9051991Sheppo
9061991Sheppo return (0);
9071991Sheppo }
9081991Sheppo
9091991Sheppo /* destroy all mutex from port table */
9101991Sheppo static void
i_vcc_cleanup_port_table(vcc_t * vccp)9111991Sheppo i_vcc_cleanup_port_table(vcc_t *vccp)
9121991Sheppo {
9131991Sheppo int i;
9141991Sheppo vcc_port_t *vport;
9151991Sheppo
9161991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
9171991Sheppo vport = &(vccp->port[i]);
9181991Sheppo mutex_destroy(&vport->lock);
9191991Sheppo cv_destroy(&vport->read_cv);
9201991Sheppo cv_destroy(&vport->write_cv);
9211991Sheppo }
9221991Sheppo }
9231991Sheppo
9241991Sheppo /*
9251991Sheppo * attach(9E): attach a device to the system.
9261991Sheppo * called once for each instance of the device on the system.
9271991Sheppo */
9281991Sheppo static int
vcc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)9291991Sheppo vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
9301991Sheppo {
9311991Sheppo int i, instance, inst;
9321991Sheppo int rv = DDI_FAILURE;
9331991Sheppo vcc_t *vccp;
9341991Sheppo minor_t minor;
9351991Sheppo vcc_port_t *vport;
9361991Sheppo
9371991Sheppo switch (cmd) {
9381991Sheppo
9391991Sheppo case DDI_ATTACH:
9401991Sheppo
9411991Sheppo instance = ddi_get_instance(dip);
9421991Sheppo if (ddi_soft_state_zalloc(vcc_ssp, instance) != DDI_SUCCESS)
9431991Sheppo return (DDI_FAILURE);
9441991Sheppo
9451991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
9461991Sheppo if (vccp == NULL) {
9471991Sheppo ddi_soft_state_free(vccp, instance);
9481991Sheppo return (ENXIO);
9491991Sheppo }
9501991Sheppo
9511991Sheppo D1("vcc_attach: DDI_ATTACH instance=%d\n", instance);
9521991Sheppo
9531991Sheppo /* initialize the mutex */
9541991Sheppo mutex_init(&vccp->lock, NULL, MUTEX_DRIVER, NULL);
9551991Sheppo
9561991Sheppo mutex_enter(&vccp->lock);
9571991Sheppo
9581991Sheppo vccp->dip = dip;
9591991Sheppo
9601991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
9611991Sheppo vport = &(vccp->port[i]);
9621991Sheppo mutex_init(&vport->lock, NULL, MUTEX_DRIVER, NULL);
9631991Sheppo cv_init(&vport->read_cv, NULL, CV_DRIVER, NULL);
9641991Sheppo cv_init(&vport->write_cv, NULL, CV_DRIVER, NULL);
9651991Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING;
9661991Sheppo }
9671991Sheppo
9681991Sheppo vport = &vccp->port[VCC_CONTROL_PORT];
9691991Sheppo mutex_enter(&vport->lock);
9701991Sheppo
9711991Sheppo vport->minorp = &vccp->minor_tbl[VCC_CONTROL_MINOR_IDX];
9721991Sheppo vport->status |= VCC_PORT_AVAIL;
9731991Sheppo
9741991Sheppo /* create a minor node for vcc control */
9751991Sheppo minor = (instance << VCC_INST_SHIFT) | VCC_CONTROL_MINOR_IDX;
9761991Sheppo
9771991Sheppo vccp->minor_tbl[VCC_CONTROL_PORT].portno =
9781991Sheppo VCC_CONTROL_MINOR_IDX;
9791991Sheppo
9801991Sheppo
9811991Sheppo rv = ddi_create_minor_node(vccp->dip, "ctl", S_IFCHR, minor,
9821991Sheppo DDI_NT_SERIAL, 0);
9831991Sheppo
9841991Sheppo mutex_exit(&vport->lock);
9851991Sheppo
9861991Sheppo if (rv != DDI_SUCCESS) {
9871991Sheppo cmn_err(CE_CONT, "vcc_attach: error"
9881991Sheppo "creating control minor node\n");
9891991Sheppo
9901991Sheppo i_vcc_cleanup_port_table(vccp);
9911991Sheppo
9921991Sheppo mutex_exit(&vccp->lock);
9931991Sheppo /* clean up soft state */
9941991Sheppo ddi_soft_state_free(vccp, instance);
9951991Sheppo
9961991Sheppo return (DDI_FAILURE);
9971991Sheppo }
9981991Sheppo
9991991Sheppo /* get the instance number by reading 'reg' property */
10001991Sheppo inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
10011991Sheppo "reg", -1);
10021991Sheppo if (inst == -1) {
10031991Sheppo cmn_err(CE_CONT, "vcc_attach: vcc%d has no "
1004*7656SSherry.Moore@Sun.COM "'reg' property\n",
10051991Sheppo ddi_get_instance(dip));
10061991Sheppo
10071991Sheppo i_vcc_cleanup_port_table(vccp);
10081991Sheppo
10091991Sheppo /* remove minor */
10101991Sheppo ddi_remove_minor_node(vccp->dip, NULL);
10111991Sheppo
10121991Sheppo /* clean up soft state */
10131991Sheppo mutex_exit(&vccp->lock);
10141991Sheppo ddi_soft_state_free(vccp, instance);
10151991Sheppo
10161991Sheppo return (DDI_FAILURE);
10171991Sheppo }
10181991Sheppo
10191991Sheppo /*
10201991Sheppo * Mdeg might invoke callback in the same call sequence
10211991Sheppo * if there is a domain port at the time of registration.
10221991Sheppo * Since the callback also grabs vcc->lock mutex, to avoid
10231991Sheppo * mutex reentry error, release the lock before registration
10241991Sheppo */
10251991Sheppo mutex_exit(&vccp->lock);
10261991Sheppo
10271991Sheppo /* register for notifications from Zeus */
10281991Sheppo rv = i_vcc_mdeg_register(vccp, inst);
10291991Sheppo if (rv != MDEG_SUCCESS) {
10301991Sheppo cmn_err(CE_CONT, "vcc_attach: error register to MD\n");
10311991Sheppo
10321991Sheppo i_vcc_cleanup_port_table(vccp);
10331991Sheppo
10341991Sheppo /* remove minor */
10351991Sheppo ddi_remove_minor_node(vccp->dip, NULL);
10361991Sheppo
10371991Sheppo /* clean up soft state */
10381991Sheppo ddi_soft_state_free(vccp, instance);
10391991Sheppo
10401991Sheppo return (DDI_FAILURE);
10411991Sheppo }
10421991Sheppo
10431991Sheppo return (DDI_SUCCESS);
10441991Sheppo
10451991Sheppo case DDI_RESUME:
10461991Sheppo
10471991Sheppo return (DDI_SUCCESS);
10481991Sheppo
10491991Sheppo default:
10501991Sheppo
10511991Sheppo return (DDI_FAILURE);
10521991Sheppo }
10531991Sheppo }
10541991Sheppo
10551991Sheppo /*
10561991Sheppo * detach(9E): detach a device from the system.
10571991Sheppo */
10581991Sheppo static int
vcc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)10591991Sheppo vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
10601991Sheppo {
10611991Sheppo int i, instance;
10621991Sheppo vcc_t *vccp;
10631991Sheppo mdeg_node_spec_t *ispecp;
10641991Sheppo vcc_port_t *vport;
10651991Sheppo
10661991Sheppo switch (cmd) {
10671991Sheppo
10681991Sheppo case DDI_DETACH:
10691991Sheppo
10701991Sheppo instance = ddi_get_instance(dip);
10711991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
10721991Sheppo if (vccp == NULL)
10731991Sheppo return (ENXIO);
10741991Sheppo
10751991Sheppo D1("vcc_detach: DDI_DETACH instance=%d\n", instance);
10761991Sheppo
10771991Sheppo mutex_enter(&vccp->lock);
10781991Sheppo
10791991Sheppo /* unregister from MD event generator */
10801991Sheppo
10811991Sheppo ASSERT(vccp->mdeg_hdl);
10821991Sheppo (void) mdeg_unregister(vccp->mdeg_hdl);
10831991Sheppo
10841991Sheppo ispecp = (mdeg_node_spec_t *)vccp->md_ispecp;
10851991Sheppo ASSERT(ispecp);
10861991Sheppo
10871991Sheppo kmem_free(ispecp->specp, sizeof (vcc_prop_template));
10881991Sheppo kmem_free(ispecp, sizeof (mdeg_node_spec_t));
10891991Sheppo
10901991Sheppo /* remove minor nodes */
10911991Sheppo ddi_remove_minor_node(vccp->dip, NULL);
10921991Sheppo mutex_exit(&vccp->lock);
10931991Sheppo
10941991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
10951991Sheppo
10961991Sheppo vport = &vccp->port[i];
10971991Sheppo mutex_enter(&vport->lock);
10981991Sheppo if (i == VCC_CONTROL_PORT) {
10991991Sheppo if (vport->status & VCC_PORT_OPEN) {
11001991Sheppo (void) i_vcc_close_port(vport);
11011991Sheppo }
11021991Sheppo }
11031991Sheppo
11041991Sheppo if ((vccp->port[i].status & VCC_PORT_AVAIL) &&
11051991Sheppo (i != VCC_CONTROL_PORT)) {
11061991Sheppo D1("vcc_detach: removing port port@%d\n", i);
11071991Sheppo (void) i_vcc_delete_port(vccp, vport);
11081991Sheppo }
11091991Sheppo mutex_exit(&vport->lock);
11101991Sheppo cv_destroy(&vport->read_cv);
11111991Sheppo cv_destroy(&vport->write_cv);
11121991Sheppo mutex_destroy(&vport->lock);
11131991Sheppo }
11141991Sheppo
11151991Sheppo
11161991Sheppo
11171991Sheppo /* destroy mutex and free the soft state */
11181991Sheppo mutex_destroy(&vccp->lock);
11191991Sheppo ddi_soft_state_free(vcc_ssp, instance);
11201991Sheppo
11211991Sheppo return (DDI_SUCCESS);
11221991Sheppo
11231991Sheppo case DDI_SUSPEND:
11241991Sheppo
11251991Sheppo return (DDI_SUCCESS);
11261991Sheppo
11271991Sheppo default:
11281991Sheppo
11291991Sheppo return (DDI_FAILURE);
11301991Sheppo }
11311991Sheppo }
11321991Sheppo
11331991Sheppo /* cb_open */
11341991Sheppo static int
vcc_open(dev_t * devp,int flag,int otyp,cred_t * cred)11351991Sheppo vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred)
11361991Sheppo {
11371991Sheppo _NOTE(ARGUNUSED(otyp, cred))
11381991Sheppo
11391991Sheppo int instance;
11401991Sheppo int rv = EIO;
11411991Sheppo minor_t minor;
11421991Sheppo uint_t portno;
11431991Sheppo vcc_t *vccp;
11441991Sheppo vcc_port_t *vport;
11451991Sheppo
11461991Sheppo minor = getminor(*devp);
11471991Sheppo instance = VCCINST(minor);
11481991Sheppo
11491991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
11501991Sheppo if (vccp == NULL) {
11511991Sheppo return (ENXIO);
11521991Sheppo }
11531991Sheppo
11541991Sheppo portno = VCCPORT(vccp, minor);
11551991Sheppo
11561991Sheppo vport = &(vccp->port[portno]);
11571991Sheppo
11581991Sheppo mutex_enter(&vport->lock);
11591991Sheppo
11603151Ssg70180 if ((vport->status & VCC_PORT_AVAIL) == 0) {
11613151Ssg70180 /* port may be removed */
11623151Ssg70180 mutex_exit(&vport->lock);
11633151Ssg70180 return (ENXIO);
11643151Ssg70180 }
11653151Ssg70180
11661991Sheppo if (vport->status & VCC_PORT_OPEN) {
11671991Sheppo /* only one open per port */
11681991Sheppo cmn_err(CE_CONT, "vcc_open: virtual-console-concentrator@%d:%d "
11691991Sheppo "is already open\n", instance, portno);
11701991Sheppo mutex_exit(&vport->lock);
11711991Sheppo return (EAGAIN);
11721991Sheppo }
11731991Sheppo
11741991Sheppo /* check minor no and pid */
11751991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1176*7656SSherry.Moore@Sun.COM vport)) != 0) {
11771991Sheppo mutex_exit(&vport->lock);
11781991Sheppo return (rv);
11791991Sheppo }
11801991Sheppo
11811991Sheppo if (portno == VCC_CONTROL_PORT) {
11821991Sheppo vport->status |= VCC_PORT_OPEN;
11831991Sheppo mutex_exit(&vport->lock);
11841991Sheppo return (0);
11851991Sheppo }
11861991Sheppo
11873297Ssb155480 /*
11883297Ssb155480 * the port may just be added by mdeg callback and may
11893297Ssb155480 * not be configured yet.
11903297Ssb155480 */
11913297Ssb155480 if (vport->ldc_id == VCC_INVALID_CHANNEL) {
11923297Ssb155480 mutex_exit(&vport->lock);
11933297Ssb155480 return (ENXIO);
11943297Ssb155480 }
11953297Ssb155480
11961991Sheppo
11971991Sheppo /* check if channel has been initialized */
11981991Sheppo if ((vport->status & VCC_PORT_LDC_CHANNEL_READY) == 0) {
11991991Sheppo rv = i_vcc_ldc_init(vccp, vport);
12001991Sheppo if (rv) {
12011991Sheppo mutex_exit(&vport->lock);
12021991Sheppo return (EIO);
12031991Sheppo }
12041991Sheppo
12051991Sheppo /* mark port as ready */
12061991Sheppo vport->status |= VCC_PORT_LDC_CHANNEL_READY;
12071991Sheppo }
12081991Sheppo
12091991Sheppo vport->status |= VCC_PORT_USE_READ_LDC | VCC_PORT_USE_WRITE_LDC|
12101991Sheppo VCC_PORT_TERM_RD|VCC_PORT_TERM_WR|VCC_PORT_OPEN;
12111991Sheppo
12121991Sheppo if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
12131991Sheppo vport->status |= VCC_PORT_NONBLOCK;
12141991Sheppo }
12151991Sheppo
12161991Sheppo mutex_exit(&vport->lock);
12171991Sheppo
12181991Sheppo return (0);
12191991Sheppo }
12201991Sheppo
12211991Sheppo /* close port */
12221991Sheppo static int
i_vcc_close_port(vcc_port_t * vport)12231991Sheppo i_vcc_close_port(vcc_port_t *vport)
12241991Sheppo {
12251991Sheppo
12261991Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) {
12271991Sheppo return (0);
12281991Sheppo }
12291991Sheppo
12301991Sheppo ASSERT(mutex_owned(&vport->lock));
12311991Sheppo
12321991Sheppo if (vport->status & VCC_PORT_LDC_CHANNEL_READY) {
12331991Sheppo /* clean up ldc channel */
12343297Ssb155480 i_vcc_ldc_fini(vport);
12351991Sheppo vport->status &= ~VCC_PORT_LDC_CHANNEL_READY;
12361991Sheppo }
12371991Sheppo
12381991Sheppo /* reset rd/wr suspends */
12391991Sheppo vport->status |= VCC_PORT_TERM_RD | VCC_PORT_TERM_WR;
12401991Sheppo vport->status &= ~VCC_PORT_NONBLOCK;
12411991Sheppo vport->status &= ~VCC_PORT_OPEN;
12421991Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING;
12431991Sheppo
12441991Sheppo /* signal any blocked read and write thread */
12451991Sheppo cv_broadcast(&vport->read_cv);
12461991Sheppo cv_broadcast(&vport->write_cv);
12471991Sheppo
12481991Sheppo return (0);
12491991Sheppo }
12501991Sheppo
12511991Sheppo /* cb_close */
12521991Sheppo static int
vcc_close(dev_t dev,int flag,int otyp,cred_t * cred)12531991Sheppo vcc_close(dev_t dev, int flag, int otyp, cred_t *cred)
12541991Sheppo {
12551991Sheppo _NOTE(ARGUNUSED(flag, otyp, cred))
12561991Sheppo
12571991Sheppo int instance;
12581991Sheppo minor_t minor;
12591991Sheppo int rv = EIO;
12601991Sheppo uint_t portno;
12611991Sheppo vcc_t *vccp;
12621991Sheppo vcc_port_t *vport;
12631991Sheppo
12641991Sheppo minor = getminor(dev);
12651991Sheppo
12661991Sheppo instance = VCCINST(minor);
12671991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
12681991Sheppo if (vccp == NULL) {
12691991Sheppo return (ENXIO);
12701991Sheppo }
12711991Sheppo
12721991Sheppo portno = VCCPORT(vccp, minor);
12731991Sheppo
12741991Sheppo D1("vcc_close: closing virtual-console-concentrator@%d:%d\n",
12751991Sheppo instance, portno);
12761991Sheppo vport = &(vccp->port[portno]);
12771991Sheppo
12781991Sheppo
12793297Ssb155480 /*
12803297Ssb155480 * needs lock to provent i_vcc_delete_port, which is called by
12813297Ssb155480 * the mdeg callback, from closing port.
12823297Ssb155480 */
12833297Ssb155480 mutex_enter(&vport->lock);
12843297Ssb155480
12851991Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) {
12863297Ssb155480 mutex_exit(&vport->lock);
12871991Sheppo return (0);
12881991Sheppo }
12891991Sheppo
12901991Sheppo if (portno == VCC_CONTROL_PORT) {
12911991Sheppo /*
12921991Sheppo * vntsd closes control port before it exits. There
12931991Sheppo * could be events still pending for vntsd.
12941991Sheppo */
12953297Ssb155480 mutex_exit(&vport->lock);
12961991Sheppo rv = i_vcc_reset_events(vccp);
12971991Sheppo return (0);
12981991Sheppo }
12991991Sheppo
13001991Sheppo
13011991Sheppo /* check minor no and pid */
13021991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1303*7656SSherry.Moore@Sun.COM vport)) != 0) {
13041991Sheppo mutex_exit(&vport->lock);
13051991Sheppo return (rv);
13061991Sheppo }
13071991Sheppo
13081991Sheppo rv = i_vcc_close_port(vport);
13091991Sheppo mutex_exit(&vport->lock);
13101991Sheppo
13111991Sheppo return (rv);
13121991Sheppo }
13131991Sheppo
13141991Sheppo /*
13151991Sheppo * ioctl VCC_CONS_TBL - vntsd allocates buffer according to return of
13161991Sheppo * VCC_NUM_PORTS. However, when vntsd requests for the console table, console
13171991Sheppo * ports could be deleted or added. parameter num_ports is number of structures
13181991Sheppo * that vntsd allocated for the table. If there are more ports than
13191991Sheppo * num_ports, set up to wakeup vntsd to add ports.
13201991Sheppo * If there less ports than num_ports, fill (-1) for cons_no to tell vntsd.
13211991Sheppo */
13221991Sheppo static int
i_vcc_cons_tbl(vcc_t * vccp,uint_t num_ports,caddr_t buf,int mode)13231991Sheppo i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, caddr_t buf, int mode)
13241991Sheppo {
13251991Sheppo vcc_console_t cons;
13261991Sheppo int i;
13271991Sheppo vcc_port_t *vport;
13281991Sheppo boolean_t notify_vntsd = B_FALSE;
13291991Sheppo char pathname[MAXPATHLEN];
13301991Sheppo
13311991Sheppo
13321991Sheppo (void) ddi_pathname(vccp->dip, pathname);
13331991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
13341991Sheppo
13351991Sheppo vport = &vccp->port[i];
13361991Sheppo
13371991Sheppo if (i == VCC_CONTROL_PORT) {
13381991Sheppo continue;
13391991Sheppo }
13401991Sheppo
13411991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
13421991Sheppo continue;
13431991Sheppo }
13441991Sheppo
13451991Sheppo /* a port exists before vntsd becomes online */
13461991Sheppo mutex_enter(&vport->lock);
13471991Sheppo
13481991Sheppo if (num_ports == 0) {
13491991Sheppo /* more ports than vntsd's buffer can hold */
13501991Sheppo vport->status |= VCC_PORT_ADDED;
13511991Sheppo notify_vntsd = B_TRUE;
13521991Sheppo mutex_exit(&vport->lock);
13531991Sheppo continue;
13541991Sheppo }
13551991Sheppo
13561991Sheppo bzero(&cons, sizeof (vcc_console_t));
13571991Sheppo
13581991Sheppo /* construct console buffer */
13591991Sheppo cons.cons_no = vport->number;
13601991Sheppo cons.tcp_port = vport->tcp_port;
13611991Sheppo (void) memcpy(cons.domain_name,
13621991Sheppo vport->minorp->domain_name, MAXPATHLEN);
13631991Sheppo
13641991Sheppo (void) memcpy(cons.group_name, vport->group_name,
13651991Sheppo MAXPATHLEN);
13661991Sheppo vport->status &= ~VCC_PORT_ADDED;
13671991Sheppo mutex_exit(&vport->lock);
13681991Sheppo
13691991Sheppo (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s",
13701991Sheppo pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name);
13711991Sheppo
13721991Sheppo /* copy out data */
13731991Sheppo if (ddi_copyout(&cons, (void *)buf,
1374*7656SSherry.Moore@Sun.COM sizeof (vcc_console_t), mode)) {
13751991Sheppo mutex_exit(&vport->lock);
13761991Sheppo return (EFAULT);
13771991Sheppo }
13781991Sheppo buf += sizeof (vcc_console_t);
13791991Sheppo
13801991Sheppo num_ports--;
13811991Sheppo
13821991Sheppo }
13831991Sheppo
13841991Sheppo if (num_ports == 0) {
13851991Sheppo /* vntsd's buffer is full */
13861991Sheppo
13871991Sheppo if (notify_vntsd) {
13881991Sheppo /* more ports need to notify vntsd */
13891991Sheppo vport = &vccp->port[VCC_CONTROL_PORT];
13901991Sheppo mutex_enter(&vport->lock);
13911991Sheppo vport->pollevent |= VCC_POLL_ADD_PORT;
13921991Sheppo mutex_exit(&vport->lock);
13931991Sheppo }
13941991Sheppo
13951991Sheppo return (0);
13961991Sheppo }
13971991Sheppo
13981991Sheppo /* less ports than vntsd expected */
13991991Sheppo bzero(&cons, sizeof (vcc_console_t));
14001991Sheppo cons.cons_no = -1;
14011991Sheppo
14021991Sheppo while (num_ports > 0) {
14031991Sheppo /* fill vntsd buffer with no console */
14041991Sheppo if (ddi_copyout(&cons, (void *)buf,
1405*7656SSherry.Moore@Sun.COM sizeof (vcc_console_t), mode) != 0) {
14061991Sheppo mutex_exit(&vport->lock);
14071991Sheppo return (EFAULT);
14081991Sheppo }
14091991Sheppo D1("i_vcc_cons_tbl: a port is deleted\n");
14101991Sheppo buf += sizeof (vcc_console_t) +MAXPATHLEN;
14111991Sheppo num_ports--;
14121991Sheppo }
14131991Sheppo
14141991Sheppo return (0);
14151991Sheppo }
14161991Sheppo
14171991Sheppo
14181991Sheppo /* turn off event flag if there is no more change */
14191991Sheppo static void
i_vcc_turn_off_event(vcc_t * vccp,uint32_t port_status,uint32_t event)14201991Sheppo i_vcc_turn_off_event(vcc_t *vccp, uint32_t port_status, uint32_t event)
14211991Sheppo {
14221991Sheppo
14231991Sheppo vcc_port_t *vport;
14241991Sheppo int i;
14251991Sheppo
14261991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
14271991Sheppo
14281991Sheppo vport = &(vccp->port[i]);
14291991Sheppo
14301991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
14311991Sheppo continue;
14321991Sheppo }
14331991Sheppo
14341991Sheppo
14351991Sheppo if (vport->status & port_status) {
14361991Sheppo /* more port changes status */
14371991Sheppo return;
14381991Sheppo }
14391991Sheppo
14401991Sheppo }
14411991Sheppo
14421991Sheppo /* no more changed port */
14431991Sheppo vport = &vccp->port[VCC_CONTROL_PORT];
14441991Sheppo
14451991Sheppo /* turn off event */
14461991Sheppo mutex_enter(&vport->lock);
14471991Sheppo vport->pollevent &= ~event;
14481991Sheppo mutex_exit(&vport->lock);
14491991Sheppo }
14501991Sheppo
14511991Sheppo /* ioctl VCC_CONS_INFO */
14521991Sheppo static int
i_vcc_cons_info(vcc_t * vccp,caddr_t buf,int mode)14531991Sheppo i_vcc_cons_info(vcc_t *vccp, caddr_t buf, int mode)
14541991Sheppo {
14551991Sheppo vcc_console_t cons;
14561991Sheppo uint_t portno;
14571991Sheppo vcc_port_t *vport;
14581991Sheppo char pathname[MAXPATHLEN];
14591991Sheppo
14601991Sheppo /* read in portno */
14611991Sheppo if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) {
14621991Sheppo return (EFAULT);
14631991Sheppo }
14641991Sheppo
14651991Sheppo D1("i_vcc_cons_info@%d:\n", portno);
14661991Sheppo
14671991Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
14681991Sheppo return (EINVAL);
14691991Sheppo }
14701991Sheppo
14711991Sheppo vport = &vccp->port[portno];
14721991Sheppo
14731991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
14741991Sheppo return (EINVAL);
14751991Sheppo }
14761991Sheppo
14771991Sheppo mutex_enter(&vport->lock);
14781991Sheppo vport->status &= ~VCC_PORT_ADDED;
14791991Sheppo
14801991Sheppo /* construct configruation data */
14811991Sheppo bzero(&cons, sizeof (vcc_console_t));
14821991Sheppo
14831991Sheppo cons.cons_no = vport->number;
14841991Sheppo cons.tcp_port = vport->tcp_port;
14851991Sheppo
14861991Sheppo (void) memcpy(cons.domain_name, vport->minorp->domain_name, MAXPATHLEN);
14871991Sheppo
14881991Sheppo (void) memcpy(cons.group_name, vport->group_name, MAXPATHLEN);
14891991Sheppo
14901991Sheppo mutex_exit(&vport->lock);
14911991Sheppo
14921991Sheppo (void) ddi_pathname(vccp->dip, pathname),
14931991Sheppo
1494*7656SSherry.Moore@Sun.COM /* copy device name */
1495*7656SSherry.Moore@Sun.COM (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s",
14961991Sheppo pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name);
14971991Sheppo /* copy data */
14981991Sheppo if (ddi_copyout(&cons, (void *)buf,
1499*7656SSherry.Moore@Sun.COM sizeof (vcc_console_t), mode) != 0) {
15001991Sheppo mutex_exit(&vport->lock);
15011991Sheppo return (EFAULT);
15021991Sheppo }
15031991Sheppo
15041991Sheppo D1("i_vcc_cons_info@%d:domain:%s serv:%s tcp@%lld %s\n",
15051991Sheppo cons.cons_no, cons.domain_name,
15061991Sheppo cons.group_name, cons.tcp_port, cons.dev_name);
15071991Sheppo
15081991Sheppo i_vcc_turn_off_event(vccp, VCC_PORT_ADDED, VCC_POLL_ADD_PORT);
15091991Sheppo
15101991Sheppo return (0);
15111991Sheppo }
15121991Sheppo
15131991Sheppo
15141991Sheppo /* response to vntsd inquiry ioctl call */
15151991Sheppo static int
i_vcc_inquiry(vcc_t * vccp,caddr_t buf,int mode)15161991Sheppo i_vcc_inquiry(vcc_t *vccp, caddr_t buf, int mode)
15171991Sheppo {
15181991Sheppo vcc_port_t *vport;
15191991Sheppo uint_t i;
15201991Sheppo vcc_response_t msg;
15211991Sheppo
15221991Sheppo vport = &(vccp->port[VCC_CONTROL_PORT]);
15231991Sheppo
15241991Sheppo if ((vport->pollevent & VCC_POLL_ADD_PORT) == 0) {
15251991Sheppo return (EINVAL);
15261991Sheppo }
15271991Sheppo
15283151Ssg70180 /* an added port */
15291991Sheppo
15301991Sheppo D1("i_vcc_inquiry\n");
15311991Sheppo
15321991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
15331991Sheppo if ((vccp->port[i].status & VCC_PORT_AVAIL) == 0) {
15341991Sheppo continue;
15351991Sheppo }
15361991Sheppo
15371991Sheppo if (vccp->port[i].status & VCC_PORT_ADDED) {
15381991Sheppo /* port added */
15391991Sheppo msg.reason = VCC_CONS_ADDED;
15401991Sheppo msg.cons_no = i;
15411991Sheppo
15421991Sheppo if (ddi_copyout((void *)&msg, (void *)buf,
1543*7656SSherry.Moore@Sun.COM sizeof (msg), mode) == -1) {
15441991Sheppo cmn_err(CE_CONT, "i_vcc_find_changed_port:"
1545*7656SSherry.Moore@Sun.COM "ddi_copyout"
15461991Sheppo " failed\n");
15471991Sheppo return (EFAULT);
15481991Sheppo }
15491991Sheppo return (0);
15501991Sheppo }
15511991Sheppo }
15521991Sheppo
15532748Slm66018 /* the added port was deleted before vntsd wakes up */
15542748Slm66018 msg.reason = VCC_CONS_MISS_ADDED;
15552748Slm66018
15562748Slm66018 if (ddi_copyout((void *)&msg, (void *)buf,
1557*7656SSherry.Moore@Sun.COM sizeof (msg), mode) == -1) {
15582748Slm66018 cmn_err(CE_CONT, "i_vcc_find_changed_port: ddi_copyout"
15592748Slm66018 " failed\n");
15602748Slm66018 return (EFAULT);
15612748Slm66018 }
15622748Slm66018
15632748Slm66018 return (0);
15641991Sheppo }
15651991Sheppo
15661991Sheppo /* clean up events after vntsd exits */
15671991Sheppo static int
i_vcc_reset_events(vcc_t * vccp)15681991Sheppo i_vcc_reset_events(vcc_t *vccp)
15691991Sheppo {
15701991Sheppo uint_t i;
15711991Sheppo vcc_port_t *vport;
15721991Sheppo
15731991Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) {
15741991Sheppo vport = &(vccp->port[i]);
15751991Sheppo
15761991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
15771991Sheppo continue;
15781991Sheppo }
15791991Sheppo
15801991Sheppo ASSERT(!mutex_owned(&vport->lock));
15811991Sheppo
15821991Sheppo if (i == VCC_CONTROL_PORT) {
15831991Sheppo /* close control port */
15841991Sheppo mutex_enter(&vport->lock);
15851991Sheppo vport->status &= ~VCC_PORT_OPEN;
15861991Sheppo
15871991Sheppo /* clean up poll events */
15881991Sheppo vport->pollevent = 0;
15891991Sheppo vport->pollflag = 0;
15901991Sheppo mutex_exit(&vport->lock);
15911991Sheppo continue;
15921991Sheppo }
15931991Sheppo if (vport->status & VCC_PORT_ADDED) {
15941991Sheppo /* pending added port event to vntsd */
15951991Sheppo mutex_enter(&vport->lock);
15961991Sheppo vport->status &= ~VCC_PORT_ADDED;
15971991Sheppo mutex_exit(&vport->lock);
15981991Sheppo }
15991991Sheppo
16001991Sheppo }
16011991Sheppo
16021991Sheppo vport = &vccp->port[VCC_CONTROL_PORT];
16031991Sheppo
16041991Sheppo return (0);
16051991Sheppo }
16061991Sheppo
16071991Sheppo /* ioctl VCC_FORCE_CLOSE */
16081991Sheppo static int
i_vcc_force_close(vcc_t * vccp,caddr_t buf,int mode)16091991Sheppo i_vcc_force_close(vcc_t *vccp, caddr_t buf, int mode)
16101991Sheppo {
16111991Sheppo uint_t portno;
16121991Sheppo vcc_port_t *vport;
16131991Sheppo int rv;
16141991Sheppo
16151991Sheppo /* read in portno */
16161991Sheppo if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) {
16171991Sheppo return (EFAULT);
16181991Sheppo }
16191991Sheppo
16201991Sheppo D1("i_vcc_force_close@%d:\n", portno);
16211991Sheppo
16221991Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) {
16231991Sheppo return (EINVAL);
16241991Sheppo }
16251991Sheppo
16261991Sheppo vport = &vccp->port[portno];
16271991Sheppo
16281991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
16291991Sheppo return (EINVAL);
16301991Sheppo }
16311991Sheppo
16321991Sheppo mutex_enter(&vport->lock);
16331991Sheppo
16341991Sheppo rv = i_vcc_close_port(vport);
16351991Sheppo
16361991Sheppo /* block callers other than vntsd */
16371991Sheppo vport->valid_pid = ddi_get_pid();
16381991Sheppo
16391991Sheppo mutex_exit(&vport->lock);
16401991Sheppo return (rv);
16411991Sheppo
16421991Sheppo }
16431991Sheppo
16441991Sheppo /* ioctl VCC_CONS_STATUS */
16451991Sheppo static int
i_vcc_cons_status(vcc_t * vccp,caddr_t buf,int mode)16461991Sheppo i_vcc_cons_status(vcc_t *vccp, caddr_t buf, int mode)
16471991Sheppo {
16481991Sheppo vcc_console_t console;
16491991Sheppo vcc_port_t *vport;
16501991Sheppo
16511991Sheppo /* read in portno */
16521991Sheppo if (ddi_copyin((void*)buf, &console, sizeof (console), mode)) {
16531991Sheppo return (EFAULT);
16541991Sheppo }
16551991Sheppo
16561991Sheppo D1("i_vcc_cons_status@%d:\n", console.cons_no);
16571991Sheppo
16581991Sheppo if ((console.cons_no >= VCC_MAX_PORTS) ||
1659*7656SSherry.Moore@Sun.COM (console.cons_no == VCC_CONTROL_PORT)) {
16601991Sheppo return (EINVAL);
16611991Sheppo }
16621991Sheppo
16631991Sheppo
16641991Sheppo vport = &vccp->port[console.cons_no];
16651991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
16661991Sheppo console.cons_no = -1;
16671991Sheppo } else if (strncmp(console.domain_name, vport->minorp->domain_name,
1668*7656SSherry.Moore@Sun.COM MAXPATHLEN)) {
16691991Sheppo console.cons_no = -1;
16701991Sheppo } else if (strncmp(console.group_name, vport->group_name,
1671*7656SSherry.Moore@Sun.COM MAXPATHLEN)) {
16721991Sheppo console.cons_no = -1;
16731991Sheppo } else if (console.tcp_port != vport->tcp_port) {
16741991Sheppo console.cons_no = -1;
16753151Ssg70180 } else if (vport->ldc_id == VCC_INVALID_CHANNEL) {
16763151Ssg70180 console.cons_no = -1;
16771991Sheppo }
16781991Sheppo
16791991Sheppo D1("i_vcc_cons_status@%d: %s %s %llx\n", console.cons_no,
16801991Sheppo console.group_name, console.domain_name, console.tcp_port);
16811991Sheppo if (ddi_copyout(&console, (void *)buf, sizeof (console), mode) == -1) {
16821991Sheppo cmn_err(CE_CONT, "i_vcc_cons_status ddi_copyout failed\n");
16831991Sheppo return (EFAULT);
16841991Sheppo }
16851991Sheppo
16861991Sheppo return (0);
16871991Sheppo }
16881991Sheppo
16891991Sheppo /* cb_ioctl handler for vcc control port */
16901991Sheppo static int
i_vcc_ctrl_ioctl(vcc_t * vccp,int cmd,void * arg,int mode)16911991Sheppo i_vcc_ctrl_ioctl(vcc_t *vccp, int cmd, void* arg, int mode)
16921991Sheppo {
16931991Sheppo
16941991Sheppo static uint_t num_ports;
16951991Sheppo
16961991Sheppo
16971991Sheppo switch (cmd) {
16981991Sheppo
16991991Sheppo case VCC_NUM_CONSOLE:
17001991Sheppo
17011991Sheppo mutex_enter(&vccp->lock);
17021991Sheppo num_ports = vccp->num_ports;
17031991Sheppo mutex_exit(&vccp->lock);
17041991Sheppo /* number of consoles */
17051991Sheppo
17061991Sheppo return (ddi_copyout((void *)&num_ports, arg,
1707*7656SSherry.Moore@Sun.COM sizeof (int), mode));
17081991Sheppo case VCC_CONS_TBL:
17091991Sheppo
17101991Sheppo /* console config table */
17111991Sheppo return (i_vcc_cons_tbl(vccp, num_ports, (caddr_t)arg, mode));
17121991Sheppo
17131991Sheppo case VCC_INQUIRY:
17141991Sheppo
17151991Sheppo /* reason for wakeup */
17161991Sheppo return (i_vcc_inquiry(vccp, (caddr_t)arg, mode));
17171991Sheppo
17181991Sheppo case VCC_CONS_INFO:
17191991Sheppo /* a console config */
17201991Sheppo return (i_vcc_cons_info(vccp, (caddr_t)arg, mode));
17211991Sheppo
17221991Sheppo case VCC_FORCE_CLOSE:
17231991Sheppo /* force to close a console */
17241991Sheppo return (i_vcc_force_close(vccp, (caddr_t)arg, mode));
17251991Sheppo
17261991Sheppo case VCC_CONS_STATUS:
17271991Sheppo /* console status */
17281991Sheppo return (i_vcc_cons_status(vccp, (caddr_t)arg, mode));
17291991Sheppo
17301991Sheppo default:
17311991Sheppo
17321991Sheppo /* unknown command */
17331991Sheppo return (ENODEV);
17341991Sheppo }
17351991Sheppo
17361991Sheppo
17371991Sheppo }
17381991Sheppo
17391991Sheppo /* write data to ldc. may block if channel has no space for write */
17401991Sheppo static int
i_vcc_write_ldc(vcc_port_t * vport,vcc_msg_t * buf)17411991Sheppo i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf)
17421991Sheppo {
17431991Sheppo int rv = EIO;
17441991Sheppo size_t size;
17451991Sheppo
17461991Sheppo ASSERT(mutex_owned(&vport->lock));
17471991Sheppo ASSERT((vport->status & VCC_PORT_USE_WRITE_LDC) == 0);
17481991Sheppo
17491991Sheppo for (; ; ) {
17501991Sheppo
17511991Sheppo size = VCC_HDR_SZ + buf->size;
17521991Sheppo rv = ldc_write(vport->ldc_handle, (caddr_t)buf, &size);
17531991Sheppo
17541991Sheppo D1("i_vcc_write_ldc: port@%d: err=%d %d bytes\n",
17551991Sheppo vport->number, rv, size);
17561991Sheppo
17571991Sheppo if (rv == 0) {
17581991Sheppo return (rv);
17591991Sheppo }
17601991Sheppo
17611991Sheppo if (rv != EWOULDBLOCK) {
17621991Sheppo return (EIO);
17631991Sheppo }
17641991Sheppo
17651991Sheppo if (vport->status & VCC_PORT_NONBLOCK) {
17661991Sheppo return (EAGAIN);
17671991Sheppo }
17681991Sheppo
17691991Sheppo /* block util ldc has more space */
17701991Sheppo
17711991Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv,
17721991Sheppo VCC_PORT_LDC_WRITE_READY);
17731991Sheppo
17741991Sheppo if (rv) {
17751991Sheppo return (rv);
17761991Sheppo }
17771991Sheppo
17781991Sheppo vport->status &= ~VCC_PORT_LDC_WRITE_READY;
17791991Sheppo
17801991Sheppo }
17811991Sheppo
17821991Sheppo }
17831991Sheppo
17841991Sheppo
17851991Sheppo
17861991Sheppo /* cb_ioctl handler for port ioctl */
17871991Sheppo static int
i_vcc_port_ioctl(vcc_t * vccp,minor_t minor,int portno,int cmd,void * arg,int mode)17881991Sheppo i_vcc_port_ioctl(vcc_t *vccp, minor_t minor, int portno, int cmd, void *arg,
17891991Sheppo int mode)
17901991Sheppo {
17911991Sheppo
17921991Sheppo vcc_port_t *vport;
17931991Sheppo struct termios term;
17941991Sheppo vcc_msg_t buf;
17951991Sheppo int rv;
17961991Sheppo
17971991Sheppo D1("i_vcc_port_ioctl@%d cmd %d\n", portno, cmd);
17981991Sheppo
17991991Sheppo vport = &(vccp->port[portno]);
18001991Sheppo
18011991Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) {
18021991Sheppo return (EIO);
18031991Sheppo }
18041991Sheppo
18051991Sheppo
18061991Sheppo switch (cmd) {
18071991Sheppo
18081991Sheppo /* terminal support */
18091991Sheppo case TCGETA:
18101991Sheppo case TCGETS:
18111991Sheppo
18121991Sheppo mutex_enter(&vport->lock);
18131991Sheppo
18141991Sheppo /* check minor no and pid */
18151991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1816*7656SSherry.Moore@Sun.COM vport)) != 0) {
18171991Sheppo mutex_exit(&vport->lock);
18181991Sheppo return (rv);
18191991Sheppo }
18201991Sheppo
18211991Sheppo (void) memcpy(&term, &vport->term, sizeof (term));
18221991Sheppo mutex_exit(&vport->lock);
18231991Sheppo
18241991Sheppo return (ddi_copyout(&term, arg, sizeof (term), mode));
18251991Sheppo
18261991Sheppo case TCSETS:
18271991Sheppo case TCSETA:
18281991Sheppo case TCSETAW:
18291991Sheppo case TCSETAF:
18301991Sheppo
18311991Sheppo if (ddi_copyin(arg, &term, sizeof (term), mode) != 0) {
18321991Sheppo return (EFAULT);
18331991Sheppo }
18341991Sheppo
18351991Sheppo mutex_enter(&vport->lock);
18361991Sheppo
18371991Sheppo /* check minor no and pid */
18381991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1839*7656SSherry.Moore@Sun.COM vport)) != 0) {
18401991Sheppo mutex_exit(&vport->lock);
18411991Sheppo return (rv);
18421991Sheppo }
18431991Sheppo
18441991Sheppo (void) memcpy(&vport->term, &term, sizeof (term));
18451991Sheppo mutex_exit(&vport->lock);
18461991Sheppo return (0);
18471991Sheppo
18481991Sheppo
18491991Sheppo case TCSBRK:
18501991Sheppo
18511991Sheppo /* send break to console */
18521991Sheppo mutex_enter(&vport->lock);
18531991Sheppo
18541991Sheppo /* check minor no and pid */
18551991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1856*7656SSherry.Moore@Sun.COM vport)) != 0) {
18571991Sheppo mutex_exit(&vport->lock);
18581991Sheppo return (rv);
18591991Sheppo }
18601991Sheppo
18611991Sheppo /* wait for write available */
18621991Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv,
18631991Sheppo VCC_PORT_LDC_CHANNEL_READY| VCC_PORT_USE_WRITE_LDC);
18641991Sheppo if (rv) {
18651991Sheppo mutex_exit(&vport->lock);
18661991Sheppo return (rv);
18671991Sheppo }
18681991Sheppo
18691991Sheppo vport->status &= ~VCC_PORT_USE_WRITE_LDC;
18701991Sheppo
18711991Sheppo buf.type = LDC_CONSOLE_CTRL;
18721991Sheppo buf.ctrl_msg = LDC_CONSOLE_BREAK;
18731991Sheppo buf.size = 0;
18741991Sheppo
18751991Sheppo rv = i_vcc_write_ldc(vport, &buf);
18761991Sheppo
18771991Sheppo mutex_exit(&vport->lock);
18781991Sheppo
18791991Sheppo i_vcc_set_port_status(vport, &vport->write_cv,
1880*7656SSherry.Moore@Sun.COM VCC_PORT_USE_WRITE_LDC);
18811991Sheppo return (0);
18821991Sheppo
18831991Sheppo case TCXONC:
18841991Sheppo /* suspend read or write */
18851991Sheppo if (ddi_copyin(arg, &cmd, sizeof (int), mode) != 0) {
18861991Sheppo return (EFAULT);
18871991Sheppo }
18881991Sheppo
18891991Sheppo mutex_enter(&vport->lock);
18901991Sheppo
18911991Sheppo /* check minor no and pid */
18921991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
1893*7656SSherry.Moore@Sun.COM vport)) != 0) {
18941991Sheppo mutex_exit(&vport->lock);
18951991Sheppo return (rv);
18961991Sheppo }
18971991Sheppo
18981991Sheppo
18991991Sheppo switch (cmd) {
19001991Sheppo
19011991Sheppo case 0:
19022748Slm66018 /* suspend read */
19032748Slm66018 vport->status &= ~VCC_PORT_TERM_RD;
19042748Slm66018 break;
19052748Slm66018
19062748Slm66018 case 1:
19072748Slm66018 /* resume read */
19082748Slm66018 vport->status |= VCC_PORT_TERM_RD;
19092748Slm66018 cv_broadcast(&vport->read_cv);
19102748Slm66018 break;
19112748Slm66018
19122748Slm66018 case 2:
19132748Slm66018 /* suspend write */
19142748Slm66018 vport->status &= ~VCC_PORT_TERM_WR;
19152748Slm66018 break;
19162748Slm66018
19172748Slm66018 case 3:
19182748Slm66018 /* resume write */
19191991Sheppo vport->status |= VCC_PORT_TERM_WR;
19201991Sheppo cv_broadcast(&vport->write_cv);
19211991Sheppo break;
19221991Sheppo
19231991Sheppo default:
19242748Slm66018 mutex_exit(&vport->lock);
19252748Slm66018 return (EINVAL);
19261991Sheppo }
19271991Sheppo
19281991Sheppo mutex_exit(&vport->lock);
19291991Sheppo return (0);
19301991Sheppo
19311991Sheppo case TCFLSH:
19321991Sheppo return (0);
19331991Sheppo
19341991Sheppo default:
19352748Slm66018 return (EINVAL);
19361991Sheppo }
19371991Sheppo
19381991Sheppo }
19391991Sheppo
19401991Sheppo /* cb_ioctl */
19411991Sheppo static int
vcc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)19421991Sheppo vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
19431991Sheppo cred_t *credp, int *rvalp)
19441991Sheppo {
19451991Sheppo _NOTE(ARGUNUSED(credp, rvalp))
19461991Sheppo
19471991Sheppo int instance;
19481991Sheppo minor_t minor;
19491991Sheppo int portno;
19501991Sheppo vcc_t *vccp;
19511991Sheppo
19521991Sheppo minor = getminor(dev);
19531991Sheppo
19541991Sheppo instance = VCCINST(minor);
19551991Sheppo
19561991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
19571991Sheppo if (vccp == NULL) {
19581991Sheppo return (ENXIO);
19591991Sheppo }
19601991Sheppo
19611991Sheppo portno = VCCPORT(vccp, minor);
19621991Sheppo
19631991Sheppo D1("vcc_ioctl: virtual-console-concentrator@%d:%d\n", instance, portno);
19641991Sheppo
19651991Sheppo if (portno >= VCC_MAX_PORTS) {
19661991Sheppo cmn_err(CE_CONT, "vcc_ioctl:virtual-console-concentrator@%d"
1967*7656SSherry.Moore@Sun.COM " invalid portno\n", portno);
19681991Sheppo return (EINVAL);
19691991Sheppo }
19701991Sheppo
19711991Sheppo D1("vcc_ioctl: virtual-console-concentrator@%d:%d ioctl cmd=%d\n",
19721991Sheppo instance, portno, cmd);
19731991Sheppo
19741991Sheppo if (portno == VCC_CONTROL_PORT) {
19751991Sheppo /* control ioctl */
19761991Sheppo return (i_vcc_ctrl_ioctl(vccp, cmd, (void *)arg, mode));
19771991Sheppo }
19781991Sheppo
19791991Sheppo /* data port ioctl */
19801991Sheppo return (i_vcc_port_ioctl(vccp, minor, portno, cmd, (void *)arg, mode));
19811991Sheppo }
19821991Sheppo
19831991Sheppo /* cb_read */
19841991Sheppo static int
vcc_read(dev_t dev,struct uio * uiop,cred_t * credp)19851991Sheppo vcc_read(dev_t dev, struct uio *uiop, cred_t *credp)
19861991Sheppo {
19871991Sheppo _NOTE(ARGUNUSED(credp))
19881991Sheppo
19891991Sheppo int instance;
19901991Sheppo minor_t minor;
19911991Sheppo uint_t portno;
19921991Sheppo vcc_t *vccp;
19931991Sheppo vcc_port_t *vport;
19941991Sheppo int rv = EIO; /* by default fail ! */
19951991Sheppo char *buf;
19961991Sheppo size_t uio_size;
19971991Sheppo size_t size;
19981991Sheppo
19991991Sheppo minor = getminor(dev);
20001991Sheppo
20011991Sheppo instance = VCCINST(minor);
20021991Sheppo
20031991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
20041991Sheppo if (vccp == NULL) {
20051991Sheppo return (ENXIO);
20061991Sheppo }
20071991Sheppo
20081991Sheppo portno = VCCPORT(vccp, minor);
20091991Sheppo
20101991Sheppo /* no read for control port */
20111991Sheppo if (portno == VCC_CONTROL_PORT) {
20121991Sheppo return (EIO);
20131991Sheppo }
20141991Sheppo
20151991Sheppo /* temp buf to hold ldc data */
20161991Sheppo uio_size = uiop->uio_resid;
20171991Sheppo
20181991Sheppo if (uio_size < VCC_MTU_SZ) {
20191991Sheppo return (EINVAL);
20201991Sheppo }
20211991Sheppo
20221991Sheppo vport = &(vccp->port[portno]);
20231991Sheppo
20241991Sheppo mutex_enter(&vport->lock);
20251991Sheppo
20261991Sheppo /* check minor no and pid */
20271991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
2028*7656SSherry.Moore@Sun.COM vport)) != 0) {
20291991Sheppo mutex_exit(&vport->lock);
20301991Sheppo return (rv);
20311991Sheppo }
20321991Sheppo
20331991Sheppo rv = i_vcc_wait_port_status(vport, &vport->read_cv,
2034*7656SSherry.Moore@Sun.COM VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY|
2035*7656SSherry.Moore@Sun.COM VCC_PORT_USE_READ_LDC);
20361991Sheppo if (rv) {
20371991Sheppo mutex_exit(&vport->lock);
20381991Sheppo return (rv);
20391991Sheppo }
20401991Sheppo
20411991Sheppo buf = kmem_alloc(uio_size, KM_SLEEP);
20421991Sheppo
20431991Sheppo vport->status &= ~VCC_PORT_USE_READ_LDC;
20441991Sheppo
20451991Sheppo for (; ; ) {
20461991Sheppo
20471991Sheppo size = uio_size;
20481991Sheppo rv = i_vcc_read_ldc(vport, buf, &size);
20491991Sheppo
20501991Sheppo
20511991Sheppo if (rv == EAGAIN) {
20521991Sheppo /* should block? */
20531991Sheppo if (vport->status & VCC_PORT_NONBLOCK) {
20541991Sheppo break;
20551991Sheppo }
20561991Sheppo
20571991Sheppo } else if (rv) {
20581991Sheppo /* error */
20591991Sheppo break;
20601991Sheppo }
20611991Sheppo
20621991Sheppo if (size > 0) {
20631991Sheppo /* got data */
20641991Sheppo break;
20651991Sheppo }
20661991Sheppo
20671991Sheppo /* wait for data from ldc */
20681991Sheppo vport->status &= ~VCC_PORT_LDC_DATA_READY;
20692748Slm66018
20702748Slm66018 mutex_exit(&vport->lock);
20712748Slm66018 i_vcc_set_port_status(vport, &vport->read_cv,
20722748Slm66018 VCC_PORT_USE_READ_LDC);
20732748Slm66018 mutex_enter(&vport->lock);
20742748Slm66018
20751991Sheppo rv = i_vcc_wait_port_status(vport, &vport->read_cv,
20762748Slm66018 VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY|
20772748Slm66018 VCC_PORT_USE_READ_LDC| VCC_PORT_LDC_DATA_READY);
20781991Sheppo if (rv) {
20791991Sheppo break;
20801991Sheppo }
20812748Slm66018
20822748Slm66018 vport->status &= ~VCC_PORT_USE_READ_LDC;
20831991Sheppo }
20841991Sheppo
20851991Sheppo mutex_exit(&vport->lock);
20861991Sheppo
20871991Sheppo if ((rv == 0) && (size > 0)) {
20881991Sheppo /* data is in buf */
20891991Sheppo rv = uiomove(buf, size, UIO_READ, uiop);
20901991Sheppo }
20911991Sheppo
20921991Sheppo kmem_free(buf, uio_size);
20931991Sheppo i_vcc_set_port_status(vport, &vport->read_cv, VCC_PORT_USE_READ_LDC);
20941991Sheppo
20951991Sheppo return (rv);
20961991Sheppo }
20971991Sheppo
20981991Sheppo
20991991Sheppo /* cb_write */
21001991Sheppo static int
vcc_write(dev_t dev,struct uio * uiop,cred_t * credp)21011991Sheppo vcc_write(dev_t dev, struct uio *uiop, cred_t *credp)
21021991Sheppo {
21031991Sheppo _NOTE(ARGUNUSED(credp))
21041991Sheppo
21051991Sheppo int instance;
21061991Sheppo minor_t minor;
21071991Sheppo size_t size;
21081991Sheppo size_t bytes;
21091991Sheppo uint_t portno;
21101991Sheppo vcc_t *vccp;
21111991Sheppo
21121991Sheppo vcc_port_t *vport;
21131991Sheppo int rv = EIO;
21141991Sheppo
21151991Sheppo vcc_msg_t buf;
21161991Sheppo
21171991Sheppo minor = getminor(dev);
21181991Sheppo
21191991Sheppo instance = VCCINST(minor);
21201991Sheppo
21211991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
21221991Sheppo if (vccp == NULL) {
21231991Sheppo return (ENXIO);
21241991Sheppo }
21251991Sheppo
21261991Sheppo portno = VCCPORT(vccp, minor);
21271991Sheppo
21281991Sheppo /* no write for control port */
21291991Sheppo if (portno == VCC_CONTROL_PORT) {
21301991Sheppo return (EIO);
21311991Sheppo }
21321991Sheppo vport = &(vccp->port[portno]);
21331991Sheppo
21341991Sheppo /*
21351991Sheppo * check if the channel has been configured,
21361991Sheppo * if write has been suspend and grab write lock.
21371991Sheppo */
21381991Sheppo mutex_enter(&vport->lock);
21391991Sheppo
21401991Sheppo /* check minor no and pid */
21411991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
2142*7656SSherry.Moore@Sun.COM vport)) != 0) {
21431991Sheppo mutex_exit(&vport->lock);
21441991Sheppo return (rv);
21451991Sheppo }
21461991Sheppo
21471991Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv,
2148*7656SSherry.Moore@Sun.COM VCC_PORT_TERM_WR|VCC_PORT_LDC_CHANNEL_READY|
2149*7656SSherry.Moore@Sun.COM VCC_PORT_USE_WRITE_LDC);
21501991Sheppo if (rv) {
21511991Sheppo mutex_exit(&vport->lock);
21521991Sheppo return (rv);
21531991Sheppo }
21541991Sheppo
21551991Sheppo vport->status &= ~VCC_PORT_USE_WRITE_LDC;
21561991Sheppo mutex_exit(&vport->lock);
21571991Sheppo size = uiop->uio_resid;
21581991Sheppo
21591991Sheppo D2("vcc_write: virtual-console-concentrator@%d:%d writing %d bytes\n",
21601991Sheppo instance, portno, size);
21611991Sheppo
21621991Sheppo
21631991Sheppo
21641991Sheppo buf.type = LDC_CONSOLE_DATA;
21651991Sheppo
21661991Sheppo while (size) {
21671991Sheppo
21681991Sheppo bytes = MIN(size, VCC_MTU_SZ);
21691991Sheppo /* move data */
21701991Sheppo rv = uiomove(&(buf.data), bytes, UIO_WRITE, uiop);
21711991Sheppo
21721991Sheppo if (rv) {
21731991Sheppo break;
21741991Sheppo }
21751991Sheppo
21761991Sheppo /* write to ldc */
21771991Sheppo buf.size = bytes;
21781991Sheppo
21791991Sheppo mutex_enter(&vport->lock);
21801991Sheppo
21811991Sheppo /* check minor no and pid */
21821991Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor),
2183*7656SSherry.Moore@Sun.COM vport)) != 0) {
21841991Sheppo mutex_exit(&vport->lock);
21851991Sheppo return (rv);
21861991Sheppo }
21871991Sheppo
21881991Sheppo rv = i_vcc_write_ldc(vport, &buf);
21891991Sheppo
21901991Sheppo mutex_exit(&vport->lock);
21911991Sheppo
21921991Sheppo if (rv) {
21931991Sheppo break;
21941991Sheppo }
21951991Sheppo
21961991Sheppo size -= bytes;
21971991Sheppo
21981991Sheppo }
21991991Sheppo
22001991Sheppo i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC);
22011991Sheppo return (rv);
22021991Sheppo }
22031991Sheppo
22041991Sheppo /* mdeg callback for a removed port */
22051991Sheppo static int
i_vcc_md_remove_port(md_t * mdp,mde_cookie_t mdep,vcc_t * vccp)22061991Sheppo i_vcc_md_remove_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp)
22071991Sheppo {
22081991Sheppo uint64_t portno; /* md requires 64bit for port number */
22091991Sheppo int rv = MDEG_FAILURE;
22101991Sheppo vcc_port_t *vport;
22111991Sheppo
22121991Sheppo if (md_get_prop_val(mdp, mdep, "id", &portno)) {
22131991Sheppo cmn_err(CE_CONT, "vcc_mdeg_cb: port has no 'id' property\n");
22141991Sheppo return (MDEG_FAILURE);
22151991Sheppo }
22161991Sheppo
22171991Sheppo if ((portno >= VCC_MAX_PORTS) || (portno < 0)) {
22181991Sheppo cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld invalid port no\n",
2219*7656SSherry.Moore@Sun.COM portno);
22201991Sheppo return (MDEG_FAILURE);
22211991Sheppo }
22221991Sheppo
22231991Sheppo if (portno == VCC_CONTROL_PORT) {
22241991Sheppo cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld can not remove"
2225*7656SSherry.Moore@Sun.COM "control port\n",
22261991Sheppo portno);
22271991Sheppo return (MDEG_FAILURE);
22281991Sheppo }
22291991Sheppo
22301991Sheppo vport = &(vccp->port[portno]);
22311991Sheppo
22321991Sheppo /* delete the port */
22331991Sheppo mutex_enter(&vport->lock);
22341991Sheppo rv = i_vcc_delete_port(vccp, vport);
22351991Sheppo mutex_exit(&vport->lock);
22361991Sheppo
22371991Sheppo mutex_enter(&vccp->lock);
22381991Sheppo vccp->num_ports--;
22391991Sheppo mutex_exit(&vccp->lock);
22401991Sheppo
22411991Sheppo return (rv ? MDEG_FAILURE : MDEG_SUCCESS);
22421991Sheppo }
22431991Sheppo
22441991Sheppo static int
i_vcc_get_ldc_id(md_t * md,mde_cookie_t mdep,uint64_t * ldc_id)22451991Sheppo i_vcc_get_ldc_id(md_t *md, mde_cookie_t mdep, uint64_t *ldc_id)
22461991Sheppo {
22471991Sheppo int num_nodes;
22481991Sheppo size_t size;
22491991Sheppo mde_cookie_t *channel;
22501991Sheppo int num_channels;
22511991Sheppo
22521991Sheppo
22531991Sheppo if ((num_nodes = md_node_count(md)) <= 0) {
22541991Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc_channel_id:"
22551991Sheppo " Invalid node count in Machine Description subtree");
22561991Sheppo return (-1);
22571991Sheppo }
22581991Sheppo size = num_nodes*(sizeof (*channel));
22591991Sheppo channel = kmem_zalloc(size, KM_SLEEP);
22601991Sheppo ASSERT(channel != NULL); /* because KM_SLEEP */
22611991Sheppo
22621991Sheppo
22631991Sheppo /* Look for channel endpoint child(ren) of the vdisk MD node */
22641991Sheppo if ((num_channels = md_scan_dag(md, mdep,
2265*7656SSherry.Moore@Sun.COM md_find_name(md, "channel-endpoint"),
2266*7656SSherry.Moore@Sun.COM md_find_name(md, "fwd"), channel)) <= 0) {
22671991Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc_id: No 'channel-endpoint'"
22681991Sheppo " found for vcc");
22691991Sheppo kmem_free(channel, size);
22701991Sheppo return (-1);
22711991Sheppo }
22721991Sheppo
22731991Sheppo /* Get the "id" value for the first channel endpoint node */
22741991Sheppo if (md_get_prop_val(md, channel[0], "id", ldc_id) != 0) {
22751991Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc: No id property found "
22761991Sheppo "for channel-endpoint of vcc");
22771991Sheppo kmem_free(channel, size);
22781991Sheppo return (-1);
22791991Sheppo }
22801991Sheppo
22811991Sheppo if (num_channels > 1) {
22821991Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc: Warning: Using ID of first"
22831991Sheppo " of multiple channels for this vcc");
22841991Sheppo }
22851991Sheppo
22861991Sheppo kmem_free(channel, size);
22871991Sheppo return (0);
22881991Sheppo }
22891991Sheppo /* mdeg callback for an added port */
22901991Sheppo static int
i_vcc_md_add_port(md_t * mdp,mde_cookie_t mdep,vcc_t * vccp)22911991Sheppo i_vcc_md_add_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp)
22921991Sheppo {
22931991Sheppo uint64_t portno; /* md requires 64 bit */
22941991Sheppo char *domain_name;
22951991Sheppo char *group_name;
22961991Sheppo uint64_t ldc_id;
22971991Sheppo uint64_t tcp_port;
22981991Sheppo vcc_port_t *vport;
22991991Sheppo
23001991Sheppo /* read in the port's reg property */
23011991Sheppo if (md_get_prop_val(mdp, mdep, "id", &portno)) {
23021991Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port_: port has no 'id' "
2303*7656SSherry.Moore@Sun.COM "property\n");
23041991Sheppo return (MDEG_FAILURE);
23051991Sheppo }
23061991Sheppo
23071991Sheppo /* read in the port's "vcc-doman-name" property */
23081991Sheppo if (md_get_prop_str(mdp, mdep, "vcc-domain-name", &domain_name)) {
23091991Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has "
2310*7656SSherry.Moore@Sun.COM "no 'vcc-domain-name' property\n", portno);
23111991Sheppo return (MDEG_FAILURE);
23121991Sheppo }
23131991Sheppo
23141991Sheppo
23151991Sheppo /* read in the port's "vcc-group-name" property */
23161991Sheppo if (md_get_prop_str(mdp, mdep, "vcc-group-name", &group_name)) {
23171991Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no "
2318*7656SSherry.Moore@Sun.COM "'vcc-group-name'property\n", portno);
23191991Sheppo return (MDEG_FAILURE);
23201991Sheppo }
23211991Sheppo
23221991Sheppo
23231991Sheppo /* read in the port's "vcc-tcp-port" property */
23241991Sheppo if (md_get_prop_val(mdp, mdep, "vcc-tcp-port", &tcp_port)) {
23251991Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no"
2326*7656SSherry.Moore@Sun.COM "'vcc-tcp-port' property\n", portno);
23271991Sheppo return (MDEG_FAILURE);
23281991Sheppo }
23291991Sheppo
23301991Sheppo D1("i_vcc_md_add_port: port@%d domain-name=%s group-name=%s"
23311991Sheppo " tcp-port=%lld\n", portno, domain_name, group_name, tcp_port);
23321991Sheppo
23331991Sheppo /* add the port */
23341991Sheppo if (i_vcc_add_port(vccp, group_name, tcp_port, portno, domain_name)) {
23351991Sheppo return (MDEG_FAILURE);
23361991Sheppo }
23371991Sheppo
23381991Sheppo vport = &vccp->port[portno];
23391991Sheppo if (i_vcc_get_ldc_id(mdp, mdep, &ldc_id)) {
23401991Sheppo mutex_enter(&vport->lock);
23411991Sheppo (void) i_vcc_delete_port(vccp, vport);
23421991Sheppo mutex_exit(&vport->lock);
23431991Sheppo return (MDEG_FAILURE);
23441991Sheppo }
23451991Sheppo
23461991Sheppo /* configure the port */
23471991Sheppo if (i_vcc_config_port(vccp, portno, ldc_id)) {
23481991Sheppo mutex_enter(&vport->lock);
23491991Sheppo (void) i_vcc_delete_port(vccp, vport);
23501991Sheppo mutex_exit(&vport->lock);
23511991Sheppo return (MDEG_FAILURE);
23521991Sheppo }
23531991Sheppo
23541991Sheppo mutex_enter(&vccp->lock);
23551991Sheppo vccp->num_ports++;
23561991Sheppo mutex_exit(&vccp->lock);
23571991Sheppo
23581991Sheppo vport = &vccp->port[VCC_CONTROL_PORT];
23591991Sheppo
23601991Sheppo if (vport->pollflag & VCC_POLL_CONFIG) {
23611991Sheppo /* wakeup vntsd */
23621991Sheppo mutex_enter(&vport->lock);
23631991Sheppo vport->pollevent |= VCC_POLL_ADD_PORT;
23641991Sheppo mutex_exit(&vport->lock);
23651991Sheppo pollwakeup(&vport->poll, POLLIN);
23661991Sheppo }
23671991Sheppo
23681991Sheppo return (MDEG_SUCCESS);
23691991Sheppo }
23701991Sheppo
23711991Sheppo /* mdeg callback */
23721991Sheppo static int
vcc_mdeg_cb(void * cb_argp,mdeg_result_t * resp)23731991Sheppo vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
23741991Sheppo {
23751991Sheppo int idx;
23761991Sheppo vcc_t *vccp;
23771991Sheppo int rv;
23781991Sheppo
23791991Sheppo vccp = (vcc_t *)cb_argp;
23801991Sheppo ASSERT(vccp);
23811991Sheppo
23821991Sheppo if (resp == NULL) {
23831991Sheppo return (MDEG_FAILURE);
23841991Sheppo }
23851991Sheppo
23861991Sheppo /* added port */
23871991Sheppo D1("vcc_mdeg_cb: added %d port(s)\n", resp->added.nelem);
23881991Sheppo
23891991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) {
23901991Sheppo rv = i_vcc_md_add_port(resp->added.mdp,
23911991Sheppo resp->added.mdep[idx], vccp);
23921991Sheppo
23931991Sheppo if (rv != MDEG_SUCCESS) {
23941991Sheppo return (rv);
23951991Sheppo }
23961991Sheppo }
23971991Sheppo
23981991Sheppo /* removed port */
23991991Sheppo D1("vcc_mdeg_cb: removed %d port(s)\n", resp->removed.nelem);
24001991Sheppo
24011991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) {
24021991Sheppo rv = i_vcc_md_remove_port(resp->removed.mdp,
24031991Sheppo resp->removed.mdep[idx], vccp);
24041991Sheppo
24051991Sheppo if (rv != MDEG_SUCCESS) {
24061991Sheppo return (rv);
24071991Sheppo }
24083151Ssg70180
24091991Sheppo }
24101991Sheppo
24111991Sheppo /*
24121991Sheppo * XXX - Currently no support for updating already active
24131991Sheppo * ports. So, ignore the match_curr and match_prev arrays
24141991Sheppo * for now.
24151991Sheppo */
24161991Sheppo
24171991Sheppo return (MDEG_SUCCESS);
24181991Sheppo }
24191991Sheppo
24201991Sheppo
24211991Sheppo /* cb_chpoll */
24221991Sheppo static int
vcc_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)24231991Sheppo vcc_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
24241991Sheppo struct pollhead **phpp)
24251991Sheppo {
24261991Sheppo int instance;
24271991Sheppo minor_t minor;
24281991Sheppo uint_t portno;
24291991Sheppo vcc_t *vccp;
24301991Sheppo vcc_port_t *vport;
24311991Sheppo
24321991Sheppo minor = getminor(dev);
24331991Sheppo
24341991Sheppo instance = VCCINST(minor);
24351991Sheppo
24361991Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance);
24371991Sheppo if (vccp == NULL) {
24381991Sheppo return (ENXIO);
24391991Sheppo }
24401991Sheppo
24411991Sheppo portno = VCCPORT(vccp, minor);
24421991Sheppo
24431991Sheppo vport = &(vccp->port[portno]);
24441991Sheppo
24451991Sheppo D1("vcc_chpoll: virtual-console-concentrator@%d events 0x%x\n",
24461991Sheppo portno, events);
24471991Sheppo
24481991Sheppo *reventsp = 0;
24491991Sheppo
24501991Sheppo if (portno != VCC_CONTROL_PORT) {
24511991Sheppo return (ENXIO);
24521991Sheppo }
24531991Sheppo
24541991Sheppo /* poll for config change */
24551991Sheppo if (vport->pollevent) {
24561991Sheppo *reventsp |= (events & POLLIN);
24571991Sheppo }
24581991Sheppo
24591991Sheppo if (((*reventsp) == 0) && (!anyyet)) {
24601991Sheppo *phpp = &vport->poll;
24611991Sheppo if (events & POLLIN) {
24621991Sheppo mutex_enter(&vport->lock);
24631991Sheppo vport->pollflag |= VCC_POLL_CONFIG;
24641991Sheppo mutex_exit(&vport->lock);
24651991Sheppo } else {
24661991Sheppo return (ENXIO);
24671991Sheppo }
24681991Sheppo }
24691991Sheppo
24701991Sheppo D1("vcc_chpoll: virtual-console-concentrator@%d:%d ev=0x%x, "
24711991Sheppo "rev=0x%x pev=0x%x, flag=0x%x\n",
24721991Sheppo instance, portno, events, (*reventsp),
24731991Sheppo vport->pollevent, vport->pollflag);
24741991Sheppo
24751991Sheppo
24761991Sheppo return (0);
24771991Sheppo }
2478