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