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