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