11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 231ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/types.h> 301ae08745Sheppo #include <sys/file.h> 311ae08745Sheppo #include <sys/errno.h> 321ae08745Sheppo #include <sys/uio.h> 331ae08745Sheppo #include <sys/open.h> 341ae08745Sheppo #include <sys/cred.h> 351ae08745Sheppo #include <sys/kmem.h> 361ae08745Sheppo #include <sys/conf.h> 371ae08745Sheppo #include <sys/cmn_err.h> 381ae08745Sheppo #include <sys/ksynch.h> 391ae08745Sheppo #include <sys/modctl.h> 401ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 411ae08745Sheppo #include <sys/debug.h> 421ae08745Sheppo #include <sys/promif.h> 431ae08745Sheppo #include <sys/ddi.h> 441ae08745Sheppo #include <sys/sunddi.h> 451ae08745Sheppo #include <sys/cyclic.h> 461ae08745Sheppo #include <sys/termio.h> 471ae08745Sheppo #include <sys/intr.h> 481ae08745Sheppo #include <sys/ivintr.h> 491ae08745Sheppo #include <sys/note.h> 501ae08745Sheppo #include <sys/stat.h> 511ae08745Sheppo #include <sys/fcntl.h> 521ae08745Sheppo #include <sys/sysmacros.h> 531ae08745Sheppo 541ae08745Sheppo #include <sys/ldc.h> 551ae08745Sheppo #include <sys/mdeg.h> 561ae08745Sheppo #include <sys/vcc_impl.h> 571ae08745Sheppo 581ae08745Sheppo /* 591ae08745Sheppo * Function prototypes. 601ae08745Sheppo */ 611ae08745Sheppo 621ae08745Sheppo /* DDI entrypoints */ 631ae08745Sheppo static int vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 641ae08745Sheppo static int vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 651ae08745Sheppo static int vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred); 661ae08745Sheppo static int vcc_close(dev_t dev, int flag, int otyp, cred_t *cred); 671ae08745Sheppo static int vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 681ae08745Sheppo cred_t *credp, int *rvalp); 691ae08745Sheppo static int vcc_read(dev_t dev, struct uio *uiop, cred_t *credp); 701ae08745Sheppo static int vcc_write(dev_t dev, struct uio *uiop, cred_t *credp); 711ae08745Sheppo static int vcc_chpoll(dev_t dev, short events, int anyyet, 721ae08745Sheppo short *reventsp, struct pollhead **phpp); 731ae08745Sheppo static int vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 741ae08745Sheppo void *arg, void **resultp); 751ae08745Sheppo 761ae08745Sheppo /* callback functions */ 771ae08745Sheppo static uint_t vcc_ldc_cb(uint64_t event, caddr_t arg); 781ae08745Sheppo static int vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 791ae08745Sheppo 801ae08745Sheppo /* Internal functions */ 811ae08745Sheppo static int i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport); 821ae08745Sheppo static int i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port, 831ae08745Sheppo uint_t portno, char *domain_name); 841ae08745Sheppo static int i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id); 851ae08745Sheppo static int i_vcc_reset_events(vcc_t *vccp); 861ae08745Sheppo static int i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, 871ae08745Sheppo caddr_t buf, int mode); 881ae08745Sheppo static int i_vcc_del_cons_ok(vcc_t *vccp, caddr_t buf, int mode); 891ae08745Sheppo static int i_vcc_close_port(vcc_port_t *vport); 901ae08745Sheppo static int i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf); 911ae08745Sheppo 921ae08745Sheppo static void *vcc_ssp; 931ae08745Sheppo 941ae08745Sheppo static struct cb_ops vcc_cb_ops = { 951ae08745Sheppo vcc_open, /* open */ 961ae08745Sheppo vcc_close, /* close */ 971ae08745Sheppo nodev, /* strategy */ 981ae08745Sheppo nodev, /* print */ 991ae08745Sheppo nodev, /* dump */ 1001ae08745Sheppo vcc_read, /* read */ 1011ae08745Sheppo vcc_write, /* write */ 1021ae08745Sheppo vcc_ioctl, /* ioctl */ 1031ae08745Sheppo nodev, /* devmap */ 1041ae08745Sheppo nodev, /* mmap */ 1051ae08745Sheppo ddi_segmap, /* segmap */ 1061ae08745Sheppo vcc_chpoll, /* chpoll */ 1071ae08745Sheppo ddi_prop_op, /* prop_op */ 1081ae08745Sheppo NULL, /* stream */ 1091ae08745Sheppo D_NEW | D_MP /* flags */ 1101ae08745Sheppo }; 1111ae08745Sheppo 1121ae08745Sheppo 1131ae08745Sheppo static struct dev_ops vcc_ops = { 1141ae08745Sheppo DEVO_REV, /* rev */ 1151ae08745Sheppo 0, /* ref count */ 1161ae08745Sheppo vcc_getinfo, /* getinfo */ 1171ae08745Sheppo nulldev, /* identify */ 1181ae08745Sheppo nulldev, /* probe */ 1191ae08745Sheppo vcc_attach, /* attach */ 1201ae08745Sheppo vcc_detach, /* detach */ 1211ae08745Sheppo nodev, /* reset */ 1221ae08745Sheppo &vcc_cb_ops, /* cb_ops */ 1231ae08745Sheppo (struct bus_ops *)NULL /* bus_ops */ 1241ae08745Sheppo }; 1251ae08745Sheppo 1261ae08745Sheppo extern struct mod_ops mod_driverops; 1271ae08745Sheppo 1281ae08745Sheppo #define VCC_CHANNEL_ENDPOINT "channel-endpoint" 1291ae08745Sheppo #define VCC_ID_PROP "id" 1301ae08745Sheppo 1311ae08745Sheppo /* 1321ae08745Sheppo * This is the string displayed by modinfo(1m). 1331ae08745Sheppo */ 1341ae08745Sheppo static char vcc_ident[] = "sun4v Virtual Console Concentrator Driver v%I%"; 1351ae08745Sheppo 1361ae08745Sheppo static struct modldrv md = { 1371ae08745Sheppo &mod_driverops, /* Type - it is a driver */ 1381ae08745Sheppo vcc_ident, /* Name of the module */ 1391ae08745Sheppo &vcc_ops, /* driver specfic opts */ 1401ae08745Sheppo }; 1411ae08745Sheppo 1421ae08745Sheppo static struct modlinkage ml = { 1431ae08745Sheppo MODREV_1, 1441ae08745Sheppo &md, 1451ae08745Sheppo NULL 1461ae08745Sheppo }; 1471ae08745Sheppo 1481ae08745Sheppo /* 1491ae08745Sheppo * Matching criteria passed to the MDEG to register interest 1501ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 1511ae08745Sheppo * 'id' property. 1521ae08745Sheppo */ 1531ae08745Sheppo static md_prop_match_t vcc_port_prop_match[] = { 1541ae08745Sheppo { MDET_PROP_VAL, "id" }, 1551ae08745Sheppo { MDET_LIST_END, NULL } 1561ae08745Sheppo }; 1571ae08745Sheppo 1581ae08745Sheppo static mdeg_node_match_t vcc_port_match = {"virtual-device-port", 1591ae08745Sheppo vcc_port_prop_match}; 1601ae08745Sheppo 1611ae08745Sheppo /* 1621ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 1631ae08745Sheppo * 'virtual-device-port' nodes that do not belong to the specified node. 1641ae08745Sheppo * This template is copied for each vldc instance and filled in with 1651ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 1661ae08745Sheppo */ 1671ae08745Sheppo static mdeg_prop_spec_t vcc_prop_template[] = { 1681ae08745Sheppo { MDET_PROP_STR, "name", "virtual-console-concentrator" }, 1691ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 1701ae08745Sheppo { MDET_LIST_END, NULL, NULL } 1711ae08745Sheppo }; 1721ae08745Sheppo 1731ae08745Sheppo #define VCC_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 1741ae08745Sheppo 1751ae08745Sheppo 1761ae08745Sheppo #ifdef DEBUG 1771ae08745Sheppo 1781ae08745Sheppo /* 1791ae08745Sheppo * Print debug messages 1801ae08745Sheppo * 1811ae08745Sheppo * set vldcdbg to 0xf to enable all messages 1821ae08745Sheppo * 1831ae08745Sheppo * 0x8 - Errors 1841ae08745Sheppo * 0x4 - Warnings 1851ae08745Sheppo * 0x2 - All debug messages (most verbose) 1861ae08745Sheppo * 0x1 - Minimal debug messages 1871ae08745Sheppo */ 1881ae08745Sheppo 1891ae08745Sheppo int vccdbg = 0x8; 1901ae08745Sheppo 1911ae08745Sheppo static void 1921ae08745Sheppo vccdebug(const char *fmt, ...) 1931ae08745Sheppo { 1941ae08745Sheppo char buf[512]; 1951ae08745Sheppo va_list ap; 1961ae08745Sheppo 1971ae08745Sheppo va_start(ap, fmt); 1981ae08745Sheppo (void) vsprintf(buf, fmt, ap); 1991ae08745Sheppo va_end(ap); 2001ae08745Sheppo 2011ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 2021ae08745Sheppo } 2031ae08745Sheppo 2041ae08745Sheppo #define D1 \ 2051ae08745Sheppo if (vccdbg & 0x01) \ 2061ae08745Sheppo vccdebug 2071ae08745Sheppo 2081ae08745Sheppo #define D2 \ 2091ae08745Sheppo if (vccdbg & 0x02) \ 2101ae08745Sheppo vccdebug 2111ae08745Sheppo 2121ae08745Sheppo #define DWARN \ 2131ae08745Sheppo if (vccdbg & 0x04) \ 2141ae08745Sheppo vccdebug 2151ae08745Sheppo 2161ae08745Sheppo #else 2171ae08745Sheppo 2181ae08745Sheppo #define D1 2191ae08745Sheppo #define D2 2201ae08745Sheppo #define DWARN 2211ae08745Sheppo 2221ae08745Sheppo #endif 2231ae08745Sheppo 2241ae08745Sheppo /* _init(9E): initialize the loadable module */ 2251ae08745Sheppo int 2261ae08745Sheppo _init(void) 2271ae08745Sheppo { 2281ae08745Sheppo int error; 2291ae08745Sheppo 2301ae08745Sheppo /* init the soft state structure */ 2311ae08745Sheppo error = ddi_soft_state_init(&vcc_ssp, sizeof (vcc_t), 1); 2321ae08745Sheppo if (error != 0) { 2331ae08745Sheppo return (error); 2341ae08745Sheppo } 2351ae08745Sheppo 2361ae08745Sheppo /* Link the driver into the system */ 2371ae08745Sheppo error = mod_install(&ml); 2381ae08745Sheppo 2391ae08745Sheppo return (error); 2401ae08745Sheppo 2411ae08745Sheppo } 2421ae08745Sheppo 2431ae08745Sheppo /* _info(9E): return information about the loadable module */ 2441ae08745Sheppo int 2451ae08745Sheppo _info(struct modinfo *modinfop) 2461ae08745Sheppo { 2471ae08745Sheppo /* Report status of the dynamically loadable driver module */ 2481ae08745Sheppo return (mod_info(&ml, modinfop)); 2491ae08745Sheppo } 2501ae08745Sheppo 2511ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2521ae08745Sheppo int 2531ae08745Sheppo _fini(void) 2541ae08745Sheppo { 2551ae08745Sheppo int error; 2561ae08745Sheppo 2571ae08745Sheppo /* Unlink the driver module from the system */ 2581ae08745Sheppo if ((error = mod_remove(&ml)) == 0) { 2591ae08745Sheppo /* 2601ae08745Sheppo * We have successfully "removed" the driver. 2611ae08745Sheppo * destroy soft state 2621ae08745Sheppo */ 2631ae08745Sheppo ddi_soft_state_fini(&vcc_ssp); 2641ae08745Sheppo } 2651ae08745Sheppo 2661ae08745Sheppo return (error); 2671ae08745Sheppo } 2681ae08745Sheppo 2691ae08745Sheppo /* getinfo(9E) */ 2701ae08745Sheppo static int 2711ae08745Sheppo vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 2721ae08745Sheppo { 2731ae08745Sheppo _NOTE(ARGUNUSED(dip)) 2741ae08745Sheppo 2751ae08745Sheppo int instance = VCCINST(getminor((dev_t)arg)); 2761ae08745Sheppo vcc_t *vccp = NULL; 2771ae08745Sheppo 2781ae08745Sheppo switch (cmd) { 2791ae08745Sheppo 2801ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 2811ae08745Sheppo if ((vccp = ddi_get_soft_state(vcc_ssp, instance)) == NULL) { 2821ae08745Sheppo *resultp = NULL; 2831ae08745Sheppo return (DDI_FAILURE); 2841ae08745Sheppo } 2851ae08745Sheppo *resultp = vccp->dip; 2861ae08745Sheppo return (DDI_SUCCESS); 2871ae08745Sheppo 2881ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 2891ae08745Sheppo *resultp = (void *)(uintptr_t)instance; 2901ae08745Sheppo return (DDI_SUCCESS); 2911ae08745Sheppo 2921ae08745Sheppo default: 2931ae08745Sheppo *resultp = NULL; 2941ae08745Sheppo return (DDI_FAILURE); 2951ae08745Sheppo } 2961ae08745Sheppo } 2971ae08745Sheppo 2981ae08745Sheppo /* 2991ae08745Sheppo * There are two cases that need special blocking. One of them is to block 3001ae08745Sheppo * a minor node without a port and another is to block application other 3011ae08745Sheppo * than vntsd. 3021ae08745Sheppo * 3031ae08745Sheppo * A minor node can exist in the file system without associated with a port 3041ae08745Sheppo * because when a port is deleted, ddi_remove_minor does not unlink it. 3051ae08745Sheppo * Clients might try to open a minor node even after the corresponding port 3061ae08745Sheppo * node has been removed. To identify and block these calls, 3071ae08745Sheppo * we need to validate the association between a port and its minor node. 3081ae08745Sheppo * 3091ae08745Sheppo * An application other than vntsd can access a console port as long 3101ae08745Sheppo * as vntsd is not using the port. A port opened by an application other 3111ae08745Sheppo * than vntsd will be closed when vntsd wants to use the port. 3121ae08745Sheppo * However, other application could use same file descriptor 3131ae08745Sheppo * access vcc cb_ops. So we need to identify and block caller other 3141ae08745Sheppo * than vntsd, when vntsd is using the port. 3151ae08745Sheppo */ 3161ae08745Sheppo static int 3171ae08745Sheppo i_vcc_can_use_port(vcc_minor_t *minorp, vcc_port_t *vport) 3181ae08745Sheppo { 3191ae08745Sheppo if (vport->minorp != minorp) { 3201ae08745Sheppo /* port config changed */ 3211ae08745Sheppo return (ENXIO); 3221ae08745Sheppo } 3231ae08745Sheppo 3241ae08745Sheppo if (vport->valid_pid == VCC_NO_PID_BLOCKING) { 3251ae08745Sheppo /* no blocking needed */ 3261ae08745Sheppo return (0); 3271ae08745Sheppo } 3281ae08745Sheppo 3291ae08745Sheppo if (vport->valid_pid != ddi_get_pid()) { 3301ae08745Sheppo return (EIO); 3311ae08745Sheppo } 3321ae08745Sheppo 3331ae08745Sheppo return (0); 3341ae08745Sheppo } 3351ae08745Sheppo 3361ae08745Sheppo 3371ae08745Sheppo /* Syncronization between thread using cv_wait */ 3381ae08745Sheppo static int 3391ae08745Sheppo i_vcc_wait_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status) 3401ae08745Sheppo { 3411ae08745Sheppo 3421ae08745Sheppo int rv; 3431ae08745Sheppo 3441ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 3451ae08745Sheppo 3461ae08745Sheppo for (; ; ) { 3471ae08745Sheppo 3481ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 3491ae08745Sheppo /* port has been deleted */ 3501ae08745Sheppo D1("i_vcc_wait_port_status: port%d deleted\n", 3511ae08745Sheppo vport->number); 3521ae08745Sheppo return (EIO); 3531ae08745Sheppo } 3541ae08745Sheppo 3551ae08745Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) { 3561ae08745Sheppo D1("i_vcc_wait_port_status: port%d is closed \n", 3571ae08745Sheppo vport->number); 3581ae08745Sheppo return (EIO); 3591ae08745Sheppo } 3601ae08745Sheppo 3611ae08745Sheppo if (vport->status & VCC_PORT_LDC_LINK_DOWN) { 3621ae08745Sheppo return (EIO); 3631ae08745Sheppo } 3641ae08745Sheppo 3651ae08745Sheppo if ((vport->valid_pid != VCC_NO_PID_BLOCKING) && 3661ae08745Sheppo (vport->valid_pid != ddi_get_pid())) { 3671ae08745Sheppo return (EIO); 3681ae08745Sheppo } 3691ae08745Sheppo 3701ae08745Sheppo if ((vport->status & status) == status) { 3711ae08745Sheppo return (0); 3721ae08745Sheppo } 3731ae08745Sheppo 3741ae08745Sheppo if (!ddi_can_receive_sig()) { 3751ae08745Sheppo return (EIO); 3761ae08745Sheppo } 3771ae08745Sheppo 3781ae08745Sheppo rv = cv_wait_sig(cv, &vport->lock); 3791ae08745Sheppo if (rv == 0) { 3801ae08745Sheppo D1("i_vcc_wait_port_status: port%d get intr \n", 3811ae08745Sheppo vport->number); 3821ae08745Sheppo /* got signal */ 3831ae08745Sheppo return (EINTR); 3841ae08745Sheppo } 3851ae08745Sheppo } 3861ae08745Sheppo 3871ae08745Sheppo } 3881ae08745Sheppo 3891ae08745Sheppo /* Syncronization between threads, signal state change */ 3901ae08745Sheppo static void 3911ae08745Sheppo i_vcc_set_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status) 3921ae08745Sheppo { 3931ae08745Sheppo 3941ae08745Sheppo mutex_enter(&vport->lock); 3951ae08745Sheppo vport->status |= status; 3961ae08745Sheppo cv_broadcast(cv); 3971ae08745Sheppo mutex_exit(&vport->lock); 3981ae08745Sheppo } 3991ae08745Sheppo 4001ae08745Sheppo /* initialize a ldc channel */ 4011ae08745Sheppo static int 4021ae08745Sheppo i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport) 4031ae08745Sheppo { 4041ae08745Sheppo ldc_attr_t attr; 4051ae08745Sheppo int rv = EIO; 4061ae08745Sheppo 4071ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 4081ae08745Sheppo ASSERT(vport->ldc_id != VCC_INVALID_CHANNEL); 4091ae08745Sheppo 4101ae08745Sheppo /* initialize the channel */ 4111ae08745Sheppo attr.devclass = LDC_DEV_SERIAL; 4121ae08745Sheppo attr.instance = ddi_get_instance(vccp->dip); 413*e1ebb9ecSlm66018 attr.mtu = VCC_MTU_SZ; 4141ae08745Sheppo attr.mode = LDC_MODE_RAW; 4151ae08745Sheppo 4161ae08745Sheppo if ((rv = ldc_init(vport->ldc_id, &attr, &(vport->ldc_handle))) != 0) { 4171ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port %d inv channel 0x%lx\n", 4181ae08745Sheppo vport->number, vport->ldc_id); 4191ae08745Sheppo vport->ldc_id = VCC_INVALID_CHANNEL; 4201ae08745Sheppo return (rv); 4211ae08745Sheppo } 4221ae08745Sheppo 4231ae08745Sheppo /* register it */ 4241ae08745Sheppo if ((rv = ldc_reg_callback(vport->ldc_handle, vcc_ldc_cb, 4251ae08745Sheppo (caddr_t)vport)) != 0) { 4261ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_register_cb" 4271ae08745Sheppo "failed\n", vport->number); 4281ae08745Sheppo (void) ldc_fini(vport->ldc_handle); 4291ae08745Sheppo vport->ldc_id = VCC_INVALID_CHANNEL; 4301ae08745Sheppo return (rv); 4311ae08745Sheppo } 4321ae08745Sheppo 4331ae08745Sheppo /* open and bring channel up */ 4341ae08745Sheppo if ((rv = ldc_open(vport->ldc_handle)) != 0) { 4351ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d inv channel 0x%lx\n", 4361ae08745Sheppo vport->number, vport->ldc_id); 4371ae08745Sheppo (void) ldc_unreg_callback(vport->ldc_handle); 4381ae08745Sheppo (void) ldc_fini(vport->ldc_handle); 4391ae08745Sheppo vport->ldc_id = VCC_INVALID_CHANNEL; 4401ae08745Sheppo return (rv); 4411ae08745Sheppo } 4421ae08745Sheppo 4431ae08745Sheppo /* init the channel status */ 4441ae08745Sheppo if ((rv = ldc_status(vport->ldc_handle, &vport->ldc_status)) != 0) { 4451ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_status failed\n", 4461ae08745Sheppo vport->number); 4471ae08745Sheppo (void) ldc_close(vport->ldc_handle); 4481ae08745Sheppo (void) ldc_unreg_callback(vport->ldc_handle); 4491ae08745Sheppo (void) ldc_fini(vport->ldc_handle); 4501ae08745Sheppo vport->ldc_id = VCC_INVALID_CHANNEL; 4511ae08745Sheppo return (rv); 4521ae08745Sheppo } 4531ae08745Sheppo 4541ae08745Sheppo return (0); 4551ae08745Sheppo } 4561ae08745Sheppo 4571ae08745Sheppo /* release a ldc channel */ 4581ae08745Sheppo static int 4591ae08745Sheppo i_vcc_ldc_fini(vcc_port_t *vport) 4601ae08745Sheppo { 4611ae08745Sheppo int rv = EIO; 4621ae08745Sheppo vcc_msg_t buf; 4631ae08745Sheppo 4641ae08745Sheppo D1("i_vcc_ldc_fini: port@%lld, ldc_id%%llx\n", vport->number, 4651ae08745Sheppo vport->ldc_id); 4661ae08745Sheppo 4671ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 4681ae08745Sheppo 4691ae08745Sheppo /* wait for write available */ 4701ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 4711ae08745Sheppo VCC_PORT_USE_WRITE_LDC); 4721ae08745Sheppo if (rv) { 4731ae08745Sheppo return (rv); 4741ae08745Sheppo } 4751ae08745Sheppo vport->status &= ~VCC_PORT_USE_WRITE_LDC; 4761ae08745Sheppo /* send a HUP message */ 4771ae08745Sheppo buf.type = LDC_CONSOLE_CTRL; 4781ae08745Sheppo buf.ctrl_msg = LDC_CONSOLE_HUP; 4791ae08745Sheppo buf.size = 0; 4801ae08745Sheppo 4811ae08745Sheppo /* in case of error, we still want to clean up ldc channel */ 4821ae08745Sheppo (void) i_vcc_write_ldc(vport, &buf); 4831ae08745Sheppo 4841ae08745Sheppo mutex_exit(&vport->lock); 4851ae08745Sheppo i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC); 4861ae08745Sheppo mutex_enter(&vport->lock); 4871ae08745Sheppo 4881ae08745Sheppo (void) ldc_set_cb_mode(vport->ldc_handle, LDC_CB_DISABLE); 4891ae08745Sheppo if ((rv = ldc_close(vport->ldc_handle)) != 0) { 4901ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_fini: cannot close channel %ld\n", 4911ae08745Sheppo vport->ldc_id); 4921ae08745Sheppo return (rv); 4931ae08745Sheppo } 4941ae08745Sheppo 4951ae08745Sheppo if ((rv = ldc_unreg_callback(vport->ldc_handle)) != 0) { 4961ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_fini: port@%d ldc_unreg_callback" 4971ae08745Sheppo "failed\n", vport->number); 4981ae08745Sheppo return (rv); 4991ae08745Sheppo } 5001ae08745Sheppo 5011ae08745Sheppo if ((rv = ldc_fini(vport->ldc_handle)) != 0) { 5021ae08745Sheppo cmn_err(CE_CONT, "i_vcc_ldc_fini: cannot finilize channel" 5031ae08745Sheppo "%ld\n", vport->ldc_id); 5041ae08745Sheppo return (rv); 5051ae08745Sheppo } 5061ae08745Sheppo 5071ae08745Sheppo return (0); 5081ae08745Sheppo } 5091ae08745Sheppo 5101ae08745Sheppo /* read data from ldc channel */ 5111ae08745Sheppo 5121ae08745Sheppo static int 5131ae08745Sheppo i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz) 5141ae08745Sheppo { 5151ae08745Sheppo 5161ae08745Sheppo int rv; 5171ae08745Sheppo size_t size; 5181ae08745Sheppo size_t space_left = *sz; 5191ae08745Sheppo vcc_msg_t buf; 5201ae08745Sheppo int i; 5211ae08745Sheppo 5221ae08745Sheppo 5231ae08745Sheppo 5241ae08745Sheppo 5251ae08745Sheppo /* make sure holding read lock */ 5261ae08745Sheppo ASSERT((vport->status & VCC_PORT_USE_READ_LDC) == 0); 5271ae08745Sheppo ASSERT(space_left >= VCC_MTU_SZ); 5281ae08745Sheppo 5291ae08745Sheppo *sz = 0; 5301ae08745Sheppo while (space_left >= VCC_MTU_SZ) { 5311ae08745Sheppo size = sizeof (buf); 5321ae08745Sheppo 5331ae08745Sheppo rv = ldc_read(vport->ldc_handle, (caddr_t)&buf, &size); 5341ae08745Sheppo 5351ae08745Sheppo if (rv) { 5361ae08745Sheppo return (rv); 5371ae08745Sheppo } 5381ae08745Sheppo 5391ae08745Sheppo 5401ae08745Sheppo /* 5411ae08745Sheppo * FIXME: ldc_read should not reaturn 0 with 5421ae08745Sheppo * either size == 0, buf.size == 0 or size < VCC_HDR_SZ 5431ae08745Sheppo */ 5441ae08745Sheppo if (size == 0) { 5451ae08745Sheppo if (*sz > 0) { 5461ae08745Sheppo return (0); 5471ae08745Sheppo } 5481ae08745Sheppo return (EAGAIN); 5491ae08745Sheppo } 5501ae08745Sheppo 5511ae08745Sheppo if (size < VCC_HDR_SZ) { 5521ae08745Sheppo return (EIO); 5531ae08745Sheppo } 5541ae08745Sheppo 5551ae08745Sheppo /* 5561ae08745Sheppo * only data is expected from console - otherwise 5571ae08745Sheppo * return error 5581ae08745Sheppo */ 5591ae08745Sheppo if (buf.type != LDC_CONSOLE_DATA) { 5601ae08745Sheppo return (EIO); 5611ae08745Sheppo } 5621ae08745Sheppo 5631ae08745Sheppo if (buf.size == 0) { 5641ae08745Sheppo if (*sz > 0) { 5651ae08745Sheppo return (0); 5661ae08745Sheppo } 5671ae08745Sheppo return (EAGAIN); 5681ae08745Sheppo } 5691ae08745Sheppo 5701ae08745Sheppo /* copy data */ 5711ae08745Sheppo for (i = 0; i < buf.size; i++, (*sz)++) { 5721ae08745Sheppo data_buf[*sz] = buf.data[i]; 5731ae08745Sheppo } 5741ae08745Sheppo 5751ae08745Sheppo space_left -= buf.size; 5761ae08745Sheppo } 5771ae08745Sheppo 5781ae08745Sheppo return (0); 5791ae08745Sheppo } 5801ae08745Sheppo 5811ae08745Sheppo /* callback from ldc */ 5821ae08745Sheppo static uint_t 5831ae08745Sheppo vcc_ldc_cb(uint64_t event, caddr_t arg) 5841ae08745Sheppo { 5851ae08745Sheppo 5861ae08745Sheppo vcc_port_t *vport = (vcc_port_t *)arg; 587*e1ebb9ecSlm66018 boolean_t hasdata; 5881ae08745Sheppo 5891ae08745Sheppo /* 5901ae08745Sheppo * do not need to hold lock because if ldc calls back, the 5911ae08745Sheppo * ldc_handle must be valid. 5921ae08745Sheppo */ 5931ae08745Sheppo D2("vcc_ldc_cb: callback invoked port=%d events=%llx\n", 5941ae08745Sheppo vport->number, event); 5951ae08745Sheppo 5961ae08745Sheppo /* check event from ldc */ 5971ae08745Sheppo if (event & LDC_EVT_WRITE) { 5981ae08745Sheppo /* channel has space for write */ 5991ae08745Sheppo 6001ae08745Sheppo i_vcc_set_port_status(vport, &vport->write_cv, 6011ae08745Sheppo VCC_PORT_LDC_WRITE_READY); 6021ae08745Sheppo return (LDC_SUCCESS); 6031ae08745Sheppo } 6041ae08745Sheppo 6051ae08745Sheppo if (event & LDC_EVT_READ) { 6061ae08745Sheppo 6071ae08745Sheppo /* channel has data for read */ 608*e1ebb9ecSlm66018 (void) ldc_chkq(vport->ldc_handle, &hasdata); 609*e1ebb9ecSlm66018 if (!hasdata) { 6101ae08745Sheppo /* data already read */ 6111ae08745Sheppo return (LDC_SUCCESS); 6121ae08745Sheppo } 6131ae08745Sheppo 6141ae08745Sheppo i_vcc_set_port_status(vport, &vport->read_cv, 6151ae08745Sheppo VCC_PORT_LDC_DATA_READY); 6161ae08745Sheppo return (LDC_SUCCESS); 6171ae08745Sheppo } 6181ae08745Sheppo 6191ae08745Sheppo if (event & LDC_EVT_DOWN) { 6201ae08745Sheppo /* channel is down */ 6211ae08745Sheppo i_vcc_set_port_status(vport, &vport->write_cv, 6221ae08745Sheppo VCC_PORT_LDC_LINK_DOWN); 6231ae08745Sheppo cv_broadcast(&vport->read_cv); 6241ae08745Sheppo 6251ae08745Sheppo } 6261ae08745Sheppo 6271ae08745Sheppo return (LDC_SUCCESS); 6281ae08745Sheppo 6291ae08745Sheppo } 6301ae08745Sheppo 6311ae08745Sheppo 6321ae08745Sheppo /* configure a vcc port with ldc channel */ 6331ae08745Sheppo static int 6341ae08745Sheppo i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id) 6351ae08745Sheppo { 6361ae08745Sheppo int rv = EIO; 6371ae08745Sheppo vcc_port_t *vport; 6381ae08745Sheppo 6391ae08745Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 6401ae08745Sheppo cmn_err(CE_CONT, "i_vcc_config_port: invalid port number %d\n", 6411ae08745Sheppo portno); 6421ae08745Sheppo return (EINVAL); 6431ae08745Sheppo } 6441ae08745Sheppo 6451ae08745Sheppo vport = &(vccp->port[portno]); 6461ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 6471ae08745Sheppo cmn_err(CE_CONT, "i_vcc_config_port: port@%d does not exist\n", 6481ae08745Sheppo portno); 6491ae08745Sheppo return (EINVAL); 6501ae08745Sheppo } 6511ae08745Sheppo 6521ae08745Sheppo 6531ae08745Sheppo if (vport->ldc_id != VCC_INVALID_CHANNEL) { 6541ae08745Sheppo cmn_err(CE_CONT, "i_vcc_config_port: port@%d channel already" 6551ae08745Sheppo "configured\n", portno); 6561ae08745Sheppo return (EINVAL); 6571ae08745Sheppo } 6581ae08745Sheppo 6591ae08745Sheppo mutex_enter(&vport->lock); 6601ae08745Sheppo 6611ae08745Sheppo /* store the ldc ID */ 6621ae08745Sheppo vport->ldc_id = ldc_id; 6631ae08745Sheppo /* check if someone has already opened this port */ 6641ae08745Sheppo if (vport->status & VCC_PORT_OPEN) { 6651ae08745Sheppo 6661ae08745Sheppo if ((rv = i_vcc_ldc_init(vccp, vport)) != 0) { 6671ae08745Sheppo mutex_exit(&vport->lock); 6681ae08745Sheppo return (rv); 6691ae08745Sheppo } 6701ae08745Sheppo 6711ae08745Sheppo /* mark port as ready */ 6721ae08745Sheppo vport->status |= VCC_PORT_LDC_CHANNEL_READY; 6731ae08745Sheppo cv_broadcast(&vport->read_cv); 6741ae08745Sheppo cv_broadcast(&vport->write_cv); 6751ae08745Sheppo } 6761ae08745Sheppo 6771ae08745Sheppo mutex_exit(&vport->lock); 6781ae08745Sheppo 6791ae08745Sheppo D1("i_vcc_config_port: port@%d ldc=%d, domain=%s", 6801ae08745Sheppo vport->number, vport->ldc_id, vport->minorp->domain_name); 6811ae08745Sheppo 6821ae08745Sheppo return (0); 6831ae08745Sheppo } 6841ae08745Sheppo 6851ae08745Sheppo /* add a vcc console port */ 6861ae08745Sheppo static int 6871ae08745Sheppo i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port, 6881ae08745Sheppo uint_t portno, char *domain_name) 6891ae08745Sheppo { 6901ae08745Sheppo int instance; 6911ae08745Sheppo int rv = MDEG_FAILURE; 6921ae08745Sheppo minor_t minor; 6931ae08745Sheppo vcc_port_t *vport; 6941ae08745Sheppo uint_t minor_idx; 6951ae08745Sheppo char name[MAXPATHLEN]; 6961ae08745Sheppo 6971ae08745Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 6981ae08745Sheppo DWARN("i_vcc_add_port: invalid port number %d\n", portno); 6991ae08745Sheppo return (MDEG_FAILURE); 7001ae08745Sheppo } 7011ae08745Sheppo 7021ae08745Sheppo vport = &(vccp->port[portno]); 7031ae08745Sheppo if (vport->status & VCC_PORT_AVAIL) { 7041ae08745Sheppo /* this port already exists */ 7051ae08745Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid port - port@%d " 7061ae08745Sheppo "exists\n", portno); 7071ae08745Sheppo return (MDEG_FAILURE); 7081ae08745Sheppo } 7091ae08745Sheppo 7101ae08745Sheppo vport->number = portno; 7111ae08745Sheppo vport->ldc_id = VCC_INVALID_CHANNEL; 7121ae08745Sheppo 7131ae08745Sheppo if (domain_name == NULL) { 7141ae08745Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid domain name\n"); 7151ae08745Sheppo return (MDEG_FAILURE); 7161ae08745Sheppo } 7171ae08745Sheppo 7181ae08745Sheppo if (group_name == NULL) { 7191ae08745Sheppo cmn_err(CE_CONT, "i_vcc_add_port: invalid group name\n"); 7201ae08745Sheppo return (MDEG_FAILURE); 7211ae08745Sheppo } 7221ae08745Sheppo 7231ae08745Sheppo /* look up minor number */ 7241ae08745Sheppo for (minor_idx = 0; minor_idx < vccp->minors_assigned; minor_idx++) { 7251ae08745Sheppo if (strcmp(vccp->minor_tbl[minor_idx].domain_name, 7261ae08745Sheppo domain_name) == 0) { 7271ae08745Sheppo /* found previous assigned minor number */ 7281ae08745Sheppo break; 7291ae08745Sheppo } 7301ae08745Sheppo } 7311ae08745Sheppo 7321ae08745Sheppo if (minor_idx == vccp->minors_assigned) { 7331ae08745Sheppo /* end of lookup - assign new minor number */ 7341ae08745Sheppo if (minor_idx == VCC_MAX_PORTS) { 7351ae08745Sheppo cmn_err(CE_CONT, "i_vcc_add_port:" 7361ae08745Sheppo "too many minornodes (%d)\n", 7371ae08745Sheppo minor_idx); 7381ae08745Sheppo return (MDEG_FAILURE); 7391ae08745Sheppo } 7401ae08745Sheppo 7411ae08745Sheppo (void) strlcpy(vccp->minor_tbl[minor_idx].domain_name, 7421ae08745Sheppo domain_name, MAXPATHLEN); 7431ae08745Sheppo 7441ae08745Sheppo vccp->minors_assigned++; 7451ae08745Sheppo } 7461ae08745Sheppo 7471ae08745Sheppo vport->minorp = &vccp->minor_tbl[minor_idx]; 7481ae08745Sheppo vccp->minor_tbl[minor_idx].portno = portno; 7491ae08745Sheppo 7501ae08745Sheppo (void) strlcpy(vport->group_name, group_name, MAXPATHLEN); 7511ae08745Sheppo 7521ae08745Sheppo vport->tcp_port = tcp_port; 7531ae08745Sheppo D1("i_vcc_add_port:@%d domain=%s, group=%s, tcp=%lld", 7541ae08745Sheppo vport->number, vport->minorp->domain_name, 7551ae08745Sheppo vport->group_name, vport->tcp_port); 7561ae08745Sheppo 7571ae08745Sheppo 7581ae08745Sheppo /* 7591ae08745Sheppo * Create a minor node. The minor number is 7601ae08745Sheppo * (instance << VCC_INST_SHIFT) | minor_idx 7611ae08745Sheppo */ 7621ae08745Sheppo instance = ddi_get_instance(vccp->dip); 7631ae08745Sheppo 7641ae08745Sheppo minor = (instance << VCC_INST_SHIFT) | (minor_idx); 7651ae08745Sheppo 7661ae08745Sheppo (void) snprintf(name, MAXPATHLEN - 1, "%s%s", VCC_MINOR_NAME_PREFIX, 7671ae08745Sheppo domain_name); 7681ae08745Sheppo 7691ae08745Sheppo rv = ddi_create_minor_node(vccp->dip, name, S_IFCHR, minor, 7701ae08745Sheppo DDI_NT_SERIAL, 0); 7711ae08745Sheppo 7721ae08745Sheppo if (rv != DDI_SUCCESS) { 7731ae08745Sheppo vccp->minors_assigned--; 7741ae08745Sheppo return (MDEG_FAILURE); 7751ae08745Sheppo } 7761ae08745Sheppo 7771ae08745Sheppo mutex_enter(&vport->lock); 7781ae08745Sheppo vport->status = VCC_PORT_AVAIL | VCC_PORT_ADDED; 7791ae08745Sheppo mutex_exit(&vport->lock); 7801ae08745Sheppo 7811ae08745Sheppo 7821ae08745Sheppo return (MDEG_SUCCESS); 7831ae08745Sheppo } 7841ae08745Sheppo 7851ae08745Sheppo /* delete a port */ 7861ae08745Sheppo static int 7871ae08745Sheppo i_vcc_delete_port(vcc_t *vccp, vcc_port_t *vport) 7881ae08745Sheppo { 7891ae08745Sheppo 7901ae08745Sheppo char name[MAXPATHLEN]; 7911ae08745Sheppo int rv; 7921ae08745Sheppo 7931ae08745Sheppo 7941ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 7951ae08745Sheppo 7961ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 7971ae08745Sheppo D1("vcc_del_port port already deleted \n"); 7981ae08745Sheppo return (0); 7991ae08745Sheppo } 8001ae08745Sheppo 8011ae08745Sheppo if (vport->status & VCC_PORT_OPEN) { 8021ae08745Sheppo /* do not block mdeg callback */ 8031ae08745Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING; 8041ae08745Sheppo rv = i_vcc_close_port(vport); 8051ae08745Sheppo } 8061ae08745Sheppo 8071ae08745Sheppo /* remove minor node */ 8081ae08745Sheppo (void) snprintf(name, MAXPATHLEN-1, "%s%s", VCC_MINOR_NAME_PREFIX, 8091ae08745Sheppo vport->minorp->domain_name); 8101ae08745Sheppo 8111ae08745Sheppo ddi_remove_minor_node(vccp->dip, name); 8121ae08745Sheppo 8131ae08745Sheppo /* let read and write thread know */ 8141ae08745Sheppo cv_broadcast(&vport->read_cv); 8151ae08745Sheppo cv_broadcast(&vport->write_cv); 8161ae08745Sheppo vport->status = 0; 8171ae08745Sheppo return (rv); 8181ae08745Sheppo 8191ae08745Sheppo 8201ae08745Sheppo } 8211ae08745Sheppo 8221ae08745Sheppo /* register callback to MDEG */ 8231ae08745Sheppo static int 8241ae08745Sheppo i_vcc_mdeg_register(vcc_t *vccp, int instance) 8251ae08745Sheppo { 8261ae08745Sheppo mdeg_prop_spec_t *pspecp; 8271ae08745Sheppo mdeg_node_spec_t *ispecp; 8281ae08745Sheppo mdeg_handle_t mdeg_hdl; 8291ae08745Sheppo int sz; 8301ae08745Sheppo int rv; 8311ae08745Sheppo 8321ae08745Sheppo /* 8331ae08745Sheppo * Allocate and initialize a per-instance copy 8341ae08745Sheppo * of the global property spec array that will 8351ae08745Sheppo * uniquely identify this vcc instance. 8361ae08745Sheppo */ 8371ae08745Sheppo sz = sizeof (vcc_prop_template); 8381ae08745Sheppo pspecp = kmem_alloc(sz, KM_SLEEP); 8391ae08745Sheppo 8401ae08745Sheppo bcopy(vcc_prop_template, pspecp, sz); 8411ae08745Sheppo 8421ae08745Sheppo VCC_SET_MDEG_PROP_INST(pspecp, instance); 8431ae08745Sheppo 8441ae08745Sheppo /* initialize the complete prop spec structure */ 8451ae08745Sheppo ispecp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 8461ae08745Sheppo ispecp->namep = "virtual-device"; 8471ae08745Sheppo ispecp->specp = pspecp; 8481ae08745Sheppo 8491ae08745Sheppo /* perform the registration */ 8501ae08745Sheppo rv = mdeg_register(ispecp, &vcc_port_match, vcc_mdeg_cb, 8511ae08745Sheppo vccp, &mdeg_hdl); 8521ae08745Sheppo 8531ae08745Sheppo if (rv != MDEG_SUCCESS) { 8541ae08745Sheppo cmn_err(CE_CONT, "i_vcc_mdeg_register:" 8551ae08745Sheppo "mdeg_register failed (%d)\n", rv); 8561ae08745Sheppo kmem_free(ispecp, sizeof (mdeg_node_spec_t)); 8571ae08745Sheppo kmem_free(pspecp, sz); 8581ae08745Sheppo return (DDI_FAILURE); 8591ae08745Sheppo } 8601ae08745Sheppo 8611ae08745Sheppo /* save off data that will be needed later */ 8621ae08745Sheppo vccp->md_ispecp = (void *)ispecp; 8631ae08745Sheppo vccp->mdeg_hdl = mdeg_hdl; 8641ae08745Sheppo 8651ae08745Sheppo return (0); 8661ae08745Sheppo } 8671ae08745Sheppo 8681ae08745Sheppo /* destroy all mutex from port table */ 8691ae08745Sheppo static void 8701ae08745Sheppo i_vcc_cleanup_port_table(vcc_t *vccp) 8711ae08745Sheppo { 8721ae08745Sheppo int i; 8731ae08745Sheppo vcc_port_t *vport; 8741ae08745Sheppo 8751ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 8761ae08745Sheppo vport = &(vccp->port[i]); 8771ae08745Sheppo mutex_destroy(&vport->lock); 8781ae08745Sheppo cv_destroy(&vport->read_cv); 8791ae08745Sheppo cv_destroy(&vport->write_cv); 8801ae08745Sheppo } 8811ae08745Sheppo } 8821ae08745Sheppo 8831ae08745Sheppo /* 8841ae08745Sheppo * attach(9E): attach a device to the system. 8851ae08745Sheppo * called once for each instance of the device on the system. 8861ae08745Sheppo */ 8871ae08745Sheppo static int 8881ae08745Sheppo vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 8891ae08745Sheppo { 8901ae08745Sheppo int i, instance, inst; 8911ae08745Sheppo int rv = DDI_FAILURE; 8921ae08745Sheppo vcc_t *vccp; 8931ae08745Sheppo minor_t minor; 8941ae08745Sheppo vcc_port_t *vport; 8951ae08745Sheppo 8961ae08745Sheppo switch (cmd) { 8971ae08745Sheppo 8981ae08745Sheppo case DDI_ATTACH: 8991ae08745Sheppo 9001ae08745Sheppo instance = ddi_get_instance(dip); 9011ae08745Sheppo if (ddi_soft_state_zalloc(vcc_ssp, instance) != DDI_SUCCESS) 9021ae08745Sheppo return (DDI_FAILURE); 9031ae08745Sheppo 9041ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 9051ae08745Sheppo if (vccp == NULL) { 9061ae08745Sheppo ddi_soft_state_free(vccp, instance); 9071ae08745Sheppo return (ENXIO); 9081ae08745Sheppo } 9091ae08745Sheppo 9101ae08745Sheppo D1("vcc_attach: DDI_ATTACH instance=%d\n", instance); 9111ae08745Sheppo 9121ae08745Sheppo /* initialize the mutex */ 9131ae08745Sheppo mutex_init(&vccp->lock, NULL, MUTEX_DRIVER, NULL); 9141ae08745Sheppo 9151ae08745Sheppo mutex_enter(&vccp->lock); 9161ae08745Sheppo 9171ae08745Sheppo vccp->dip = dip; 9181ae08745Sheppo 9191ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 9201ae08745Sheppo vport = &(vccp->port[i]); 9211ae08745Sheppo mutex_init(&vport->lock, NULL, MUTEX_DRIVER, NULL); 9221ae08745Sheppo cv_init(&vport->read_cv, NULL, CV_DRIVER, NULL); 9231ae08745Sheppo cv_init(&vport->write_cv, NULL, CV_DRIVER, NULL); 9241ae08745Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING; 9251ae08745Sheppo } 9261ae08745Sheppo 9271ae08745Sheppo vport = &vccp->port[VCC_CONTROL_PORT]; 9281ae08745Sheppo mutex_enter(&vport->lock); 9291ae08745Sheppo 9301ae08745Sheppo vport->minorp = &vccp->minor_tbl[VCC_CONTROL_MINOR_IDX]; 9311ae08745Sheppo vport->status |= VCC_PORT_AVAIL; 9321ae08745Sheppo 9331ae08745Sheppo /* create a minor node for vcc control */ 9341ae08745Sheppo minor = (instance << VCC_INST_SHIFT) | VCC_CONTROL_MINOR_IDX; 9351ae08745Sheppo 9361ae08745Sheppo vccp->minor_tbl[VCC_CONTROL_PORT].portno = 9371ae08745Sheppo VCC_CONTROL_MINOR_IDX; 9381ae08745Sheppo 9391ae08745Sheppo 9401ae08745Sheppo rv = ddi_create_minor_node(vccp->dip, "ctl", S_IFCHR, minor, 9411ae08745Sheppo DDI_NT_SERIAL, 0); 9421ae08745Sheppo 9431ae08745Sheppo mutex_exit(&vport->lock); 9441ae08745Sheppo 9451ae08745Sheppo if (rv != DDI_SUCCESS) { 9461ae08745Sheppo cmn_err(CE_CONT, "vcc_attach: error" 9471ae08745Sheppo "creating control minor node\n"); 9481ae08745Sheppo 9491ae08745Sheppo i_vcc_cleanup_port_table(vccp); 9501ae08745Sheppo 9511ae08745Sheppo mutex_exit(&vccp->lock); 9521ae08745Sheppo /* clean up soft state */ 9531ae08745Sheppo ddi_soft_state_free(vccp, instance); 9541ae08745Sheppo 9551ae08745Sheppo return (DDI_FAILURE); 9561ae08745Sheppo } 9571ae08745Sheppo 9581ae08745Sheppo /* get the instance number by reading 'reg' property */ 9591ae08745Sheppo inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 9601ae08745Sheppo "reg", -1); 9611ae08745Sheppo if (inst == -1) { 9621ae08745Sheppo cmn_err(CE_CONT, "vcc_attach: vcc%d has no " 9631ae08745Sheppo "'reg' property\n", 9641ae08745Sheppo ddi_get_instance(dip)); 9651ae08745Sheppo 9661ae08745Sheppo i_vcc_cleanup_port_table(vccp); 9671ae08745Sheppo 9681ae08745Sheppo /* remove minor */ 9691ae08745Sheppo ddi_remove_minor_node(vccp->dip, NULL); 9701ae08745Sheppo 9711ae08745Sheppo /* clean up soft state */ 9721ae08745Sheppo mutex_exit(&vccp->lock); 9731ae08745Sheppo ddi_soft_state_free(vccp, instance); 9741ae08745Sheppo 9751ae08745Sheppo return (DDI_FAILURE); 9761ae08745Sheppo } 9771ae08745Sheppo 9781ae08745Sheppo /* 9791ae08745Sheppo * Mdeg might invoke callback in the same call sequence 9801ae08745Sheppo * if there is a domain port at the time of registration. 9811ae08745Sheppo * Since the callback also grabs vcc->lock mutex, to avoid 9821ae08745Sheppo * mutex reentry error, release the lock before registration 9831ae08745Sheppo */ 9841ae08745Sheppo mutex_exit(&vccp->lock); 9851ae08745Sheppo 9861ae08745Sheppo /* register for notifications from Zeus */ 9871ae08745Sheppo rv = i_vcc_mdeg_register(vccp, inst); 9881ae08745Sheppo if (rv != MDEG_SUCCESS) { 9891ae08745Sheppo cmn_err(CE_CONT, "vcc_attach: error register to MD\n"); 9901ae08745Sheppo 9911ae08745Sheppo i_vcc_cleanup_port_table(vccp); 9921ae08745Sheppo 9931ae08745Sheppo /* remove minor */ 9941ae08745Sheppo ddi_remove_minor_node(vccp->dip, NULL); 9951ae08745Sheppo 9961ae08745Sheppo /* clean up soft state */ 9971ae08745Sheppo ddi_soft_state_free(vccp, instance); 9981ae08745Sheppo 9991ae08745Sheppo return (DDI_FAILURE); 10001ae08745Sheppo } 10011ae08745Sheppo 10021ae08745Sheppo return (DDI_SUCCESS); 10031ae08745Sheppo 10041ae08745Sheppo case DDI_RESUME: 10051ae08745Sheppo 10061ae08745Sheppo return (DDI_SUCCESS); 10071ae08745Sheppo 10081ae08745Sheppo default: 10091ae08745Sheppo 10101ae08745Sheppo return (DDI_FAILURE); 10111ae08745Sheppo } 10121ae08745Sheppo } 10131ae08745Sheppo 10141ae08745Sheppo /* 10151ae08745Sheppo * detach(9E): detach a device from the system. 10161ae08745Sheppo */ 10171ae08745Sheppo static int 10181ae08745Sheppo vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 10191ae08745Sheppo { 10201ae08745Sheppo int i, instance; 10211ae08745Sheppo vcc_t *vccp; 10221ae08745Sheppo mdeg_node_spec_t *ispecp; 10231ae08745Sheppo vcc_port_t *vport; 10241ae08745Sheppo 10251ae08745Sheppo switch (cmd) { 10261ae08745Sheppo 10271ae08745Sheppo case DDI_DETACH: 10281ae08745Sheppo 10291ae08745Sheppo instance = ddi_get_instance(dip); 10301ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 10311ae08745Sheppo if (vccp == NULL) 10321ae08745Sheppo return (ENXIO); 10331ae08745Sheppo 10341ae08745Sheppo D1("vcc_detach: DDI_DETACH instance=%d\n", instance); 10351ae08745Sheppo 10361ae08745Sheppo mutex_enter(&vccp->lock); 10371ae08745Sheppo 10381ae08745Sheppo /* unregister from MD event generator */ 10391ae08745Sheppo 10401ae08745Sheppo ASSERT(vccp->mdeg_hdl); 10411ae08745Sheppo (void) mdeg_unregister(vccp->mdeg_hdl); 10421ae08745Sheppo 10431ae08745Sheppo ispecp = (mdeg_node_spec_t *)vccp->md_ispecp; 10441ae08745Sheppo ASSERT(ispecp); 10451ae08745Sheppo 10461ae08745Sheppo kmem_free(ispecp->specp, sizeof (vcc_prop_template)); 10471ae08745Sheppo kmem_free(ispecp, sizeof (mdeg_node_spec_t)); 10481ae08745Sheppo 10491ae08745Sheppo /* remove minor nodes */ 10501ae08745Sheppo ddi_remove_minor_node(vccp->dip, NULL); 10511ae08745Sheppo mutex_exit(&vccp->lock); 10521ae08745Sheppo 10531ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 10541ae08745Sheppo 10551ae08745Sheppo vport = &vccp->port[i]; 10561ae08745Sheppo mutex_enter(&vport->lock); 10571ae08745Sheppo if (i == VCC_CONTROL_PORT) { 10581ae08745Sheppo if (vport->status & VCC_PORT_OPEN) { 10591ae08745Sheppo (void) i_vcc_close_port(vport); 10601ae08745Sheppo } 10611ae08745Sheppo } 10621ae08745Sheppo 10631ae08745Sheppo if ((vccp->port[i].status & VCC_PORT_AVAIL) && 10641ae08745Sheppo (i != VCC_CONTROL_PORT)) { 10651ae08745Sheppo D1("vcc_detach: removing port port@%d\n", i); 10661ae08745Sheppo (void) i_vcc_delete_port(vccp, vport); 10671ae08745Sheppo } 10681ae08745Sheppo mutex_exit(&vport->lock); 10691ae08745Sheppo cv_destroy(&vport->read_cv); 10701ae08745Sheppo cv_destroy(&vport->write_cv); 10711ae08745Sheppo mutex_destroy(&vport->lock); 10721ae08745Sheppo } 10731ae08745Sheppo 10741ae08745Sheppo 10751ae08745Sheppo 10761ae08745Sheppo /* destroy mutex and free the soft state */ 10771ae08745Sheppo mutex_destroy(&vccp->lock); 10781ae08745Sheppo ddi_soft_state_free(vcc_ssp, instance); 10791ae08745Sheppo 10801ae08745Sheppo return (DDI_SUCCESS); 10811ae08745Sheppo 10821ae08745Sheppo case DDI_SUSPEND: 10831ae08745Sheppo 10841ae08745Sheppo return (DDI_SUCCESS); 10851ae08745Sheppo 10861ae08745Sheppo default: 10871ae08745Sheppo 10881ae08745Sheppo return (DDI_FAILURE); 10891ae08745Sheppo } 10901ae08745Sheppo } 10911ae08745Sheppo 10921ae08745Sheppo /* cb_open */ 10931ae08745Sheppo static int 10941ae08745Sheppo vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred) 10951ae08745Sheppo { 10961ae08745Sheppo _NOTE(ARGUNUSED(otyp, cred)) 10971ae08745Sheppo 10981ae08745Sheppo int instance; 10991ae08745Sheppo int rv = EIO; 11001ae08745Sheppo minor_t minor; 11011ae08745Sheppo uint_t portno; 11021ae08745Sheppo vcc_t *vccp; 11031ae08745Sheppo vcc_port_t *vport; 11041ae08745Sheppo 11051ae08745Sheppo minor = getminor(*devp); 11061ae08745Sheppo instance = VCCINST(minor); 11071ae08745Sheppo 11081ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 11091ae08745Sheppo if (vccp == NULL) { 11101ae08745Sheppo return (ENXIO); 11111ae08745Sheppo } 11121ae08745Sheppo 11131ae08745Sheppo portno = VCCPORT(vccp, minor); 11141ae08745Sheppo 11151ae08745Sheppo vport = &(vccp->port[portno]); 11161ae08745Sheppo 11171ae08745Sheppo mutex_enter(&vport->lock); 11181ae08745Sheppo 11191ae08745Sheppo if (vport->status & VCC_PORT_OPEN) { 11201ae08745Sheppo /* only one open per port */ 11211ae08745Sheppo cmn_err(CE_CONT, "vcc_open: virtual-console-concentrator@%d:%d " 11221ae08745Sheppo "is already open\n", instance, portno); 11231ae08745Sheppo mutex_exit(&vport->lock); 11241ae08745Sheppo return (EAGAIN); 11251ae08745Sheppo } 11261ae08745Sheppo 11271ae08745Sheppo /* check minor no and pid */ 11281ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 11291ae08745Sheppo vport)) != 0) { 11301ae08745Sheppo mutex_exit(&vport->lock); 11311ae08745Sheppo return (rv); 11321ae08745Sheppo } 11331ae08745Sheppo 11341ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 11351ae08745Sheppo vport->status |= VCC_PORT_OPEN; 11361ae08745Sheppo mutex_exit(&vport->lock); 11371ae08745Sheppo return (0); 11381ae08745Sheppo } 11391ae08745Sheppo 11401ae08745Sheppo 11411ae08745Sheppo /* check if channel has been initialized */ 11421ae08745Sheppo if ((vport->status & VCC_PORT_LDC_CHANNEL_READY) == 0) { 11431ae08745Sheppo rv = i_vcc_ldc_init(vccp, vport); 11441ae08745Sheppo if (rv) { 11451ae08745Sheppo mutex_exit(&vport->lock); 11461ae08745Sheppo return (EIO); 11471ae08745Sheppo } 11481ae08745Sheppo 11491ae08745Sheppo /* mark port as ready */ 11501ae08745Sheppo vport->status |= VCC_PORT_LDC_CHANNEL_READY; 11511ae08745Sheppo } 11521ae08745Sheppo 11531ae08745Sheppo vport->status |= VCC_PORT_USE_READ_LDC | VCC_PORT_USE_WRITE_LDC| 11541ae08745Sheppo VCC_PORT_TERM_RD|VCC_PORT_TERM_WR|VCC_PORT_OPEN; 11551ae08745Sheppo 11561ae08745Sheppo if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) { 11571ae08745Sheppo vport->status |= VCC_PORT_NONBLOCK; 11581ae08745Sheppo } 11591ae08745Sheppo 11601ae08745Sheppo mutex_exit(&vport->lock); 11611ae08745Sheppo 11621ae08745Sheppo return (0); 11631ae08745Sheppo } 11641ae08745Sheppo 11651ae08745Sheppo /* close port */ 11661ae08745Sheppo static int 11671ae08745Sheppo i_vcc_close_port(vcc_port_t *vport) 11681ae08745Sheppo { 11691ae08745Sheppo int rv = EIO; 11701ae08745Sheppo 11711ae08745Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) { 11721ae08745Sheppo return (0); 11731ae08745Sheppo } 11741ae08745Sheppo 11751ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 11761ae08745Sheppo 11771ae08745Sheppo if (vport->status & VCC_PORT_LDC_CHANNEL_READY) { 11781ae08745Sheppo /* clean up ldc channel */ 11791ae08745Sheppo if ((rv = i_vcc_ldc_fini(vport)) != 0) { 11801ae08745Sheppo return (rv); 11811ae08745Sheppo } 11821ae08745Sheppo vport->status &= ~VCC_PORT_LDC_CHANNEL_READY; 11831ae08745Sheppo } 11841ae08745Sheppo 11851ae08745Sheppo /* reset rd/wr suspends */ 11861ae08745Sheppo vport->status |= VCC_PORT_TERM_RD | VCC_PORT_TERM_WR; 11871ae08745Sheppo vport->status &= ~VCC_PORT_NONBLOCK; 11881ae08745Sheppo vport->status &= ~VCC_PORT_OPEN; 11891ae08745Sheppo vport->valid_pid = VCC_NO_PID_BLOCKING; 11901ae08745Sheppo 11911ae08745Sheppo /* signal any blocked read and write thread */ 11921ae08745Sheppo cv_broadcast(&vport->read_cv); 11931ae08745Sheppo cv_broadcast(&vport->write_cv); 11941ae08745Sheppo 11951ae08745Sheppo return (0); 11961ae08745Sheppo } 11971ae08745Sheppo 11981ae08745Sheppo /* cb_close */ 11991ae08745Sheppo static int 12001ae08745Sheppo vcc_close(dev_t dev, int flag, int otyp, cred_t *cred) 12011ae08745Sheppo { 12021ae08745Sheppo _NOTE(ARGUNUSED(flag, otyp, cred)) 12031ae08745Sheppo 12041ae08745Sheppo int instance; 12051ae08745Sheppo minor_t minor; 12061ae08745Sheppo int rv = EIO; 12071ae08745Sheppo uint_t portno; 12081ae08745Sheppo vcc_t *vccp; 12091ae08745Sheppo vcc_port_t *vport; 12101ae08745Sheppo 12111ae08745Sheppo minor = getminor(dev); 12121ae08745Sheppo 12131ae08745Sheppo instance = VCCINST(minor); 12141ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 12151ae08745Sheppo if (vccp == NULL) { 12161ae08745Sheppo return (ENXIO); 12171ae08745Sheppo } 12181ae08745Sheppo 12191ae08745Sheppo portno = VCCPORT(vccp, minor); 12201ae08745Sheppo 12211ae08745Sheppo D1("vcc_close: closing virtual-console-concentrator@%d:%d\n", 12221ae08745Sheppo instance, portno); 12231ae08745Sheppo 12241ae08745Sheppo vport = &(vccp->port[portno]); 12251ae08745Sheppo 12261ae08745Sheppo 12271ae08745Sheppo if ((vport->status & VCC_PORT_OPEN) == 0) { 12281ae08745Sheppo return (0); 12291ae08745Sheppo } 12301ae08745Sheppo 12311ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 12321ae08745Sheppo /* 12331ae08745Sheppo * vntsd closes control port before it exits. There 12341ae08745Sheppo * could be events still pending for vntsd. 12351ae08745Sheppo */ 12361ae08745Sheppo rv = i_vcc_reset_events(vccp); 12371ae08745Sheppo return (0); 12381ae08745Sheppo } 12391ae08745Sheppo 12401ae08745Sheppo mutex_enter(&vport->lock); 12411ae08745Sheppo 12421ae08745Sheppo /* check minor no and pid */ 12431ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 12441ae08745Sheppo vport)) != 0) { 12451ae08745Sheppo mutex_exit(&vport->lock); 12461ae08745Sheppo return (rv); 12471ae08745Sheppo } 12481ae08745Sheppo 12491ae08745Sheppo rv = i_vcc_close_port(vport); 12501ae08745Sheppo mutex_exit(&vport->lock); 12511ae08745Sheppo 12521ae08745Sheppo return (rv); 12531ae08745Sheppo } 12541ae08745Sheppo 12551ae08745Sheppo /* 12561ae08745Sheppo * ioctl VCC_CONS_TBL - vntsd allocates buffer according to return of 12571ae08745Sheppo * VCC_NUM_PORTS. However, when vntsd requests for the console table, console 12581ae08745Sheppo * ports could be deleted or added. parameter num_ports is number of structures 12591ae08745Sheppo * that vntsd allocated for the table. If there are more ports than 12601ae08745Sheppo * num_ports, set up to wakeup vntsd to add ports. 12611ae08745Sheppo * If there less ports than num_ports, fill (-1) for cons_no to tell vntsd. 12621ae08745Sheppo */ 12631ae08745Sheppo static int 12641ae08745Sheppo i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, caddr_t buf, int mode) 12651ae08745Sheppo { 12661ae08745Sheppo vcc_console_t cons; 12671ae08745Sheppo int i; 12681ae08745Sheppo vcc_port_t *vport; 12691ae08745Sheppo boolean_t notify_vntsd = B_FALSE; 12701ae08745Sheppo char pathname[MAXPATHLEN]; 12711ae08745Sheppo 12721ae08745Sheppo 12731ae08745Sheppo (void) ddi_pathname(vccp->dip, pathname); 12741ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 12751ae08745Sheppo 12761ae08745Sheppo vport = &vccp->port[i]; 12771ae08745Sheppo 12781ae08745Sheppo if (i == VCC_CONTROL_PORT) { 12791ae08745Sheppo continue; 12801ae08745Sheppo } 12811ae08745Sheppo 12821ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 12831ae08745Sheppo continue; 12841ae08745Sheppo } 12851ae08745Sheppo 12861ae08745Sheppo /* a port exists before vntsd becomes online */ 12871ae08745Sheppo mutex_enter(&vport->lock); 12881ae08745Sheppo 12891ae08745Sheppo if (num_ports == 0) { 12901ae08745Sheppo /* more ports than vntsd's buffer can hold */ 12911ae08745Sheppo vport->status |= VCC_PORT_ADDED; 12921ae08745Sheppo notify_vntsd = B_TRUE; 12931ae08745Sheppo mutex_exit(&vport->lock); 12941ae08745Sheppo continue; 12951ae08745Sheppo } 12961ae08745Sheppo 12971ae08745Sheppo bzero(&cons, sizeof (vcc_console_t)); 12981ae08745Sheppo 12991ae08745Sheppo /* construct console buffer */ 13001ae08745Sheppo cons.cons_no = vport->number; 13011ae08745Sheppo cons.tcp_port = vport->tcp_port; 13021ae08745Sheppo (void) memcpy(cons.domain_name, 13031ae08745Sheppo vport->minorp->domain_name, MAXPATHLEN); 13041ae08745Sheppo 13051ae08745Sheppo (void) memcpy(cons.group_name, vport->group_name, 13061ae08745Sheppo MAXPATHLEN); 13071ae08745Sheppo vport->status &= ~VCC_PORT_ADDED; 13081ae08745Sheppo mutex_exit(&vport->lock); 13091ae08745Sheppo 13101ae08745Sheppo (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 13111ae08745Sheppo pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 13121ae08745Sheppo 13131ae08745Sheppo /* copy out data */ 13141ae08745Sheppo if (ddi_copyout(&cons, (void *)buf, 13151ae08745Sheppo sizeof (vcc_console_t), mode)) { 13161ae08745Sheppo mutex_exit(&vport->lock); 13171ae08745Sheppo return (EFAULT); 13181ae08745Sheppo } 13191ae08745Sheppo buf += sizeof (vcc_console_t); 13201ae08745Sheppo 13211ae08745Sheppo num_ports--; 13221ae08745Sheppo 13231ae08745Sheppo } 13241ae08745Sheppo 13251ae08745Sheppo if (num_ports == 0) { 13261ae08745Sheppo /* vntsd's buffer is full */ 13271ae08745Sheppo 13281ae08745Sheppo if (notify_vntsd) { 13291ae08745Sheppo /* more ports need to notify vntsd */ 13301ae08745Sheppo vport = &vccp->port[VCC_CONTROL_PORT]; 13311ae08745Sheppo mutex_enter(&vport->lock); 13321ae08745Sheppo vport->pollevent |= VCC_POLL_ADD_PORT; 13331ae08745Sheppo mutex_exit(&vport->lock); 13341ae08745Sheppo } 13351ae08745Sheppo 13361ae08745Sheppo return (0); 13371ae08745Sheppo } 13381ae08745Sheppo 13391ae08745Sheppo /* less ports than vntsd expected */ 13401ae08745Sheppo bzero(&cons, sizeof (vcc_console_t)); 13411ae08745Sheppo cons.cons_no = -1; 13421ae08745Sheppo 13431ae08745Sheppo while (num_ports > 0) { 13441ae08745Sheppo /* fill vntsd buffer with no console */ 13451ae08745Sheppo if (ddi_copyout(&cons, (void *)buf, 13461ae08745Sheppo sizeof (vcc_console_t), mode) != 0) { 13471ae08745Sheppo mutex_exit(&vport->lock); 13481ae08745Sheppo return (EFAULT); 13491ae08745Sheppo } 13501ae08745Sheppo D1("i_vcc_cons_tbl: a port is deleted\n"); 13511ae08745Sheppo buf += sizeof (vcc_console_t) +MAXPATHLEN; 13521ae08745Sheppo num_ports--; 13531ae08745Sheppo } 13541ae08745Sheppo 13551ae08745Sheppo return (0); 13561ae08745Sheppo } 13571ae08745Sheppo 13581ae08745Sheppo 13591ae08745Sheppo /* turn off event flag if there is no more change */ 13601ae08745Sheppo static void 13611ae08745Sheppo i_vcc_turn_off_event(vcc_t *vccp, uint32_t port_status, uint32_t event) 13621ae08745Sheppo { 13631ae08745Sheppo 13641ae08745Sheppo vcc_port_t *vport; 13651ae08745Sheppo int i; 13661ae08745Sheppo 13671ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 13681ae08745Sheppo 13691ae08745Sheppo vport = &(vccp->port[i]); 13701ae08745Sheppo 13711ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 13721ae08745Sheppo continue; 13731ae08745Sheppo } 13741ae08745Sheppo 13751ae08745Sheppo 13761ae08745Sheppo if (vport->status & port_status) { 13771ae08745Sheppo /* more port changes status */ 13781ae08745Sheppo return; 13791ae08745Sheppo } 13801ae08745Sheppo 13811ae08745Sheppo } 13821ae08745Sheppo 13831ae08745Sheppo /* no more changed port */ 13841ae08745Sheppo vport = &vccp->port[VCC_CONTROL_PORT]; 13851ae08745Sheppo 13861ae08745Sheppo /* turn off event */ 13871ae08745Sheppo mutex_enter(&vport->lock); 13881ae08745Sheppo vport->pollevent &= ~event; 13891ae08745Sheppo mutex_exit(&vport->lock); 13901ae08745Sheppo } 13911ae08745Sheppo 13921ae08745Sheppo /* ioctl VCC_CONS_INFO */ 13931ae08745Sheppo static int 13941ae08745Sheppo i_vcc_cons_info(vcc_t *vccp, caddr_t buf, int mode) 13951ae08745Sheppo { 13961ae08745Sheppo vcc_console_t cons; 13971ae08745Sheppo uint_t portno; 13981ae08745Sheppo vcc_port_t *vport; 13991ae08745Sheppo char pathname[MAXPATHLEN]; 14001ae08745Sheppo 14011ae08745Sheppo /* read in portno */ 14021ae08745Sheppo if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 14031ae08745Sheppo return (EFAULT); 14041ae08745Sheppo } 14051ae08745Sheppo 14061ae08745Sheppo D1("i_vcc_cons_info@%d:\n", portno); 14071ae08745Sheppo 14081ae08745Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 14091ae08745Sheppo return (EINVAL); 14101ae08745Sheppo } 14111ae08745Sheppo 14121ae08745Sheppo vport = &vccp->port[portno]; 14131ae08745Sheppo 14141ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 14151ae08745Sheppo return (EINVAL); 14161ae08745Sheppo } 14171ae08745Sheppo 14181ae08745Sheppo mutex_enter(&vport->lock); 14191ae08745Sheppo vport->status &= ~VCC_PORT_ADDED; 14201ae08745Sheppo 14211ae08745Sheppo /* construct configruation data */ 14221ae08745Sheppo bzero(&cons, sizeof (vcc_console_t)); 14231ae08745Sheppo 14241ae08745Sheppo cons.cons_no = vport->number; 14251ae08745Sheppo cons.tcp_port = vport->tcp_port; 14261ae08745Sheppo 14271ae08745Sheppo (void) memcpy(cons.domain_name, vport->minorp->domain_name, MAXPATHLEN); 14281ae08745Sheppo 14291ae08745Sheppo (void) memcpy(cons.group_name, vport->group_name, MAXPATHLEN); 14301ae08745Sheppo 14311ae08745Sheppo mutex_exit(&vport->lock); 14321ae08745Sheppo 14331ae08745Sheppo (void) ddi_pathname(vccp->dip, pathname), 14341ae08745Sheppo 14351ae08745Sheppo /* copy device name */ 14361ae08745Sheppo (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 14371ae08745Sheppo pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 14381ae08745Sheppo /* copy data */ 14391ae08745Sheppo if (ddi_copyout(&cons, (void *)buf, 14401ae08745Sheppo sizeof (vcc_console_t), mode) != 0) { 14411ae08745Sheppo mutex_exit(&vport->lock); 14421ae08745Sheppo return (EFAULT); 14431ae08745Sheppo } 14441ae08745Sheppo 14451ae08745Sheppo D1("i_vcc_cons_info@%d:domain:%s serv:%s tcp@%lld %s\n", 14461ae08745Sheppo cons.cons_no, cons.domain_name, 14471ae08745Sheppo cons.group_name, cons.tcp_port, cons.dev_name); 14481ae08745Sheppo 14491ae08745Sheppo i_vcc_turn_off_event(vccp, VCC_PORT_ADDED, VCC_POLL_ADD_PORT); 14501ae08745Sheppo 14511ae08745Sheppo return (0); 14521ae08745Sheppo } 14531ae08745Sheppo 14541ae08745Sheppo 14551ae08745Sheppo /* response to vntsd inquiry ioctl call */ 14561ae08745Sheppo static int 14571ae08745Sheppo i_vcc_inquiry(vcc_t *vccp, caddr_t buf, int mode) 14581ae08745Sheppo { 14591ae08745Sheppo vcc_port_t *vport; 14601ae08745Sheppo uint_t i; 14611ae08745Sheppo vcc_response_t msg; 14621ae08745Sheppo 14631ae08745Sheppo vport = &(vccp->port[VCC_CONTROL_PORT]); 14641ae08745Sheppo 14651ae08745Sheppo if ((vport->pollevent & VCC_POLL_ADD_PORT) == 0) { 14661ae08745Sheppo return (EINVAL); 14671ae08745Sheppo } 14681ae08745Sheppo 14691ae08745Sheppo /* an added port */ 14701ae08745Sheppo 14711ae08745Sheppo D1("i_vcc_inquiry\n"); 14721ae08745Sheppo 14731ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 14741ae08745Sheppo if ((vccp->port[i].status & VCC_PORT_AVAIL) == 0) { 14751ae08745Sheppo continue; 14761ae08745Sheppo } 14771ae08745Sheppo 14781ae08745Sheppo if (vccp->port[i].status & VCC_PORT_ADDED) { 14791ae08745Sheppo /* port added */ 14801ae08745Sheppo msg.reason = VCC_CONS_ADDED; 14811ae08745Sheppo msg.cons_no = i; 14821ae08745Sheppo 14831ae08745Sheppo if (ddi_copyout((void *)&msg, (void *)buf, 14841ae08745Sheppo sizeof (msg), mode) == -1) { 14851ae08745Sheppo cmn_err(CE_CONT, "i_vcc_find_changed_port:" 14861ae08745Sheppo "ddi_copyout" 14871ae08745Sheppo " failed\n"); 14881ae08745Sheppo return (EFAULT); 14891ae08745Sheppo } 14901ae08745Sheppo return (0); 14911ae08745Sheppo } 14921ae08745Sheppo } 14931ae08745Sheppo 14941ae08745Sheppo return (EINVAL); 14951ae08745Sheppo } 14961ae08745Sheppo 14971ae08745Sheppo /* clean up events after vntsd exits */ 14981ae08745Sheppo static int 14991ae08745Sheppo i_vcc_reset_events(vcc_t *vccp) 15001ae08745Sheppo { 15011ae08745Sheppo uint_t i; 15021ae08745Sheppo vcc_port_t *vport; 15031ae08745Sheppo 15041ae08745Sheppo for (i = 0; i < VCC_MAX_PORTS; i++) { 15051ae08745Sheppo vport = &(vccp->port[i]); 15061ae08745Sheppo 15071ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 15081ae08745Sheppo continue; 15091ae08745Sheppo } 15101ae08745Sheppo 15111ae08745Sheppo ASSERT(!mutex_owned(&vport->lock)); 15121ae08745Sheppo 15131ae08745Sheppo if (i == VCC_CONTROL_PORT) { 15141ae08745Sheppo /* close control port */ 15151ae08745Sheppo mutex_enter(&vport->lock); 15161ae08745Sheppo vport->status &= ~VCC_PORT_OPEN; 15171ae08745Sheppo 15181ae08745Sheppo /* clean up poll events */ 15191ae08745Sheppo vport->pollevent = 0; 15201ae08745Sheppo vport->pollflag = 0; 15211ae08745Sheppo mutex_exit(&vport->lock); 15221ae08745Sheppo continue; 15231ae08745Sheppo } 15241ae08745Sheppo if (vport->status & VCC_PORT_ADDED) { 15251ae08745Sheppo /* pending added port event to vntsd */ 15261ae08745Sheppo mutex_enter(&vport->lock); 15271ae08745Sheppo vport->status &= ~VCC_PORT_ADDED; 15281ae08745Sheppo mutex_exit(&vport->lock); 15291ae08745Sheppo } 15301ae08745Sheppo 15311ae08745Sheppo } 15321ae08745Sheppo 15331ae08745Sheppo vport = &vccp->port[VCC_CONTROL_PORT]; 15341ae08745Sheppo 15351ae08745Sheppo return (0); 15361ae08745Sheppo } 15371ae08745Sheppo 15381ae08745Sheppo /* ioctl VCC_FORCE_CLOSE */ 15391ae08745Sheppo static int 15401ae08745Sheppo i_vcc_force_close(vcc_t *vccp, caddr_t buf, int mode) 15411ae08745Sheppo { 15421ae08745Sheppo uint_t portno; 15431ae08745Sheppo vcc_port_t *vport; 15441ae08745Sheppo int rv; 15451ae08745Sheppo 15461ae08745Sheppo /* read in portno */ 15471ae08745Sheppo if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 15481ae08745Sheppo return (EFAULT); 15491ae08745Sheppo } 15501ae08745Sheppo 15511ae08745Sheppo D1("i_vcc_force_close@%d:\n", portno); 15521ae08745Sheppo 15531ae08745Sheppo if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 15541ae08745Sheppo return (EINVAL); 15551ae08745Sheppo } 15561ae08745Sheppo 15571ae08745Sheppo vport = &vccp->port[portno]; 15581ae08745Sheppo 15591ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 15601ae08745Sheppo return (EINVAL); 15611ae08745Sheppo } 15621ae08745Sheppo 15631ae08745Sheppo mutex_enter(&vport->lock); 15641ae08745Sheppo 15651ae08745Sheppo rv = i_vcc_close_port(vport); 15661ae08745Sheppo 15671ae08745Sheppo /* block callers other than vntsd */ 15681ae08745Sheppo vport->valid_pid = ddi_get_pid(); 15691ae08745Sheppo 15701ae08745Sheppo mutex_exit(&vport->lock); 15711ae08745Sheppo return (rv); 15721ae08745Sheppo 15731ae08745Sheppo } 15741ae08745Sheppo 15751ae08745Sheppo /* ioctl VCC_CONS_STATUS */ 15761ae08745Sheppo static int 15771ae08745Sheppo i_vcc_cons_status(vcc_t *vccp, caddr_t buf, int mode) 15781ae08745Sheppo { 15791ae08745Sheppo vcc_console_t console; 15801ae08745Sheppo vcc_port_t *vport; 15811ae08745Sheppo 15821ae08745Sheppo /* read in portno */ 15831ae08745Sheppo if (ddi_copyin((void*)buf, &console, sizeof (console), mode)) { 15841ae08745Sheppo return (EFAULT); 15851ae08745Sheppo } 15861ae08745Sheppo 15871ae08745Sheppo D1("i_vcc_cons_status@%d:\n", console.cons_no); 15881ae08745Sheppo 15891ae08745Sheppo if ((console.cons_no >= VCC_MAX_PORTS) || 15901ae08745Sheppo (console.cons_no == VCC_CONTROL_PORT)) { 15911ae08745Sheppo return (EINVAL); 15921ae08745Sheppo } 15931ae08745Sheppo 15941ae08745Sheppo 15951ae08745Sheppo vport = &vccp->port[console.cons_no]; 15961ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 15971ae08745Sheppo console.cons_no = -1; 15981ae08745Sheppo } else if (strncmp(console.domain_name, vport->minorp->domain_name, 15991ae08745Sheppo MAXPATHLEN)) { 16001ae08745Sheppo console.cons_no = -1; 16011ae08745Sheppo } else if (strncmp(console.group_name, vport->group_name, 16021ae08745Sheppo MAXPATHLEN)) { 16031ae08745Sheppo console.cons_no = -1; 16041ae08745Sheppo } else if (console.tcp_port != vport->tcp_port) { 16051ae08745Sheppo console.cons_no = -1; 16061ae08745Sheppo } 16071ae08745Sheppo 16081ae08745Sheppo D1("i_vcc_cons_status@%d: %s %s %llx\n", console.cons_no, 16091ae08745Sheppo console.group_name, console.domain_name, console.tcp_port); 16101ae08745Sheppo if (ddi_copyout(&console, (void *)buf, sizeof (console), mode) == -1) { 16111ae08745Sheppo cmn_err(CE_CONT, "i_vcc_cons_status ddi_copyout failed\n"); 16121ae08745Sheppo return (EFAULT); 16131ae08745Sheppo } 16141ae08745Sheppo 16151ae08745Sheppo return (0); 16161ae08745Sheppo } 16171ae08745Sheppo 16181ae08745Sheppo /* cb_ioctl handler for vcc control port */ 16191ae08745Sheppo static int 16201ae08745Sheppo i_vcc_ctrl_ioctl(vcc_t *vccp, int cmd, void* arg, int mode) 16211ae08745Sheppo { 16221ae08745Sheppo 16231ae08745Sheppo static uint_t num_ports; 16241ae08745Sheppo 16251ae08745Sheppo 16261ae08745Sheppo switch (cmd) { 16271ae08745Sheppo 16281ae08745Sheppo case VCC_NUM_CONSOLE: 16291ae08745Sheppo 16301ae08745Sheppo mutex_enter(&vccp->lock); 16311ae08745Sheppo num_ports = vccp->num_ports; 16321ae08745Sheppo mutex_exit(&vccp->lock); 16331ae08745Sheppo /* number of consoles */ 16341ae08745Sheppo 16351ae08745Sheppo return (ddi_copyout((void *)&num_ports, arg, 16361ae08745Sheppo sizeof (int), mode)); 16371ae08745Sheppo case VCC_CONS_TBL: 16381ae08745Sheppo 16391ae08745Sheppo /* console config table */ 16401ae08745Sheppo return (i_vcc_cons_tbl(vccp, num_ports, (caddr_t)arg, mode)); 16411ae08745Sheppo 16421ae08745Sheppo case VCC_INQUIRY: 16431ae08745Sheppo 16441ae08745Sheppo /* reason for wakeup */ 16451ae08745Sheppo return (i_vcc_inquiry(vccp, (caddr_t)arg, mode)); 16461ae08745Sheppo 16471ae08745Sheppo case VCC_CONS_INFO: 16481ae08745Sheppo /* a console config */ 16491ae08745Sheppo return (i_vcc_cons_info(vccp, (caddr_t)arg, mode)); 16501ae08745Sheppo 16511ae08745Sheppo case VCC_FORCE_CLOSE: 16521ae08745Sheppo /* force to close a console */ 16531ae08745Sheppo return (i_vcc_force_close(vccp, (caddr_t)arg, mode)); 16541ae08745Sheppo 16551ae08745Sheppo case VCC_CONS_STATUS: 16561ae08745Sheppo /* console status */ 16571ae08745Sheppo return (i_vcc_cons_status(vccp, (caddr_t)arg, mode)); 16581ae08745Sheppo 16591ae08745Sheppo default: 16601ae08745Sheppo 16611ae08745Sheppo /* unknown command */ 16621ae08745Sheppo return (ENODEV); 16631ae08745Sheppo } 16641ae08745Sheppo 16651ae08745Sheppo 16661ae08745Sheppo } 16671ae08745Sheppo 16681ae08745Sheppo /* write data to ldc. may block if channel has no space for write */ 16691ae08745Sheppo static int 16701ae08745Sheppo i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf) 16711ae08745Sheppo { 16721ae08745Sheppo int rv = EIO; 16731ae08745Sheppo size_t size; 16741ae08745Sheppo 16751ae08745Sheppo ASSERT(mutex_owned(&vport->lock)); 16761ae08745Sheppo ASSERT((vport->status & VCC_PORT_USE_WRITE_LDC) == 0); 16771ae08745Sheppo 16781ae08745Sheppo for (; ; ) { 16791ae08745Sheppo 16801ae08745Sheppo size = VCC_HDR_SZ + buf->size; 16811ae08745Sheppo rv = ldc_write(vport->ldc_handle, (caddr_t)buf, &size); 16821ae08745Sheppo 16831ae08745Sheppo D1("i_vcc_write_ldc: port@%d: err=%d %d bytes\n", 16841ae08745Sheppo vport->number, rv, size); 16851ae08745Sheppo 16861ae08745Sheppo if (rv == 0) { 16871ae08745Sheppo return (rv); 16881ae08745Sheppo } 16891ae08745Sheppo 16901ae08745Sheppo if (rv != EWOULDBLOCK) { 16911ae08745Sheppo return (EIO); 16921ae08745Sheppo } 16931ae08745Sheppo 16941ae08745Sheppo if (vport->status & VCC_PORT_NONBLOCK) { 16951ae08745Sheppo return (EAGAIN); 16961ae08745Sheppo } 16971ae08745Sheppo 16981ae08745Sheppo /* block util ldc has more space */ 16991ae08745Sheppo 17001ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 17011ae08745Sheppo VCC_PORT_LDC_WRITE_READY); 17021ae08745Sheppo 17031ae08745Sheppo if (rv) { 17041ae08745Sheppo return (rv); 17051ae08745Sheppo } 17061ae08745Sheppo 17071ae08745Sheppo vport->status &= ~VCC_PORT_LDC_WRITE_READY; 17081ae08745Sheppo 17091ae08745Sheppo } 17101ae08745Sheppo 17111ae08745Sheppo } 17121ae08745Sheppo 17131ae08745Sheppo 17141ae08745Sheppo 17151ae08745Sheppo /* cb_ioctl handler for port ioctl */ 17161ae08745Sheppo static int 17171ae08745Sheppo i_vcc_port_ioctl(vcc_t *vccp, minor_t minor, int portno, int cmd, void *arg, 17181ae08745Sheppo int mode) 17191ae08745Sheppo { 17201ae08745Sheppo 17211ae08745Sheppo vcc_port_t *vport; 17221ae08745Sheppo struct termios term; 17231ae08745Sheppo vcc_msg_t buf; 17241ae08745Sheppo int rv; 17251ae08745Sheppo 17261ae08745Sheppo D1("i_vcc_port_ioctl@%d cmd %d\n", portno, cmd); 17271ae08745Sheppo 17281ae08745Sheppo vport = &(vccp->port[portno]); 17291ae08745Sheppo 17301ae08745Sheppo if ((vport->status & VCC_PORT_AVAIL) == 0) { 17311ae08745Sheppo return (EIO); 17321ae08745Sheppo } 17331ae08745Sheppo 17341ae08745Sheppo 17351ae08745Sheppo switch (cmd) { 17361ae08745Sheppo 17371ae08745Sheppo /* terminal support */ 17381ae08745Sheppo case TCGETA: 17391ae08745Sheppo case TCGETS: 17401ae08745Sheppo 17411ae08745Sheppo mutex_enter(&vport->lock); 17421ae08745Sheppo 17431ae08745Sheppo /* check minor no and pid */ 17441ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 17451ae08745Sheppo vport)) != 0) { 17461ae08745Sheppo mutex_exit(&vport->lock); 17471ae08745Sheppo return (rv); 17481ae08745Sheppo } 17491ae08745Sheppo 17501ae08745Sheppo (void) memcpy(&term, &vport->term, sizeof (term)); 17511ae08745Sheppo mutex_exit(&vport->lock); 17521ae08745Sheppo 17531ae08745Sheppo return (ddi_copyout(&term, arg, sizeof (term), mode)); 17541ae08745Sheppo 17551ae08745Sheppo case TCSETS: 17561ae08745Sheppo case TCSETA: 17571ae08745Sheppo case TCSETAW: 17581ae08745Sheppo case TCSETAF: 17591ae08745Sheppo 17601ae08745Sheppo if (ddi_copyin(arg, &term, sizeof (term), mode) != 0) { 17611ae08745Sheppo return (EFAULT); 17621ae08745Sheppo } 17631ae08745Sheppo 17641ae08745Sheppo mutex_enter(&vport->lock); 17651ae08745Sheppo 17661ae08745Sheppo /* check minor no and pid */ 17671ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 17681ae08745Sheppo vport)) != 0) { 17691ae08745Sheppo mutex_exit(&vport->lock); 17701ae08745Sheppo return (rv); 17711ae08745Sheppo } 17721ae08745Sheppo 17731ae08745Sheppo (void) memcpy(&vport->term, &term, sizeof (term)); 17741ae08745Sheppo mutex_exit(&vport->lock); 17751ae08745Sheppo return (0); 17761ae08745Sheppo 17771ae08745Sheppo 17781ae08745Sheppo case TCSBRK: 17791ae08745Sheppo 17801ae08745Sheppo /* send break to console */ 17811ae08745Sheppo mutex_enter(&vport->lock); 17821ae08745Sheppo 17831ae08745Sheppo /* check minor no and pid */ 17841ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 17851ae08745Sheppo vport)) != 0) { 17861ae08745Sheppo mutex_exit(&vport->lock); 17871ae08745Sheppo return (rv); 17881ae08745Sheppo } 17891ae08745Sheppo 17901ae08745Sheppo /* wait for write available */ 17911ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 17921ae08745Sheppo VCC_PORT_LDC_CHANNEL_READY| VCC_PORT_USE_WRITE_LDC); 17931ae08745Sheppo if (rv) { 17941ae08745Sheppo mutex_exit(&vport->lock); 17951ae08745Sheppo return (rv); 17961ae08745Sheppo } 17971ae08745Sheppo 17981ae08745Sheppo vport->status &= ~VCC_PORT_USE_WRITE_LDC; 17991ae08745Sheppo 18001ae08745Sheppo buf.type = LDC_CONSOLE_CTRL; 18011ae08745Sheppo buf.ctrl_msg = LDC_CONSOLE_BREAK; 18021ae08745Sheppo buf.size = 0; 18031ae08745Sheppo 18041ae08745Sheppo rv = i_vcc_write_ldc(vport, &buf); 18051ae08745Sheppo 18061ae08745Sheppo mutex_exit(&vport->lock); 18071ae08745Sheppo 18081ae08745Sheppo i_vcc_set_port_status(vport, &vport->write_cv, 18091ae08745Sheppo VCC_PORT_USE_WRITE_LDC); 18101ae08745Sheppo return (0); 18111ae08745Sheppo 18121ae08745Sheppo case TCXONC: 18131ae08745Sheppo /* suspend read or write */ 18141ae08745Sheppo if (ddi_copyin(arg, &cmd, sizeof (int), mode) != 0) { 18151ae08745Sheppo return (EFAULT); 18161ae08745Sheppo } 18171ae08745Sheppo 18181ae08745Sheppo mutex_enter(&vport->lock); 18191ae08745Sheppo 18201ae08745Sheppo /* check minor no and pid */ 18211ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 18221ae08745Sheppo vport)) != 0) { 18231ae08745Sheppo mutex_exit(&vport->lock); 18241ae08745Sheppo return (rv); 18251ae08745Sheppo } 18261ae08745Sheppo 18271ae08745Sheppo 18281ae08745Sheppo switch (cmd) { 18291ae08745Sheppo 18301ae08745Sheppo case 0: 18311ae08745Sheppo vport->status |= VCC_PORT_TERM_WR; 18321ae08745Sheppo cv_broadcast(&vport->write_cv); 18331ae08745Sheppo break; 18341ae08745Sheppo case 1: 18351ae08745Sheppo /* get write lock */ 18361ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 18371ae08745Sheppo VCC_PORT_USE_WRITE_LDC); 18381ae08745Sheppo if (rv) { 18391ae08745Sheppo mutex_exit(&vport->lock); 18401ae08745Sheppo return (rv); 18411ae08745Sheppo } 18421ae08745Sheppo vport->status &= ~VCC_PORT_TERM_WR; 18431ae08745Sheppo cv_broadcast(&vport->write_cv); 18441ae08745Sheppo break; 18451ae08745Sheppo case 2: 18461ae08745Sheppo vport->status |= VCC_PORT_TERM_RD; 18471ae08745Sheppo cv_broadcast(&vport->read_cv); 18481ae08745Sheppo break; 18491ae08745Sheppo case 3: 18501ae08745Sheppo /* get read lock */ 18511ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 18521ae08745Sheppo VCC_PORT_USE_READ_LDC); 18531ae08745Sheppo if (rv) { 18541ae08745Sheppo mutex_exit(&vport->lock); 18551ae08745Sheppo return (rv); 18561ae08745Sheppo } 18571ae08745Sheppo vport->status &= ~VCC_PORT_TERM_RD; 18581ae08745Sheppo cv_broadcast(&vport->read_cv); 18591ae08745Sheppo break; 18601ae08745Sheppo 18611ae08745Sheppo default: 18621ae08745Sheppo break; 18631ae08745Sheppo } 18641ae08745Sheppo 18651ae08745Sheppo mutex_exit(&vport->lock); 18661ae08745Sheppo return (0); 18671ae08745Sheppo 18681ae08745Sheppo case TCFLSH: 18691ae08745Sheppo return (0); 18701ae08745Sheppo 18711ae08745Sheppo default: 18721ae08745Sheppo return (ENODEV); 18731ae08745Sheppo } 18741ae08745Sheppo 18751ae08745Sheppo } 18761ae08745Sheppo 18771ae08745Sheppo /* cb_ioctl */ 18781ae08745Sheppo static int 18791ae08745Sheppo vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 18801ae08745Sheppo cred_t *credp, int *rvalp) 18811ae08745Sheppo { 18821ae08745Sheppo _NOTE(ARGUNUSED(credp, rvalp)) 18831ae08745Sheppo 18841ae08745Sheppo int instance; 18851ae08745Sheppo minor_t minor; 18861ae08745Sheppo int portno; 18871ae08745Sheppo vcc_t *vccp; 18881ae08745Sheppo 18891ae08745Sheppo minor = getminor(dev); 18901ae08745Sheppo 18911ae08745Sheppo instance = VCCINST(minor); 18921ae08745Sheppo 18931ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 18941ae08745Sheppo if (vccp == NULL) { 18951ae08745Sheppo return (ENXIO); 18961ae08745Sheppo } 18971ae08745Sheppo 18981ae08745Sheppo portno = VCCPORT(vccp, minor); 18991ae08745Sheppo 19001ae08745Sheppo D1("vcc_ioctl: virtual-console-concentrator@%d:%d\n", instance, portno); 19011ae08745Sheppo 19021ae08745Sheppo if (portno >= VCC_MAX_PORTS) { 19031ae08745Sheppo cmn_err(CE_CONT, "vcc_ioctl:virtual-console-concentrator@%d" 19041ae08745Sheppo " invalid portno\n", portno); 19051ae08745Sheppo return (EINVAL); 19061ae08745Sheppo } 19071ae08745Sheppo 19081ae08745Sheppo D1("vcc_ioctl: virtual-console-concentrator@%d:%d ioctl cmd=%d\n", 19091ae08745Sheppo instance, portno, cmd); 19101ae08745Sheppo 19111ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 19121ae08745Sheppo /* control ioctl */ 19131ae08745Sheppo return (i_vcc_ctrl_ioctl(vccp, cmd, (void *)arg, mode)); 19141ae08745Sheppo } 19151ae08745Sheppo 19161ae08745Sheppo /* data port ioctl */ 19171ae08745Sheppo return (i_vcc_port_ioctl(vccp, minor, portno, cmd, (void *)arg, mode)); 19181ae08745Sheppo } 19191ae08745Sheppo 19201ae08745Sheppo /* cb_read */ 19211ae08745Sheppo static int 19221ae08745Sheppo vcc_read(dev_t dev, struct uio *uiop, cred_t *credp) 19231ae08745Sheppo { 19241ae08745Sheppo _NOTE(ARGUNUSED(credp)) 19251ae08745Sheppo 19261ae08745Sheppo int instance; 19271ae08745Sheppo minor_t minor; 19281ae08745Sheppo uint_t portno; 19291ae08745Sheppo vcc_t *vccp; 19301ae08745Sheppo vcc_port_t *vport; 19311ae08745Sheppo int rv = EIO; /* by default fail ! */ 19321ae08745Sheppo char *buf; 19331ae08745Sheppo size_t uio_size; 19341ae08745Sheppo size_t size; 19351ae08745Sheppo 19361ae08745Sheppo minor = getminor(dev); 19371ae08745Sheppo 19381ae08745Sheppo instance = VCCINST(minor); 19391ae08745Sheppo 19401ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 19411ae08745Sheppo if (vccp == NULL) { 19421ae08745Sheppo return (ENXIO); 19431ae08745Sheppo } 19441ae08745Sheppo 19451ae08745Sheppo portno = VCCPORT(vccp, minor); 19461ae08745Sheppo 19471ae08745Sheppo /* no read for control port */ 19481ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 19491ae08745Sheppo return (EIO); 19501ae08745Sheppo } 19511ae08745Sheppo 19521ae08745Sheppo /* temp buf to hold ldc data */ 19531ae08745Sheppo uio_size = uiop->uio_resid; 19541ae08745Sheppo 19551ae08745Sheppo if (uio_size < VCC_MTU_SZ) { 19561ae08745Sheppo return (EINVAL); 19571ae08745Sheppo } 19581ae08745Sheppo 19591ae08745Sheppo vport = &(vccp->port[portno]); 19601ae08745Sheppo 19611ae08745Sheppo mutex_enter(&vport->lock); 19621ae08745Sheppo 19631ae08745Sheppo /* check minor no and pid */ 19641ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 19651ae08745Sheppo vport)) != 0) { 19661ae08745Sheppo mutex_exit(&vport->lock); 19671ae08745Sheppo return (rv); 19681ae08745Sheppo } 19691ae08745Sheppo 19701ae08745Sheppo 19711ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->read_cv, 19721ae08745Sheppo VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY| 19731ae08745Sheppo VCC_PORT_USE_READ_LDC); 19741ae08745Sheppo if (rv) { 19751ae08745Sheppo mutex_exit(&vport->lock); 19761ae08745Sheppo return (rv); 19771ae08745Sheppo } 19781ae08745Sheppo 19791ae08745Sheppo buf = kmem_alloc(uio_size, KM_SLEEP); 19801ae08745Sheppo 19811ae08745Sheppo vport->status &= ~VCC_PORT_USE_READ_LDC; 19821ae08745Sheppo 19831ae08745Sheppo for (; ; ) { 19841ae08745Sheppo 19851ae08745Sheppo size = uio_size; 19861ae08745Sheppo rv = i_vcc_read_ldc(vport, buf, &size); 19871ae08745Sheppo 19881ae08745Sheppo 19891ae08745Sheppo if (rv == EAGAIN) { 19901ae08745Sheppo /* should block? */ 19911ae08745Sheppo if (vport->status & VCC_PORT_NONBLOCK) { 19921ae08745Sheppo break; 19931ae08745Sheppo } 19941ae08745Sheppo 19951ae08745Sheppo } else if (rv) { 19961ae08745Sheppo /* error */ 19971ae08745Sheppo break; 19981ae08745Sheppo } 19991ae08745Sheppo 20001ae08745Sheppo if (size > 0) { 20011ae08745Sheppo /* got data */ 20021ae08745Sheppo break; 20031ae08745Sheppo } 20041ae08745Sheppo 20051ae08745Sheppo /* wait for data from ldc */ 20061ae08745Sheppo vport->status &= ~VCC_PORT_LDC_DATA_READY; 20071ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->read_cv, 20081ae08745Sheppo VCC_PORT_LDC_DATA_READY); 20091ae08745Sheppo if (rv) { 20101ae08745Sheppo break; 20111ae08745Sheppo } 20121ae08745Sheppo } 20131ae08745Sheppo 20141ae08745Sheppo mutex_exit(&vport->lock); 20151ae08745Sheppo 20161ae08745Sheppo if ((rv == 0) && (size > 0)) { 20171ae08745Sheppo /* data is in buf */ 20181ae08745Sheppo rv = uiomove(buf, size, UIO_READ, uiop); 20191ae08745Sheppo } 20201ae08745Sheppo 20211ae08745Sheppo kmem_free(buf, uio_size); 20221ae08745Sheppo i_vcc_set_port_status(vport, &vport->read_cv, VCC_PORT_USE_READ_LDC); 20231ae08745Sheppo 20241ae08745Sheppo return (rv); 20251ae08745Sheppo } 20261ae08745Sheppo 20271ae08745Sheppo 20281ae08745Sheppo /* cb_write */ 20291ae08745Sheppo static int 20301ae08745Sheppo vcc_write(dev_t dev, struct uio *uiop, cred_t *credp) 20311ae08745Sheppo { 20321ae08745Sheppo _NOTE(ARGUNUSED(credp)) 20331ae08745Sheppo 20341ae08745Sheppo int instance; 20351ae08745Sheppo minor_t minor; 20361ae08745Sheppo size_t size; 20371ae08745Sheppo size_t bytes; 20381ae08745Sheppo uint_t portno; 20391ae08745Sheppo vcc_t *vccp; 20401ae08745Sheppo 20411ae08745Sheppo vcc_port_t *vport; 20421ae08745Sheppo int rv = EIO; 20431ae08745Sheppo 20441ae08745Sheppo vcc_msg_t buf; 20451ae08745Sheppo 20461ae08745Sheppo minor = getminor(dev); 20471ae08745Sheppo 20481ae08745Sheppo instance = VCCINST(minor); 20491ae08745Sheppo 20501ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 20511ae08745Sheppo if (vccp == NULL) { 20521ae08745Sheppo return (ENXIO); 20531ae08745Sheppo } 20541ae08745Sheppo 20551ae08745Sheppo portno = VCCPORT(vccp, minor); 20561ae08745Sheppo 20571ae08745Sheppo /* no write for control port */ 20581ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 20591ae08745Sheppo return (EIO); 20601ae08745Sheppo } 20611ae08745Sheppo vport = &(vccp->port[portno]); 20621ae08745Sheppo 20631ae08745Sheppo /* 20641ae08745Sheppo * check if the channel has been configured, 20651ae08745Sheppo * if write has been suspend and grab write lock. 20661ae08745Sheppo */ 20671ae08745Sheppo mutex_enter(&vport->lock); 20681ae08745Sheppo 20691ae08745Sheppo /* check minor no and pid */ 20701ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 20711ae08745Sheppo vport)) != 0) { 20721ae08745Sheppo mutex_exit(&vport->lock); 20731ae08745Sheppo return (rv); 20741ae08745Sheppo } 20751ae08745Sheppo 20761ae08745Sheppo rv = i_vcc_wait_port_status(vport, &vport->write_cv, 20771ae08745Sheppo VCC_PORT_TERM_WR|VCC_PORT_LDC_CHANNEL_READY| 20781ae08745Sheppo VCC_PORT_USE_WRITE_LDC); 20791ae08745Sheppo if (rv) { 20801ae08745Sheppo mutex_exit(&vport->lock); 20811ae08745Sheppo return (rv); 20821ae08745Sheppo } 20831ae08745Sheppo 20841ae08745Sheppo vport->status &= ~VCC_PORT_USE_WRITE_LDC; 20851ae08745Sheppo mutex_exit(&vport->lock); 20861ae08745Sheppo size = uiop->uio_resid; 20871ae08745Sheppo 20881ae08745Sheppo D2("vcc_write: virtual-console-concentrator@%d:%d writing %d bytes\n", 20891ae08745Sheppo instance, portno, size); 20901ae08745Sheppo 20911ae08745Sheppo 20921ae08745Sheppo 20931ae08745Sheppo buf.type = LDC_CONSOLE_DATA; 20941ae08745Sheppo 20951ae08745Sheppo while (size) { 20961ae08745Sheppo 20971ae08745Sheppo bytes = MIN(size, VCC_MTU_SZ); 20981ae08745Sheppo /* move data */ 20991ae08745Sheppo rv = uiomove(&(buf.data), bytes, UIO_WRITE, uiop); 21001ae08745Sheppo 21011ae08745Sheppo if (rv) { 21021ae08745Sheppo break; 21031ae08745Sheppo } 21041ae08745Sheppo 21051ae08745Sheppo /* write to ldc */ 21061ae08745Sheppo buf.size = bytes; 21071ae08745Sheppo 21081ae08745Sheppo mutex_enter(&vport->lock); 21091ae08745Sheppo 21101ae08745Sheppo /* check minor no and pid */ 21111ae08745Sheppo if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 21121ae08745Sheppo vport)) != 0) { 21131ae08745Sheppo mutex_exit(&vport->lock); 21141ae08745Sheppo return (rv); 21151ae08745Sheppo } 21161ae08745Sheppo 21171ae08745Sheppo rv = i_vcc_write_ldc(vport, &buf); 21181ae08745Sheppo 21191ae08745Sheppo mutex_exit(&vport->lock); 21201ae08745Sheppo 21211ae08745Sheppo if (rv) { 21221ae08745Sheppo break; 21231ae08745Sheppo } 21241ae08745Sheppo 21251ae08745Sheppo size -= bytes; 21261ae08745Sheppo 21271ae08745Sheppo } 21281ae08745Sheppo 21291ae08745Sheppo i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC); 21301ae08745Sheppo return (rv); 21311ae08745Sheppo } 21321ae08745Sheppo 21331ae08745Sheppo /* mdeg callback for a removed port */ 21341ae08745Sheppo static int 21351ae08745Sheppo i_vcc_md_remove_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 21361ae08745Sheppo { 21371ae08745Sheppo uint64_t portno; /* md requires 64bit for port number */ 21381ae08745Sheppo int rv = MDEG_FAILURE; 21391ae08745Sheppo vcc_port_t *vport; 21401ae08745Sheppo 21411ae08745Sheppo if (md_get_prop_val(mdp, mdep, "id", &portno)) { 21421ae08745Sheppo cmn_err(CE_CONT, "vcc_mdeg_cb: port has no 'id' property\n"); 21431ae08745Sheppo return (MDEG_FAILURE); 21441ae08745Sheppo } 21451ae08745Sheppo 21461ae08745Sheppo if ((portno >= VCC_MAX_PORTS) || (portno < 0)) { 21471ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld invalid port no\n", 21481ae08745Sheppo portno); 21491ae08745Sheppo return (MDEG_FAILURE); 21501ae08745Sheppo } 21511ae08745Sheppo 21521ae08745Sheppo if (portno == VCC_CONTROL_PORT) { 21531ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld can not remove" 21541ae08745Sheppo "control port\n", 21551ae08745Sheppo portno); 21561ae08745Sheppo return (MDEG_FAILURE); 21571ae08745Sheppo } 21581ae08745Sheppo 21591ae08745Sheppo vport = &(vccp->port[portno]); 21601ae08745Sheppo 21611ae08745Sheppo /* delete the port */ 21621ae08745Sheppo mutex_enter(&vport->lock); 21631ae08745Sheppo rv = i_vcc_delete_port(vccp, vport); 21641ae08745Sheppo mutex_exit(&vport->lock); 21651ae08745Sheppo 21661ae08745Sheppo mutex_enter(&vccp->lock); 21671ae08745Sheppo vccp->num_ports--; 21681ae08745Sheppo mutex_exit(&vccp->lock); 21691ae08745Sheppo 21701ae08745Sheppo return (rv ? MDEG_FAILURE : MDEG_SUCCESS); 21711ae08745Sheppo } 21721ae08745Sheppo 21731ae08745Sheppo static int 21741ae08745Sheppo i_vcc_get_ldc_id(md_t *md, mde_cookie_t mdep, uint64_t *ldc_id) 21751ae08745Sheppo { 21761ae08745Sheppo int num_nodes; 21771ae08745Sheppo size_t size; 21781ae08745Sheppo mde_cookie_t *channel; 21791ae08745Sheppo int num_channels; 21801ae08745Sheppo 21811ae08745Sheppo 21821ae08745Sheppo if ((num_nodes = md_node_count(md)) <= 0) { 21831ae08745Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc_channel_id:" 21841ae08745Sheppo " Invalid node count in Machine Description subtree"); 21851ae08745Sheppo return (-1); 21861ae08745Sheppo } 21871ae08745Sheppo size = num_nodes*(sizeof (*channel)); 21881ae08745Sheppo channel = kmem_zalloc(size, KM_SLEEP); 21891ae08745Sheppo ASSERT(channel != NULL); /* because KM_SLEEP */ 21901ae08745Sheppo 21911ae08745Sheppo 21921ae08745Sheppo /* Look for channel endpoint child(ren) of the vdisk MD node */ 21931ae08745Sheppo if ((num_channels = md_scan_dag(md, mdep, 21941ae08745Sheppo md_find_name(md, "channel-endpoint"), 21951ae08745Sheppo md_find_name(md, "fwd"), channel)) <= 0) { 21961ae08745Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc_id: No 'channel-endpoint'" 21971ae08745Sheppo " found for vcc"); 21981ae08745Sheppo kmem_free(channel, size); 21991ae08745Sheppo return (-1); 22001ae08745Sheppo } 22011ae08745Sheppo 22021ae08745Sheppo /* Get the "id" value for the first channel endpoint node */ 22031ae08745Sheppo if (md_get_prop_val(md, channel[0], "id", ldc_id) != 0) { 22041ae08745Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc: No id property found " 22051ae08745Sheppo "for channel-endpoint of vcc"); 22061ae08745Sheppo kmem_free(channel, size); 22071ae08745Sheppo return (-1); 22081ae08745Sheppo } 22091ae08745Sheppo 22101ae08745Sheppo if (num_channels > 1) { 22111ae08745Sheppo cmn_err(CE_CONT, "i_vcc_get_ldc: Warning: Using ID of first" 22121ae08745Sheppo " of multiple channels for this vcc"); 22131ae08745Sheppo } 22141ae08745Sheppo 22151ae08745Sheppo kmem_free(channel, size); 22161ae08745Sheppo return (0); 22171ae08745Sheppo } 22181ae08745Sheppo /* mdeg callback for an added port */ 22191ae08745Sheppo static int 22201ae08745Sheppo i_vcc_md_add_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 22211ae08745Sheppo { 22221ae08745Sheppo uint64_t portno; /* md requires 64 bit */ 22231ae08745Sheppo char *domain_name; 22241ae08745Sheppo char *group_name; 22251ae08745Sheppo uint64_t ldc_id; 22261ae08745Sheppo uint64_t tcp_port; 22271ae08745Sheppo vcc_port_t *vport; 22281ae08745Sheppo 22291ae08745Sheppo /* read in the port's reg property */ 22301ae08745Sheppo if (md_get_prop_val(mdp, mdep, "id", &portno)) { 22311ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port_: port has no 'id' " 22321ae08745Sheppo "property\n"); 22331ae08745Sheppo return (MDEG_FAILURE); 22341ae08745Sheppo } 22351ae08745Sheppo 22361ae08745Sheppo /* read in the port's "vcc-doman-name" property */ 22371ae08745Sheppo if (md_get_prop_str(mdp, mdep, "vcc-domain-name", &domain_name)) { 22381ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has " 22391ae08745Sheppo "no 'vcc-domain-name' property\n", portno); 22401ae08745Sheppo return (MDEG_FAILURE); 22411ae08745Sheppo } 22421ae08745Sheppo 22431ae08745Sheppo 22441ae08745Sheppo /* read in the port's "vcc-group-name" property */ 22451ae08745Sheppo if (md_get_prop_str(mdp, mdep, "vcc-group-name", &group_name)) { 22461ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no " 22471ae08745Sheppo "'vcc-group-name'property\n", portno); 22481ae08745Sheppo return (MDEG_FAILURE); 22491ae08745Sheppo } 22501ae08745Sheppo 22511ae08745Sheppo 22521ae08745Sheppo /* read in the port's "vcc-tcp-port" property */ 22531ae08745Sheppo if (md_get_prop_val(mdp, mdep, "vcc-tcp-port", &tcp_port)) { 22541ae08745Sheppo cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no" 22551ae08745Sheppo "'vcc-tcp-port' property\n", portno); 22561ae08745Sheppo return (MDEG_FAILURE); 22571ae08745Sheppo } 22581ae08745Sheppo 22591ae08745Sheppo D1("i_vcc_md_add_port: port@%d domain-name=%s group-name=%s" 22601ae08745Sheppo " tcp-port=%lld\n", portno, domain_name, group_name, tcp_port); 22611ae08745Sheppo 22621ae08745Sheppo /* add the port */ 22631ae08745Sheppo if (i_vcc_add_port(vccp, group_name, tcp_port, portno, domain_name)) { 22641ae08745Sheppo return (MDEG_FAILURE); 22651ae08745Sheppo } 22661ae08745Sheppo 22671ae08745Sheppo vport = &vccp->port[portno]; 22681ae08745Sheppo if (i_vcc_get_ldc_id(mdp, mdep, &ldc_id)) { 22691ae08745Sheppo mutex_enter(&vport->lock); 22701ae08745Sheppo (void) i_vcc_delete_port(vccp, vport); 22711ae08745Sheppo mutex_exit(&vport->lock); 22721ae08745Sheppo return (MDEG_FAILURE); 22731ae08745Sheppo } 22741ae08745Sheppo 22751ae08745Sheppo /* configure the port */ 22761ae08745Sheppo if (i_vcc_config_port(vccp, portno, ldc_id)) { 22771ae08745Sheppo mutex_enter(&vport->lock); 22781ae08745Sheppo (void) i_vcc_delete_port(vccp, vport); 22791ae08745Sheppo mutex_exit(&vport->lock); 22801ae08745Sheppo return (MDEG_FAILURE); 22811ae08745Sheppo } 22821ae08745Sheppo 22831ae08745Sheppo mutex_enter(&vccp->lock); 22841ae08745Sheppo vccp->num_ports++; 22851ae08745Sheppo mutex_exit(&vccp->lock); 22861ae08745Sheppo 22871ae08745Sheppo vport = &vccp->port[VCC_CONTROL_PORT]; 22881ae08745Sheppo 22891ae08745Sheppo if (vport->pollflag & VCC_POLL_CONFIG) { 22901ae08745Sheppo /* wakeup vntsd */ 22911ae08745Sheppo mutex_enter(&vport->lock); 22921ae08745Sheppo vport->pollevent |= VCC_POLL_ADD_PORT; 22931ae08745Sheppo mutex_exit(&vport->lock); 22941ae08745Sheppo pollwakeup(&vport->poll, POLLIN); 22951ae08745Sheppo } 22961ae08745Sheppo 22971ae08745Sheppo return (MDEG_SUCCESS); 22981ae08745Sheppo } 22991ae08745Sheppo 23001ae08745Sheppo /* mdeg callback */ 23011ae08745Sheppo static int 23021ae08745Sheppo vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 23031ae08745Sheppo { 23041ae08745Sheppo int idx; 23051ae08745Sheppo vcc_t *vccp; 23061ae08745Sheppo int rv; 23071ae08745Sheppo 23081ae08745Sheppo vccp = (vcc_t *)cb_argp; 23091ae08745Sheppo ASSERT(vccp); 23101ae08745Sheppo 23111ae08745Sheppo if (resp == NULL) { 23121ae08745Sheppo return (MDEG_FAILURE); 23131ae08745Sheppo } 23141ae08745Sheppo 23151ae08745Sheppo /* added port */ 23161ae08745Sheppo D1("vcc_mdeg_cb: added %d port(s)\n", resp->added.nelem); 23171ae08745Sheppo 23181ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 23191ae08745Sheppo rv = i_vcc_md_add_port(resp->added.mdp, 23201ae08745Sheppo resp->added.mdep[idx], vccp); 23211ae08745Sheppo 23221ae08745Sheppo if (rv != MDEG_SUCCESS) { 23231ae08745Sheppo return (rv); 23241ae08745Sheppo } 23251ae08745Sheppo } 23261ae08745Sheppo 23271ae08745Sheppo /* removed port */ 23281ae08745Sheppo D1("vcc_mdeg_cb: removed %d port(s)\n", resp->removed.nelem); 23291ae08745Sheppo 23301ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 23311ae08745Sheppo rv = i_vcc_md_remove_port(resp->removed.mdp, 23321ae08745Sheppo resp->removed.mdep[idx], vccp); 23331ae08745Sheppo 23341ae08745Sheppo if (rv != MDEG_SUCCESS) { 23351ae08745Sheppo return (rv); 23361ae08745Sheppo } 23371ae08745Sheppo } 23381ae08745Sheppo 23391ae08745Sheppo /* 23401ae08745Sheppo * XXX - Currently no support for updating already active 23411ae08745Sheppo * ports. So, ignore the match_curr and match_prev arrays 23421ae08745Sheppo * for now. 23431ae08745Sheppo */ 23441ae08745Sheppo 23451ae08745Sheppo 23461ae08745Sheppo return (MDEG_SUCCESS); 23471ae08745Sheppo } 23481ae08745Sheppo 23491ae08745Sheppo 23501ae08745Sheppo /* cb_chpoll */ 23511ae08745Sheppo static int 23521ae08745Sheppo vcc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 23531ae08745Sheppo struct pollhead **phpp) 23541ae08745Sheppo { 23551ae08745Sheppo int instance; 23561ae08745Sheppo minor_t minor; 23571ae08745Sheppo uint_t portno; 23581ae08745Sheppo vcc_t *vccp; 23591ae08745Sheppo vcc_port_t *vport; 23601ae08745Sheppo 23611ae08745Sheppo minor = getminor(dev); 23621ae08745Sheppo 23631ae08745Sheppo instance = VCCINST(minor); 23641ae08745Sheppo 23651ae08745Sheppo vccp = ddi_get_soft_state(vcc_ssp, instance); 23661ae08745Sheppo if (vccp == NULL) { 23671ae08745Sheppo return (ENXIO); 23681ae08745Sheppo } 23691ae08745Sheppo 23701ae08745Sheppo portno = VCCPORT(vccp, minor); 23711ae08745Sheppo 23721ae08745Sheppo vport = &(vccp->port[portno]); 23731ae08745Sheppo 23741ae08745Sheppo D1("vcc_chpoll: virtual-console-concentrator@%d events 0x%x\n", 23751ae08745Sheppo portno, events); 23761ae08745Sheppo 23771ae08745Sheppo *reventsp = 0; 23781ae08745Sheppo 23791ae08745Sheppo if (portno != VCC_CONTROL_PORT) { 23801ae08745Sheppo return (ENXIO); 23811ae08745Sheppo } 23821ae08745Sheppo 23831ae08745Sheppo /* poll for config change */ 23841ae08745Sheppo if (vport->pollevent) { 23851ae08745Sheppo *reventsp |= (events & POLLIN); 23861ae08745Sheppo } 23871ae08745Sheppo 23881ae08745Sheppo if (((*reventsp) == 0) && (!anyyet)) { 23891ae08745Sheppo *phpp = &vport->poll; 23901ae08745Sheppo if (events & POLLIN) { 23911ae08745Sheppo mutex_enter(&vport->lock); 23921ae08745Sheppo vport->pollflag |= VCC_POLL_CONFIG; 23931ae08745Sheppo mutex_exit(&vport->lock); 23941ae08745Sheppo } else { 23951ae08745Sheppo return (ENXIO); 23961ae08745Sheppo } 23971ae08745Sheppo } 23981ae08745Sheppo 23991ae08745Sheppo D1("vcc_chpoll: virtual-console-concentrator@%d:%d ev=0x%x, " 24001ae08745Sheppo "rev=0x%x pev=0x%x, flag=0x%x\n", 24011ae08745Sheppo instance, portno, events, (*reventsp), 24021ae08745Sheppo vport->pollevent, vport->pollflag); 24031ae08745Sheppo 24041ae08745Sheppo 24051ae08745Sheppo return (0); 24061ae08745Sheppo } 2407