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