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