130588217SMike Christensen /* 230588217SMike Christensen * CDDL HEADER START 330588217SMike Christensen * 430588217SMike Christensen * The contents of this file are subject to the terms of the 530588217SMike Christensen * Common Development and Distribution License (the "License"). 630588217SMike Christensen * You may not use this file except in compliance with the License. 730588217SMike Christensen * 830588217SMike Christensen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 930588217SMike Christensen * or http://www.opensolaris.org/os/licensing. 1030588217SMike Christensen * See the License for the specific language governing permissions 1130588217SMike Christensen * and limitations under the License. 1230588217SMike Christensen * 1330588217SMike Christensen * When distributing Covered Code, include this CDDL HEADER in each 1430588217SMike Christensen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1530588217SMike Christensen * If applicable, add the following below this CDDL HEADER, with the 1630588217SMike Christensen * fields enclosed by brackets "[]" replaced with your own identifying 1730588217SMike Christensen * information: Portions Copyright [yyyy] [name of copyright owner] 1830588217SMike Christensen * 1930588217SMike Christensen * CDDL HEADER END 2030588217SMike Christensen */ 2130588217SMike Christensen 2230588217SMike Christensen /* 2349b225e1SGavin Maltby * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2430588217SMike Christensen * Use is subject to license terms. 2530588217SMike Christensen */ 2630588217SMike Christensen 2730588217SMike Christensen /* 2830588217SMike Christensen * LDOMs Domain Services Device Driver 2930588217SMike Christensen */ 3030588217SMike Christensen #include <sys/types.h> 3130588217SMike Christensen #include <sys/file.h> 3230588217SMike Christensen #include <sys/errno.h> 3330588217SMike Christensen #include <sys/open.h> 3430588217SMike Christensen #include <sys/cred.h> 3530588217SMike Christensen #include <sys/uio.h> 3630588217SMike Christensen #include <sys/stat.h> 3730588217SMike Christensen #include <sys/ksynch.h> 3830588217SMike Christensen #include <sys/modctl.h> 3930588217SMike Christensen #include <sys/conf.h> 4030588217SMike Christensen #include <sys/devops.h> 4130588217SMike Christensen #include <sys/debug.h> 4230588217SMike Christensen #include <sys/cmn_err.h> 4330588217SMike Christensen #include <sys/ddi.h> 4430588217SMike Christensen #include <sys/sunddi.h> 4530588217SMike Christensen #include <sys/taskq.h> 4630588217SMike Christensen #include <sys/disp.h> 4730588217SMike Christensen #include <sys/note.h> 4830588217SMike Christensen #include <sys/mach_descrip.h> 4930588217SMike Christensen #include <sys/mdesc.h> 5030588217SMike Christensen #include <sys/mdeg.h> 5130588217SMike Christensen #include <sys/ldc.h> 5230588217SMike Christensen #include <sys/ds.h> 5330588217SMike Christensen #include <sys/ds_impl.h> 5430588217SMike Christensen #include <sys/vlds.h> 5530588217SMike Christensen #include <sys/bitmap.h> 5630588217SMike Christensen #include <sys/sysevent.h> 5730588217SMike Christensen 5830588217SMike Christensen static dev_info_t *vlds_devi; 5930588217SMike Christensen 6030588217SMike Christensen 6130588217SMike Christensen typedef struct vlds_state { 6230588217SMike Christensen dev_info_t *dip; 6330588217SMike Christensen int instance; 6430588217SMike Christensen evchan_t *evchan; 6530588217SMike Christensen } vlds_state_t; 6630588217SMike Christensen 6730588217SMike Christensen static void *vlds_statep; 6830588217SMike Christensen 6930588217SMike Christensen typedef struct vlds_recv_hdr { 7030588217SMike Christensen struct vlds_recv_hdr *next; /* next in recv list */ 7130588217SMike Christensen void *data; /* the data itself */ 7230588217SMike Christensen size_t datasz; /* size of the data */ 7330588217SMike Christensen } vlds_recv_hdr_t; 7430588217SMike Christensen 7530588217SMike Christensen typedef struct vlds_svc_info { 7630588217SMike Christensen int state; /* driver svc info state VLDS_RECV* */ 7730588217SMike Christensen vlds_recv_hdr_t *recv_headp; /* ptr to head of recv queue */ 7830588217SMike Christensen vlds_recv_hdr_t *recv_tailp; /* ptr to tail of recv queue */ 7930588217SMike Christensen size_t recv_size; /* no. of bytes in recv queue */ 80ba9236fbSMike Christensen uint_t recv_cnt; /* no of messages in recv queue */ 8130588217SMike Christensen kmutex_t recv_lock; /* lock for recv queue */ 8230588217SMike Christensen kcondvar_t recv_cv; /* condition variable for recv queue */ 8330588217SMike Christensen int recv_nreaders; /* no of currently waiting readers */ 8430588217SMike Christensen } vlds_svc_info_t; 8530588217SMike Christensen 8630588217SMike Christensen #define VLDS_RECV_OK 1 8730588217SMike Christensen #define VLDS_RECV_UNREG_PENDING 2 88ba9236fbSMike Christensen #define VLDS_RECV_OVERFLOW 3 8930588217SMike Christensen 9030588217SMike Christensen static int vlds_ports_inited = 0; 9130588217SMike Christensen 9230588217SMike Christensen static uint_t vlds_flags_to_svc(uint64_t flags); 9330588217SMike Christensen 9430588217SMike Christensen 9530588217SMike Christensen #define VLDS_NAME "vlds" 9630588217SMike Christensen static int vlds_open(dev_t *devp, int flag, int otyp, cred_t *credp); 9730588217SMike Christensen static int vlds_close(dev_t dev, int flag, int otyp, cred_t *credp); 9830588217SMike Christensen static int vlds_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 9930588217SMike Christensen int *rvalp); 10030588217SMike Christensen static int vlds_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 10130588217SMike Christensen void **resultp); 10230588217SMike Christensen static int vlds_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 10330588217SMike Christensen static int vlds_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 10430588217SMike Christensen 10530588217SMike Christensen /* mdeg register functions */ 106a600f50dSMike Christensen static void vlds_mdeg_init(void); 107a600f50dSMike Christensen static int vlds_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 108a600f50dSMike Christensen static int vlds_mdeg_register(void); 109a600f50dSMike Christensen static int vlds_mdeg_unregister(void); 110a600f50dSMike Christensen static int vlds_add_mdeg_port(md_t *mdp, mde_cookie_t node); 11130588217SMike Christensen 11230588217SMike Christensen /* driver utilities */ 11330588217SMike Christensen static void vlds_user_reg_cb(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl); 11430588217SMike Christensen static void vlds_user_unreg_cb(ds_cb_arg_t arg); 11530588217SMike Christensen static void vlds_user_data_cb(ds_cb_arg_t arg, void *buf, size_t buflen); 11630588217SMike Christensen static void vlds_recvq_init(vlds_svc_info_t *dpsp); 11730588217SMike Christensen static void vlds_recvq_destroy(vlds_svc_info_t *dpsp); 11830588217SMike Christensen static int vlds_recvq_get_data(vlds_svc_info_t *dpsp, void *buf, size_t buflen, 11930588217SMike Christensen size_t *msglenp, int mode); 12030588217SMike Christensen static void vlds_recvq_drain(vlds_svc_info_t *dpsp); 12130588217SMike Christensen static int vlds_recvq_put_data(vlds_svc_info_t *dpsp, void *buf, size_t buflen); 12230588217SMike Christensen static int vlds_recv_msg(ds_svc_hdl_t hdl, void *buf, size_t buflen, 12330588217SMike Christensen size_t *msglenp, int mode); 12430588217SMike Christensen 12530588217SMike Christensen /* 12630588217SMike Christensen * DS driver Ops Vector 12730588217SMike Christensen */ 12830588217SMike Christensen static struct cb_ops vlds_cb_ops = { 12930588217SMike Christensen vlds_open, /* cb_open */ 13030588217SMike Christensen vlds_close, /* cb_close */ 13130588217SMike Christensen nodev, /* cb_strategy */ 13230588217SMike Christensen nodev, /* cb_print */ 13330588217SMike Christensen nodev, /* cb_dump */ 13430588217SMike Christensen nodev, /* cb_read */ 13530588217SMike Christensen nodev, /* cb_write */ 13630588217SMike Christensen vlds_ioctl, /* cb_ioctl */ 13730588217SMike Christensen nodev, /* cb_devmap */ 13830588217SMike Christensen nodev, /* cb_mmap */ 13930588217SMike Christensen nodev, /* cb_segmap */ 14030588217SMike Christensen nochpoll, /* cb_chpoll */ 14130588217SMike Christensen ddi_prop_op, /* cb_prop_op */ 14230588217SMike Christensen (struct streamtab *)NULL, /* cb_str */ 14330588217SMike Christensen D_MP | D_64BIT, /* cb_flag */ 14430588217SMike Christensen CB_REV, /* cb_rev */ 14530588217SMike Christensen nodev, /* cb_aread */ 14630588217SMike Christensen nodev /* cb_awrite */ 14730588217SMike Christensen }; 14830588217SMike Christensen 14930588217SMike Christensen static struct dev_ops vlds_dev_ops = { 15030588217SMike Christensen DEVO_REV, /* devo_rev */ 15130588217SMike Christensen 0, /* devo_refcnt */ 15230588217SMike Christensen vlds_getinfo, /* devo_getinfo */ 15330588217SMike Christensen nulldev, /* devo_identify */ 15430588217SMike Christensen nulldev, /* devo_probe */ 15530588217SMike Christensen vlds_attach, /* devo_attach */ 15630588217SMike Christensen vlds_detach, /* devo_detach */ 15730588217SMike Christensen nodev, /* devo_reset */ 15830588217SMike Christensen &vlds_cb_ops, /* devo_cb_ops */ 15930588217SMike Christensen (struct bus_ops *)NULL, /* devo_bus_ops */ 16030588217SMike Christensen nulldev /* devo_power */ 16130588217SMike Christensen }; 16230588217SMike Christensen 16330588217SMike Christensen static struct modldrv modldrv = { 16430588217SMike Christensen &mod_driverops, 16530588217SMike Christensen "Domain Services Driver 1.0", 16630588217SMike Christensen &vlds_dev_ops 16730588217SMike Christensen }; 16830588217SMike Christensen 16930588217SMike Christensen static struct modlinkage modlinkage = { 17030588217SMike Christensen MODREV_1, 17130588217SMike Christensen (void *)&modldrv, 17230588217SMike Christensen NULL 17330588217SMike Christensen }; 17430588217SMike Christensen 17530588217SMike Christensen /* 17630588217SMike Christensen * Callback ops for user-land services. 17730588217SMike Christensen */ 17830588217SMike Christensen static ds_clnt_ops_t ds_user_ops = { 17930588217SMike Christensen vlds_user_reg_cb, /* register */ 18030588217SMike Christensen vlds_user_unreg_cb, /* unregister */ 18130588217SMike Christensen vlds_user_data_cb, /* data */ 18230588217SMike Christensen NULL /* ds_ucap_init will fill in */ 18330588217SMike Christensen }; 18430588217SMike Christensen 185ba9236fbSMike Christensen static size_t vlds_recvq_maxsize = DS_STREAM_MTU * 8; 186ba9236fbSMike Christensen static uint_t vlds_recvq_maxmsg = 16; 187ba9236fbSMike Christensen 18830588217SMike Christensen #define VLDS_MINOR_MAX SHRT_MAX 18930588217SMike Christensen 19030588217SMike Christensen /* Definitions for binding handle array */ 19130588217SMike Christensen static ulong_t vlds_bitmap_initial = 1; /* index 0 indicates error */ 19230588217SMike Christensen static ulong_t *vlds_minor_bitmap = &vlds_bitmap_initial; 19330588217SMike Christensen static size_t vlds_minor_bits = BT_NBIPUL; 19430588217SMike Christensen static kmutex_t vlds_minor_mutex; 19530588217SMike Christensen 19630588217SMike Christensen /* 19730588217SMike Christensen * Following vlds_minor_* routines map a binding handle to a minor number. 19830588217SMike Christensen * Has to be called w/ locks held. 19930588217SMike Christensen */ 20030588217SMike Christensen static ulong_t * 20130588217SMike Christensen vlds_minor_alloc(void) 20230588217SMike Christensen { 20330588217SMike Christensen ulong_t *bhst = vlds_minor_bitmap; 20430588217SMike Christensen 20530588217SMike Christensen /* Increase bitmap by one BT_NBIPUL */ 20630588217SMike Christensen if (vlds_minor_bits + BT_NBIPUL > VLDS_MINOR_MAX) { 20730588217SMike Christensen return ((ulong_t *)NULL); 20830588217SMike Christensen } 20930588217SMike Christensen vlds_minor_bitmap = kmem_zalloc( 21030588217SMike Christensen BT_SIZEOFMAP(vlds_minor_bits + BT_NBIPUL), KM_SLEEP); 21130588217SMike Christensen bcopy(bhst, vlds_minor_bitmap, BT_SIZEOFMAP(vlds_minor_bits)); 21230588217SMike Christensen if (bhst != &vlds_bitmap_initial) 21330588217SMike Christensen kmem_free(bhst, BT_SIZEOFMAP(vlds_minor_bits)); 21430588217SMike Christensen vlds_minor_bits += BT_NBIPUL; 21530588217SMike Christensen 21630588217SMike Christensen return (vlds_minor_bitmap); 21730588217SMike Christensen } 21830588217SMike Christensen 21930588217SMike Christensen static void 22030588217SMike Christensen vlds_minor_free(ulong_t *bitmap) 22130588217SMike Christensen { 22230588217SMike Christensen if (bitmap != &vlds_bitmap_initial) 22330588217SMike Christensen kmem_free(bitmap, BT_SIZEOFMAP(vlds_minor_bits)); 22430588217SMike Christensen } 22530588217SMike Christensen 22630588217SMike Christensen static index_t 22730588217SMike Christensen vlds_minor_get(void) 22830588217SMike Christensen { 22930588217SMike Christensen index_t idx; 23030588217SMike Christensen ulong_t *bhst; 23130588217SMike Christensen 23230588217SMike Christensen /* Search for an available index */ 23330588217SMike Christensen mutex_enter(&vlds_minor_mutex); 23430588217SMike Christensen if ((idx = bt_availbit(vlds_minor_bitmap, 23530588217SMike Christensen vlds_minor_bits)) == -1) { 23630588217SMike Christensen /* All busy - allocate additional binding handle bitmap space */ 23730588217SMike Christensen if ((bhst = vlds_minor_alloc()) == NULL) { 23830588217SMike Christensen /* Reached our maximum of id's == SHRT_MAX */ 23930588217SMike Christensen mutex_exit(&vlds_minor_mutex); 24030588217SMike Christensen return (0); 24130588217SMike Christensen } else { 24230588217SMike Christensen vlds_minor_bitmap = bhst; 24330588217SMike Christensen } 24430588217SMike Christensen idx = bt_availbit(vlds_minor_bitmap, vlds_minor_bits); 24530588217SMike Christensen } 24630588217SMike Christensen BT_SET(vlds_minor_bitmap, idx); 24730588217SMike Christensen mutex_exit(&vlds_minor_mutex); 24830588217SMike Christensen return (idx); 24930588217SMike Christensen } 25030588217SMike Christensen 25130588217SMike Christensen static void 25230588217SMike Christensen vlds_minor_rele(index_t idx) 25330588217SMike Christensen { 25430588217SMike Christensen mutex_enter(&vlds_minor_mutex); 25530588217SMike Christensen ASSERT(BT_TEST(vlds_minor_bitmap, idx) == 1); 25630588217SMike Christensen BT_CLEAR(vlds_minor_bitmap, idx); 25730588217SMike Christensen mutex_exit(&vlds_minor_mutex); 25830588217SMike Christensen } 25930588217SMike Christensen 26030588217SMike Christensen static void 26130588217SMike Christensen vlds_minor_init(void) 26230588217SMike Christensen { 26330588217SMike Christensen mutex_init(&vlds_minor_mutex, NULL, MUTEX_DEFAULT, NULL); 26430588217SMike Christensen } 26530588217SMike Christensen 26630588217SMike Christensen int 26730588217SMike Christensen _init(void) 26830588217SMike Christensen { 26930588217SMike Christensen int s; 27030588217SMike Christensen 27130588217SMike Christensen if ((s = ddi_soft_state_init(&vlds_statep, sizeof (vlds_state_t), 0)) 27230588217SMike Christensen != 0) 27330588217SMike Christensen return (s); 27430588217SMike Christensen 27530588217SMike Christensen if ((s = mod_install(&modlinkage)) != 0) { 27630588217SMike Christensen ddi_soft_state_fini(&vlds_statep); 27730588217SMike Christensen return (s); 27830588217SMike Christensen } 27930588217SMike Christensen 280a600f50dSMike Christensen vlds_mdeg_init(); 28130588217SMike Christensen 28230588217SMike Christensen return (s); 28330588217SMike Christensen } 28430588217SMike Christensen 28530588217SMike Christensen int 28630588217SMike Christensen _fini(void) 28730588217SMike Christensen { 28830588217SMike Christensen int s; 28930588217SMike Christensen 29030588217SMike Christensen if ((s = mod_remove(&modlinkage)) != 0) 29130588217SMike Christensen return (s); 29230588217SMike Christensen 29330588217SMike Christensen ddi_soft_state_fini(&vlds_statep); 29430588217SMike Christensen 29530588217SMike Christensen return (s); 29630588217SMike Christensen } 29730588217SMike Christensen 29830588217SMike Christensen int 29930588217SMike Christensen _info(struct modinfo *modinfop) 30030588217SMike Christensen { 30130588217SMike Christensen return (mod_info(&modlinkage, modinfop)); 30230588217SMike Christensen } 30330588217SMike Christensen 30430588217SMike Christensen 30530588217SMike Christensen 30630588217SMike Christensen /*ARGSUSED*/ 30730588217SMike Christensen static int 30830588217SMike Christensen vlds_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 30930588217SMike Christensen { 31030588217SMike Christensen switch (cmd) { 31130588217SMike Christensen case DDI_INFO_DEVT2DEVINFO: 31230588217SMike Christensen *resultp = vlds_devi; 31330588217SMike Christensen return (DDI_SUCCESS); 31430588217SMike Christensen case DDI_INFO_DEVT2INSTANCE: 31530588217SMike Christensen *resultp = 0; 31630588217SMike Christensen return (DDI_SUCCESS); 31730588217SMike Christensen } 31830588217SMike Christensen return (DDI_FAILURE); 31930588217SMike Christensen } 32030588217SMike Christensen 32130588217SMike Christensen 32230588217SMike Christensen static int 32330588217SMike Christensen vlds_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 32430588217SMike Christensen { 32530588217SMike Christensen if (cmd != DDI_ATTACH) { 32630588217SMike Christensen return (DDI_FAILURE); 32730588217SMike Christensen } 32830588217SMike Christensen 32930588217SMike Christensen if (ddi_create_minor_node(devi, VLDS_NAME, S_IFCHR, 33030588217SMike Christensen 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 33130588217SMike Christensen ddi_remove_minor_node(devi, NULL); 33230588217SMike Christensen return (DDI_FAILURE); 33330588217SMike Christensen } 33430588217SMike Christensen vlds_devi = devi; 33530588217SMike Christensen 33630588217SMike Christensen vlds_minor_init(); 33730588217SMike Christensen 338*af4c679fSSean McEnroe (void) vlds_mdeg_register(); 339*af4c679fSSean McEnroe 34030588217SMike Christensen return (DDI_SUCCESS); 34130588217SMike Christensen } 34230588217SMike Christensen 34330588217SMike Christensen 34430588217SMike Christensen /*ARGSUSED*/ 34530588217SMike Christensen static int 34630588217SMike Christensen vlds_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 34730588217SMike Christensen { 34830588217SMike Christensen if (cmd != DDI_DETACH) { 34930588217SMike Christensen return (DDI_FAILURE); 35030588217SMike Christensen } 35130588217SMike Christensen 35230588217SMike Christensen vlds_minor_free(vlds_minor_bitmap); 35330588217SMike Christensen ddi_remove_minor_node(devi, NULL); 354*af4c679fSSean McEnroe (void) vlds_mdeg_unregister(); 35530588217SMike Christensen return (DDI_SUCCESS); 35630588217SMike Christensen } 35730588217SMike Christensen 35830588217SMike Christensen 35930588217SMike Christensen /*ARGSUSED*/ 36030588217SMike Christensen static int 36130588217SMike Christensen vlds_open(dev_t *devp, int flag, int otyp, cred_t *credp) 36230588217SMike Christensen { 36330588217SMike Christensen int minor; 36430588217SMike Christensen 36530588217SMike Christensen if (otyp != OTYP_CHR) 36630588217SMike Christensen return (EINVAL); 36730588217SMike Christensen 36830588217SMike Christensen if (getminor(*devp) != 0) 36930588217SMike Christensen return (ENXIO); 37030588217SMike Christensen 37130588217SMike Christensen minor = vlds_minor_get(); 37230588217SMike Christensen if (minor == 0) 37330588217SMike Christensen /* All minors are busy */ 37430588217SMike Christensen return (EBUSY); 37530588217SMike Christensen 37630588217SMike Christensen if (ddi_soft_state_zalloc(vlds_statep, minor) != DDI_SUCCESS) { 37730588217SMike Christensen vlds_minor_rele(minor); 37830588217SMike Christensen return (ENOMEM); 37930588217SMike Christensen } 38030588217SMike Christensen 38130588217SMike Christensen *devp = makedevice(getmajor(*devp), minor); 38230588217SMike Christensen 38330588217SMike Christensen return (0); 38430588217SMike Christensen } 38530588217SMike Christensen 38630588217SMike Christensen 38730588217SMike Christensen /*ARGSUSED*/ 38830588217SMike Christensen static int 38930588217SMike Christensen vlds_close(dev_t dev, int flag, int otyp, cred_t *credp) 39030588217SMike Christensen { 39130588217SMike Christensen int minor = (int)getminor(dev); 39230588217SMike Christensen vlds_state_t *sp; 39330588217SMike Christensen 39430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "vlds_close"); 39530588217SMike Christensen 39630588217SMike Christensen /* 39730588217SMike Christensen * Unregister all handles associated with this process. 39830588217SMike Christensen */ 39930588217SMike Christensen ds_unreg_all(minor); 40030588217SMike Christensen 40130588217SMike Christensen if (otyp != OTYP_CHR) 40230588217SMike Christensen return (EINVAL); 40330588217SMike Christensen 40430588217SMike Christensen sp = ddi_get_soft_state(vlds_statep, minor); 40530588217SMike Christensen if (sp == NULL) { 40630588217SMike Christensen return (ENXIO); 40730588217SMike Christensen } 40830588217SMike Christensen 40930588217SMike Christensen if (sp->evchan) { 41049b225e1SGavin Maltby (void) sysevent_evc_unbind(sp->evchan); 41130588217SMike Christensen sp->evchan = NULL; 41230588217SMike Christensen } 41330588217SMike Christensen 41430588217SMike Christensen ddi_soft_state_free(vlds_statep, minor); 41530588217SMike Christensen vlds_minor_rele(minor); 41630588217SMike Christensen 41730588217SMike Christensen return (0); 41830588217SMike Christensen } 41930588217SMike Christensen 42030588217SMike Christensen int 42130588217SMike Christensen vlds_init_sysevent(vlds_state_t *sp, uint32_t flags) 42230588217SMike Christensen { 42330588217SMike Christensen char evchan_name[MAX_CHNAME_LEN]; 42430588217SMike Christensen int rv; 42530588217SMike Christensen 42630588217SMike Christensen if (flags & DSSF_ANYCB_VALID) { 42730588217SMike Christensen if (sp->evchan) { 42830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: sysevent already bound", 42930588217SMike Christensen __func__); 43030588217SMike Christensen return (0); 43130588217SMike Christensen } 43230588217SMike Christensen (void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, ddi_get_pid()); 43330588217SMike Christensen if ((rv = sysevent_evc_bind(evchan_name, &sp->evchan, 43430588217SMike Christensen EVCH_CREAT|EVCH_HOLD_PEND)) != 0) { 43530588217SMike Christensen cmn_err(CE_WARN, "%s: can't bind to '%s' (%d)", 43630588217SMike Christensen __func__, evchan_name, rv); 43730588217SMike Christensen return (rv); 43830588217SMike Christensen } 43930588217SMike Christensen 44030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: sysevent bind to '%s' successful", 44130588217SMike Christensen __func__, evchan_name); 44230588217SMike Christensen } 44330588217SMike Christensen return (0); 44430588217SMike Christensen } 44530588217SMike Christensen 44630588217SMike Christensen #define ARGTOPTR(x) ((void *)((uintptr_t)(x))) 44730588217SMike Christensen #define ARGTOUINT(x) ((uint_t)(x)) 44830588217SMike Christensen #define ARGTOINT(x) ((int)(x)) 44930588217SMike Christensen 45030588217SMike Christensen static int 45130588217SMike Christensen vlds_get_string(vlds_string_t *strp, char **rstrp, int mode) 45230588217SMike Christensen { 45330588217SMike Christensen char *str; 45430588217SMike Christensen uint_t len = strp->vlds_strlen; 45530588217SMike Christensen uint_t slen; 45630588217SMike Christensen 45730588217SMike Christensen if (len == 0) { 45830588217SMike Christensen *rstrp = NULL; 45930588217SMike Christensen return (0); 46030588217SMike Christensen } 46130588217SMike Christensen if (len > MAXNAMELEN) { 46230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: invalid string length: %d", __func__, 46330588217SMike Christensen len); 46430588217SMike Christensen return (EINVAL); 46530588217SMike Christensen } 46630588217SMike Christensen str = DS_MALLOC(len); 46730588217SMike Christensen if (ddi_copyin(ARGTOPTR(strp->vlds_strp), str, len, mode) != 0) { 46830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: ddi copyin failed (%p)", __func__, 46930588217SMike Christensen ARGTOPTR(strp->vlds_strp)); 47030588217SMike Christensen DS_FREE(str, len); 47130588217SMike Christensen return (EFAULT); 47230588217SMike Christensen } 47330588217SMike Christensen slen = strlen(str) + 1; 47430588217SMike Christensen if (slen != len) { 47530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: invalid string len: %d != len: %d", 47630588217SMike Christensen __func__, slen, len); 47730588217SMike Christensen DS_FREE(str, len); 47830588217SMike Christensen return (EINVAL); 47930588217SMike Christensen } 48030588217SMike Christensen *rstrp = str; 48130588217SMike Christensen return (0); 48230588217SMike Christensen } 48330588217SMike Christensen 48430588217SMike Christensen static int 48530588217SMike Christensen vlds_put_string(char *str, vlds_string_t *strp, int mode) 48630588217SMike Christensen { 48730588217SMike Christensen uint_t len; 48830588217SMike Christensen char *tstr = NULL; 48930588217SMike Christensen int rv; 49030588217SMike Christensen 49130588217SMike Christensen if (str == NULL) { 49230588217SMike Christensen str = ""; 49330588217SMike Christensen } 49430588217SMike Christensen len = strlen(str) + 1; 49530588217SMike Christensen 49630588217SMike Christensen /* 49730588217SMike Christensen * If string is longer than user buffer, return a 49830588217SMike Christensen * truncated, null-terminated string. 49930588217SMike Christensen */ 50030588217SMike Christensen if (len > strp->vlds_strlen) { 50130588217SMike Christensen len = strp->vlds_strlen; 50230588217SMike Christensen if (len > 0) { 50330588217SMike Christensen tstr = DS_MALLOC(len); 50430588217SMike Christensen (void) memcpy(tstr, str, len - 1); 50530588217SMike Christensen tstr[len - 1] = '\0'; 50630588217SMike Christensen str = tstr; 50730588217SMike Christensen } 50830588217SMike Christensen } 50930588217SMike Christensen rv = ddi_copyout(str, ARGTOPTR(strp->vlds_strp), len, mode); 51030588217SMike Christensen if (tstr) { 51130588217SMike Christensen DS_FREE(tstr, len); 51230588217SMike Christensen } 51330588217SMike Christensen if (rv) { 51430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: copyout (%p) failed", __func__, 51530588217SMike Christensen ARGTOPTR(strp->vlds_strp)); 51630588217SMike Christensen return (EFAULT); 51730588217SMike Christensen } 51830588217SMike Christensen return (0); 51930588217SMike Christensen } 52030588217SMike Christensen 52130588217SMike Christensen static int 52230588217SMike Christensen vlds_get_ucap(vlds_cap_t *capp, ds_capability_t *ucap, int mode) 52330588217SMike Christensen { 52430588217SMike Christensen char *servp; 52530588217SMike Christensen vlds_ver_t *dsvp; 52630588217SMike Christensen vlds_cap_t vlds_cap; 52730588217SMike Christensen uint_t n; 52830588217SMike Christensen uint_t nver; 52930588217SMike Christensen int i; 53030588217SMike Christensen int rv; 53130588217SMike Christensen 53230588217SMike Christensen if (ddi_copyin(capp, &vlds_cap, sizeof (vlds_cap), mode) != 0) { 53330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: cap copyin failed (%p)", __func__, 53430588217SMike Christensen (void *)capp); 53530588217SMike Christensen return (EFAULT); 53630588217SMike Christensen } 53730588217SMike Christensen 53830588217SMike Christensen nver = ARGTOUINT(vlds_cap.vlds_nver); 53930588217SMike Christensen 54030588217SMike Christensen if (nver > VLDS_MAX_VERS) { 54130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: vlds_nver (%d) invalid", __func__, 54230588217SMike Christensen nver); 54330588217SMike Christensen return (EINVAL); 54430588217SMike Christensen } 54530588217SMike Christensen 54630588217SMike Christensen if ((rv = vlds_get_string(&vlds_cap.vlds_service, &servp, mode)) != 0) { 54730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: vlds_get_string vlds_service failed " 54830588217SMike Christensen "(%d)", __func__, rv); 54930588217SMike Christensen return (rv); 55030588217SMike Christensen } else if (servp == NULL) { 55130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: vlds_get_string vlds_service is NULL", 55230588217SMike Christensen __func__); 55330588217SMike Christensen return (EINVAL); 55430588217SMike Christensen } 55530588217SMike Christensen 55630588217SMike Christensen n = nver * sizeof (vlds_ver_t); 55730588217SMike Christensen dsvp = DS_MALLOC(n); 55830588217SMike Christensen 55930588217SMike Christensen if (ddi_copyin(ARGTOPTR(vlds_cap.vlds_versp), dsvp, n, mode) != 0) { 56030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: copyin of vers (%p, %d) failed", 56130588217SMike Christensen __func__, ARGTOPTR(vlds_cap.vlds_versp), n); 56230588217SMike Christensen DS_FREE(servp, strlen(servp) + 1); 56330588217SMike Christensen DS_FREE(dsvp, n); 56430588217SMike Christensen return (EFAULT); 56530588217SMike Christensen } 56630588217SMike Christensen 56730588217SMike Christensen ucap->svc_id = servp; 56830588217SMike Christensen ucap->vers = DS_MALLOC(nver * sizeof (ds_ver_t)); 56930588217SMike Christensen for (i = 0; i < nver; i++) { 57030588217SMike Christensen ucap->vers[i].major = dsvp[i].vlds_major; 57130588217SMike Christensen ucap->vers[i].minor = dsvp[i].vlds_minor; 57230588217SMike Christensen } 57330588217SMike Christensen ucap->nvers = nver; 57430588217SMike Christensen DS_FREE(dsvp, n); 57530588217SMike Christensen return (0); 57630588217SMike Christensen } 57730588217SMike Christensen 57830588217SMike Christensen static void 57930588217SMike Christensen vlds_free_ucap(ds_capability_t *ucap) 58030588217SMike Christensen { 58130588217SMike Christensen kmem_free(ucap->svc_id, strlen(ucap->svc_id) + 1); 58230588217SMike Christensen kmem_free(ucap->vers, ucap->nvers * sizeof (ds_ver_t)); 58330588217SMike Christensen } 58430588217SMike Christensen 58530588217SMike Christensen /*ARGSUSED*/ 58630588217SMike Christensen static int 58730588217SMike Christensen vlds_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 58830588217SMike Christensen int *rvalp) 58930588217SMike Christensen { 59030588217SMike Christensen vlds_state_t *sp; 59130588217SMike Christensen ds_svc_hdl_t hdl; 59230588217SMike Christensen ds_domain_hdl_t dhdl; 59330588217SMike Christensen char *servicep; 59430588217SMike Christensen int rv; 59530588217SMike Christensen int minor = (int)getminor(dev); 59630588217SMike Christensen 59730588217SMike Christensen if ((sp = ddi_get_soft_state(vlds_statep, minor)) == NULL) 59830588217SMike Christensen return (ENXIO); 59930588217SMike Christensen 60030588217SMike Christensen switch (cmd) { 60130588217SMike Christensen 60230588217SMike Christensen case VLDS_SVC_REG: 60330588217SMike Christensen { 60430588217SMike Christensen vlds_svc_reg_arg_t vlds_arg; 60530588217SMike Christensen ds_capability_t ucap; 60630588217SMike Christensen uint64_t hdl_arg; 60730588217SMike Christensen uint_t flags; 60830588217SMike Christensen 60930588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 61030588217SMike Christensen mode) != 0) { 61130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SVC REG arg copyin failed", 61230588217SMike Christensen __func__); 61330588217SMike Christensen return (EFAULT); 61430588217SMike Christensen } 61530588217SMike Christensen 61630588217SMike Christensen if ((rv = vlds_get_ucap(ARGTOPTR(vlds_arg.vlds_capp), &ucap, 61730588217SMike Christensen mode)) != 0) { 61830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SVC REG get_ucap failed (%d)", 61930588217SMike Christensen __func__, rv); 62030588217SMike Christensen return (rv); 62130588217SMike Christensen } 62230588217SMike Christensen 62330588217SMike Christensen flags = vlds_flags_to_svc(vlds_arg.vlds_reg_flags); 62430588217SMike Christensen if ((rv = vlds_init_sysevent(sp, flags)) != 0) { 62530588217SMike Christensen vlds_free_ucap(&ucap); 62630588217SMike Christensen return (rv); 62730588217SMike Christensen } 62830588217SMike Christensen 62930588217SMike Christensen rv = ds_ucap_init(&ucap, &ds_user_ops, 63030588217SMike Christensen vlds_flags_to_svc(vlds_arg.vlds_reg_flags) | DSSF_ISUSER, 63130588217SMike Christensen minor, &hdl); 63230588217SMike Christensen 63330588217SMike Christensen vlds_free_ucap(&ucap); 63430588217SMike Christensen 63530588217SMike Christensen if (rv) { 63630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SVC REG ds_ucap_init failed " 63730588217SMike Christensen "(%d)", __func__, rv); 63830588217SMike Christensen return (rv); 63930588217SMike Christensen } 64030588217SMike Christensen 64130588217SMike Christensen hdl_arg = hdl; 64230588217SMike Christensen if (ddi_copyout(&hdl_arg, ARGTOPTR(vlds_arg.vlds_hdlp), 64330588217SMike Christensen sizeof (hdl_arg), mode) != 0) { 64430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SVC REG copyout failed", 64530588217SMike Christensen __func__); 64630588217SMike Christensen return (EFAULT); 64730588217SMike Christensen } 64830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SVC REG succeeded: hdl: %lx", 64930588217SMike Christensen __func__, hdl); 65030588217SMike Christensen break; 65130588217SMike Christensen } 65230588217SMike Christensen 65330588217SMike Christensen case VLDS_UNREG_HDL: 65430588217SMike Christensen { 65530588217SMike Christensen vlds_unreg_hdl_arg_t vlds_arg; 65630588217SMike Christensen 65730588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 65830588217SMike Christensen mode) != 0) { 65930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: UNREG_HDL arg copyin failed", 66030588217SMike Christensen __func__); 66130588217SMike Christensen return (EFAULT); 66230588217SMike Christensen } 66330588217SMike Christensen 66430588217SMike Christensen hdl = vlds_arg.vlds_hdl; 66530588217SMike Christensen 66630588217SMike Christensen if ((rv = ds_is_my_hdl(hdl, minor)) != 0) { 66730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: UNREG_HDL ds_is_my_hdl " 66830588217SMike Christensen " hdl: %lx inst: %d failed (%d)", __func__, 66930588217SMike Christensen hdl, rv, minor); 67030588217SMike Christensen return (rv); 67130588217SMike Christensen } 67230588217SMike Christensen 67330588217SMike Christensen if ((rv = ds_unreg_hdl(hdl)) != 0) { 67430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: UNREG_HDL ds_cap_unreg " 67530588217SMike Christensen " hdl: %lx failed (%d)", __func__, hdl, rv); 67630588217SMike Christensen return (rv); 67730588217SMike Christensen } 67830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: UNREG_HDL hdl: %lx succeeded", 67930588217SMike Christensen __func__, hdl); 68030588217SMike Christensen break; 68130588217SMike Christensen } 68230588217SMike Christensen 68330588217SMike Christensen case VLDS_HDL_LOOKUP: 68430588217SMike Christensen { 68530588217SMike Christensen vlds_hdl_lookup_arg_t vlds_arg; 68630588217SMike Christensen ds_svc_hdl_t *hdlsp; 68730588217SMike Christensen uint_t is_client, maxhdls, nhdls; 68830588217SMike Christensen uint64_t nhdls_arg; 68930588217SMike Christensen 69030588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 69130588217SMike Christensen mode) != 0) { 69230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP arg copyin failed", 69330588217SMike Christensen __func__); 69430588217SMike Christensen return (EFAULT); 69530588217SMike Christensen } 69630588217SMike Christensen 69730588217SMike Christensen is_client = ARGTOUINT(vlds_arg.vlds_isclient); 69830588217SMike Christensen maxhdls = ARGTOUINT(vlds_arg.vlds_maxhdls); 69930588217SMike Christensen if (maxhdls == 0) { 70030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP invalid maxhdls " 70130588217SMike Christensen "%d", __func__, maxhdls); 70230588217SMike Christensen return (EINVAL); 70330588217SMike Christensen } 70430588217SMike Christensen 70530588217SMike Christensen if ((rv = vlds_get_string(&vlds_arg.vlds_service, &servicep, 70630588217SMike Christensen mode)) != 0) { 70730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP vlds_get_string " 70830588217SMike Christensen "(service) failed (%d)", __func__, rv); 70930588217SMike Christensen return (EFAULT); 71030588217SMike Christensen } else if (servicep == NULL) { 71130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP vlds_get_string " 71230588217SMike Christensen " service is NULL", __func__); 71330588217SMike Christensen return (EINVAL); 71430588217SMike Christensen } 71530588217SMike Christensen 71630588217SMike Christensen if (ARGTOPTR(vlds_arg.vlds_hdlsp) == 0) { 71730588217SMike Christensen hdlsp = NULL; 71830588217SMike Christensen } else { 71930588217SMike Christensen hdlsp = DS_MALLOC(maxhdls * sizeof (*hdlsp)); 72030588217SMike Christensen } 72130588217SMike Christensen 72230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP (%s, %d) entered", 72330588217SMike Christensen __func__, servicep, is_client); 72430588217SMike Christensen rv = ds_hdl_lookup(servicep, is_client, hdlsp, maxhdls, &nhdls); 72530588217SMike Christensen 72630588217SMike Christensen DS_FREE(servicep, strlen(servicep) + 1); 72730588217SMike Christensen if (rv) { 72830588217SMike Christensen if (hdlsp) { 72930588217SMike Christensen DS_FREE(hdlsp, maxhdls * sizeof (*hdlsp)); 73030588217SMike Christensen } 73130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP failed: (%d)", 73230588217SMike Christensen __func__, rv); 73330588217SMike Christensen return (rv); 73430588217SMike Christensen } 73530588217SMike Christensen 73630588217SMike Christensen if (hdlsp != NULL && nhdls > 0 && 73730588217SMike Christensen ddi_copyout(hdlsp, ARGTOPTR(vlds_arg.vlds_hdlsp), 73830588217SMike Christensen nhdls * sizeof (ds_svc_hdl_t), mode) != 0) { 73930588217SMike Christensen if (hdlsp) { 74030588217SMike Christensen DS_FREE(hdlsp, maxhdls * sizeof (*hdlsp)); 74130588217SMike Christensen } 74230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP copyout of hdls " 74330588217SMike Christensen " failed", __func__); 74430588217SMike Christensen return (EFAULT); 74530588217SMike Christensen } 74630588217SMike Christensen if (hdlsp) { 74730588217SMike Christensen DS_FREE(hdlsp, maxhdls * sizeof (*hdlsp)); 74830588217SMike Christensen } 74930588217SMike Christensen 75030588217SMike Christensen nhdls_arg = nhdls; 75130588217SMike Christensen if (ddi_copyout(&nhdls_arg, ARGTOPTR(vlds_arg.vlds_nhdlsp), 75230588217SMike Christensen sizeof (nhdls_arg), mode) != 0) { 75330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP copyout of nhdls " 75430588217SMike Christensen " failed", __func__); 75530588217SMike Christensen return (EFAULT); 75630588217SMike Christensen } 75730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_LOOKUP succeeded: nhdls: %d", 75830588217SMike Christensen __func__, nhdls); 75930588217SMike Christensen break; 76030588217SMike Christensen } 76130588217SMike Christensen 76230588217SMike Christensen case VLDS_DMN_LOOKUP: 76330588217SMike Christensen { 76430588217SMike Christensen vlds_dmn_lookup_arg_t vlds_arg; 76530588217SMike Christensen uint64_t dhdl_arg; 76630588217SMike Christensen 76730588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 76830588217SMike Christensen mode) != 0) { 76930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DMN_LOOKUP arg copyin failed", 77030588217SMike Christensen __func__); 77130588217SMike Christensen return (EFAULT); 77230588217SMike Christensen } 77330588217SMike Christensen 77430588217SMike Christensen hdl = vlds_arg.vlds_hdl; 77530588217SMike Christensen 77630588217SMike Christensen if ((rv = ds_domain_lookup(hdl, &dhdl)) != 0) { 77730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DMN_LOOKUP lookup hdl: 0x%lx " 77830588217SMike Christensen "failed (%d)", __func__, hdl, rv); 77930588217SMike Christensen return (rv); 78030588217SMike Christensen } 78130588217SMike Christensen 78230588217SMike Christensen dhdl_arg = dhdl; 78330588217SMike Christensen 78430588217SMike Christensen if (ddi_copyout(&dhdl_arg, ARGTOPTR(vlds_arg.vlds_dhdlp), 78530588217SMike Christensen sizeof (dhdl_arg), mode) != 0) { 78630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DMN_LOOKUP copyout " 78730588217SMike Christensen "failed (%d)", __func__, rv); 78830588217SMike Christensen return (rv); 78930588217SMike Christensen } 79030588217SMike Christensen 79130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DMN_LOOKUP hdl: 0x%lx, dhdl: 0x%lx " 79230588217SMike Christensen "succeeded", __func__, hdl, dhdl); 79330588217SMike Christensen break; 79430588217SMike Christensen } 79530588217SMike Christensen 79630588217SMike Christensen case VLDS_SEND_MSG: 79730588217SMike Christensen { 79830588217SMike Christensen vlds_send_msg_arg_t vlds_arg; 79930588217SMike Christensen size_t buflen; 80030588217SMike Christensen char *bufp; 80130588217SMike Christensen 80230588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 80330588217SMike Christensen mode) != 0) { 80430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG arg copyin failed", 80530588217SMike Christensen __func__); 80630588217SMike Christensen return (EFAULT); 80730588217SMike Christensen } 80830588217SMike Christensen 80930588217SMike Christensen hdl = vlds_arg.vlds_hdl; 81030588217SMike Christensen if ((rv = ds_is_my_hdl(hdl, minor)) != 0) { 81130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG ds_is_my_hdl " 81230588217SMike Christensen " hdl: %lx inst: %d failed (%d)", __func__, 81330588217SMike Christensen hdl, rv, minor); 81430588217SMike Christensen return (rv); 81530588217SMike Christensen } 81630588217SMike Christensen 81730588217SMike Christensen buflen = ARGTOUINT(vlds_arg.vlds_buflen); 81830588217SMike Christensen bufp = DS_MALLOC(buflen); 81930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG (hdl: %lx, bufp: %p, " 82030588217SMike Christensen "buflen: %ld", __func__, hdl, ARGTOPTR(vlds_arg.vlds_bufp), 82130588217SMike Christensen buflen); 82230588217SMike Christensen 82330588217SMike Christensen if (ddi_copyin(ARGTOPTR(vlds_arg.vlds_bufp), bufp, buflen, 82430588217SMike Christensen mode) != 0) { 82530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG buf (%p, %ld) " 82630588217SMike Christensen "copyin failed", __func__, 82730588217SMike Christensen ARGTOPTR(vlds_arg.vlds_bufp), buflen); 82830588217SMike Christensen DS_FREE(bufp, buflen); 82930588217SMike Christensen return (EFAULT); 83030588217SMike Christensen } 83130588217SMike Christensen 83230588217SMike Christensen if ((rv = ds_cap_send(hdl, bufp, buflen)) != 0) { 83330588217SMike Christensen DS_FREE(bufp, buflen); 83430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG ds_cap_send failed " 83530588217SMike Christensen "(%d)", __func__, rv); 83630588217SMike Christensen return (rv); 83730588217SMike Christensen } 83830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: SEND_MSG hdl: %lx, bufp: %p, " 83930588217SMike Christensen "buflen: %ld succeeded", __func__, hdl, (void *)bufp, 84030588217SMike Christensen buflen); 84130588217SMike Christensen DS_DUMP_MSG(DS_DBG_FLAG_VLDS, bufp, buflen); 84230588217SMike Christensen DS_FREE(bufp, buflen); 84330588217SMike Christensen break; 84430588217SMike Christensen } 84530588217SMike Christensen 84630588217SMike Christensen case VLDS_RECV_MSG: 84730588217SMike Christensen { 84830588217SMike Christensen vlds_recv_msg_arg_t vlds_arg; 84930588217SMike Christensen size_t buflen, msglen; 85030588217SMike Christensen uint64_t msglen_arg; 85130588217SMike Christensen 85230588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 85330588217SMike Christensen mode) != 0) { 85430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: RECV_MSG arg copyin failed", 85530588217SMike Christensen __func__); 85630588217SMike Christensen return (EFAULT); 85730588217SMike Christensen } 85830588217SMike Christensen 85930588217SMike Christensen hdl = vlds_arg.vlds_hdl; 86030588217SMike Christensen if ((rv = ds_is_my_hdl(hdl, minor)) != 0) { 86130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: RECV_MSG ds_is_my_hdl " 86230588217SMike Christensen " hdl: %lx inst: %d failed (%d)", __func__, 86330588217SMike Christensen hdl, rv, minor); 86430588217SMike Christensen return (rv); 86530588217SMike Christensen } 86630588217SMike Christensen 86730588217SMike Christensen buflen = ARGTOUINT(vlds_arg.vlds_buflen); 86830588217SMike Christensen 86930588217SMike Christensen if ((rv = vlds_recv_msg(hdl, ARGTOPTR(vlds_arg.vlds_bufp), 87030588217SMike Christensen buflen, &msglen, mode)) != 0 && rv != EFBIG) { 87130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: RECV_MSG vlds_recv_msg " 87230588217SMike Christensen " failed (%d)", __func__, rv); 87330588217SMike Christensen return (rv); 87430588217SMike Christensen } 87530588217SMike Christensen 87630588217SMike Christensen msglen_arg = msglen; 87730588217SMike Christensen if (ddi_copyout(&msglen_arg, ARGTOPTR(vlds_arg.vlds_msglenp), 87830588217SMike Christensen sizeof (msglen_arg), mode) != 0) { 87930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: RECV_MSG copyout of msglen " 88030588217SMike Christensen "failed", __func__); 88130588217SMike Christensen return (EFAULT); 88230588217SMike Christensen } 88330588217SMike Christensen 88430588217SMike Christensen if (rv == EFBIG) { 88530588217SMike Christensen return (EFBIG); 88630588217SMike Christensen } 88730588217SMike Christensen 88830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: RECV_MSG hdl: %lx, " 88930588217SMike Christensen "msglen: %ld succeeded", __func__, hdl, buflen); 89030588217SMike Christensen break; 89130588217SMike Christensen } 89230588217SMike Christensen 89330588217SMike Christensen case VLDS_HDL_ISREADY: 89430588217SMike Christensen { 89530588217SMike Christensen vlds_hdl_isready_arg_t vlds_arg; 89630588217SMike Christensen ds_svc_hdl_t hdl; 89730588217SMike Christensen uint64_t is_ready_arg; 89830588217SMike Christensen uint_t is_ready; 89930588217SMike Christensen 90030588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 90130588217SMike Christensen mode) != 0) { 90230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_ISREADY arg copyin " 90330588217SMike Christensen "failed", __func__); 90430588217SMike Christensen return (EFAULT); 90530588217SMike Christensen } 90630588217SMike Christensen 90730588217SMike Christensen hdl = vlds_arg.vlds_hdl; 90830588217SMike Christensen if ((rv = ds_hdl_isready(hdl, &is_ready)) != 0) { 90930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_ISREADY ds_hdl_isready " 91030588217SMike Christensen "error (%d)", __func__, rv); 91130588217SMike Christensen return (rv); 91230588217SMike Christensen } 91330588217SMike Christensen 91430588217SMike Christensen is_ready_arg = is_ready; 91530588217SMike Christensen if (ddi_copyout(&is_ready_arg, ARGTOPTR(vlds_arg.vlds_isreadyp), 91630588217SMike Christensen sizeof (is_ready_arg), mode) != 0) { 91730588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_ISREADY copyout of " 91830588217SMike Christensen "vlds_isready failed", __func__); 91930588217SMike Christensen return (EFAULT); 92030588217SMike Christensen } 92130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: HDL_ISREADY succeeded hdl: %lx, " 92230588217SMike Christensen "is_ready: %d", __func__, hdl, is_ready); 92330588217SMike Christensen break; 92430588217SMike Christensen } 92530588217SMike Christensen 92630588217SMike Christensen case VLDS_DOM_NAM2HDL: 92730588217SMike Christensen { 92830588217SMike Christensen vlds_dom_nam2hdl_arg_t vlds_arg; 92930588217SMike Christensen char *domain_name; 93030588217SMike Christensen uint64_t dhdl_arg; 93130588217SMike Christensen ds_domain_hdl_t dhdl; 93230588217SMike Christensen 93330588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 93430588217SMike Christensen mode) != 0) { 93530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL arg copyin " 93630588217SMike Christensen "failed", __func__); 93730588217SMike Christensen return (EFAULT); 93830588217SMike Christensen } 93930588217SMike Christensen 94030588217SMike Christensen if ((rv = vlds_get_string(&vlds_arg.vlds_domain_name, 94130588217SMike Christensen &domain_name, mode)) != 0) { 94230588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL vlds_get_string " 94330588217SMike Christensen "domain_name failed (%d)", __func__, rv); 94430588217SMike Christensen return (EFAULT); 94530588217SMike Christensen } else if (servicep == NULL) { 94630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL vlds_get_string " 94730588217SMike Christensen " domain_name is NULL", __func__); 94830588217SMike Christensen return (EINVAL); 94930588217SMike Christensen } 95030588217SMike Christensen 95130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL (%s) entered", __func__, 95230588217SMike Christensen domain_name); 95330588217SMike Christensen 95430588217SMike Christensen if ((rv = ds_dom_name_to_hdl(domain_name, &dhdl)) != 0) { 95530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL name: '%s' " 95630588217SMike Christensen "failed: (%d)", __func__, domain_name, rv); 95730588217SMike Christensen DS_FREE(domain_name, strlen(domain_name) + 1); 95830588217SMike Christensen return (rv); 95930588217SMike Christensen } 96030588217SMike Christensen 96130588217SMike Christensen dhdl_arg = dhdl; 96230588217SMike Christensen if (ddi_copyout(&dhdl_arg, ARGTOPTR(vlds_arg.vlds_dhdlp), 96330588217SMike Christensen sizeof (dhdl_arg), mode) != 0) { 96430588217SMike Christensen DS_FREE(domain_name, strlen(domain_name) + 1); 96530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL copyout of dhdl " 96630588217SMike Christensen " failed", __func__); 96730588217SMike Christensen return (EFAULT); 96830588217SMike Christensen } 96930588217SMike Christensen 97030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_NAM2HDL succeeded: name: '%s', " 97130588217SMike Christensen "dhdl: 0x%lx", __func__, domain_name, dhdl); 97230588217SMike Christensen DS_FREE(domain_name, strlen(domain_name) + 1); 97330588217SMike Christensen break; 97430588217SMike Christensen } 97530588217SMike Christensen 97630588217SMike Christensen case VLDS_DOM_HDL2NAM: 97730588217SMike Christensen { 97830588217SMike Christensen vlds_dom_hdl2nam_arg_t vlds_arg; 97930588217SMike Christensen ds_domain_hdl_t dhdl; 98030588217SMike Christensen char *domain_name; 98130588217SMike Christensen 98230588217SMike Christensen if (ddi_copyin((void *)arg, &vlds_arg, sizeof (vlds_arg), 98330588217SMike Christensen mode) != 0) { 98430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_HDL2NAM arg copyin " 98530588217SMike Christensen "failed", __func__); 98630588217SMike Christensen return (EFAULT); 98730588217SMike Christensen } 98830588217SMike Christensen 98930588217SMike Christensen dhdl = vlds_arg.vlds_dhdl; 990a600f50dSMike Christensen if ((rv = ds_dom_hdl_to_name(dhdl, &domain_name)) != 0) { 99130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_HDL2NAM lookup dhdl: %lx " 99230588217SMike Christensen "failed (%d)", __func__, dhdl, rv); 99330588217SMike Christensen return (rv); 99430588217SMike Christensen } 99530588217SMike Christensen 99630588217SMike Christensen if ((rv = vlds_put_string(domain_name, 99730588217SMike Christensen &vlds_arg.vlds_domain_name, mode)) != 0) { 99830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_HDL2NAM vlds_put_string " 99930588217SMike Christensen "'%s' failed (%d)", __func__, domain_name, rv); 100030588217SMike Christensen return (rv); 100130588217SMike Christensen } 100230588217SMike Christensen 100330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: DOM_HDL2NAM dhdl: 0x%lx name: '%s'", 100430588217SMike Christensen __func__, dhdl, domain_name); 100530588217SMike Christensen break; 100630588217SMike Christensen } 100730588217SMike Christensen 100830588217SMike Christensen default: 100930588217SMike Christensen return (EINVAL); 101030588217SMike Christensen } 101130588217SMike Christensen return (0); 101230588217SMike Christensen } 101330588217SMike Christensen 101430588217SMike Christensen static uint_t 101530588217SMike Christensen vlds_flags_to_svc(uint64_t flags) 101630588217SMike Christensen { 101730588217SMike Christensen uint_t sflags = 0; 101830588217SMike Christensen 101930588217SMike Christensen if (flags & VLDS_REG_CLIENT) 102030588217SMike Christensen sflags |= DSSF_ISCLIENT; 102130588217SMike Christensen if (flags & VLDS_REGCB_VALID) 102230588217SMike Christensen sflags |= DSSF_REGCB_VALID; 102330588217SMike Christensen if (flags & VLDS_UNREGCB_VALID) 102430588217SMike Christensen sflags |= DSSF_UNREGCB_VALID; 102530588217SMike Christensen if (flags & VLDS_DATACB_VALID) 102630588217SMike Christensen sflags |= DSSF_DATACB_VALID; 102730588217SMike Christensen return (sflags); 102830588217SMike Christensen } 102930588217SMike Christensen 103030588217SMike Christensen /* 103130588217SMike Christensen * MD registration code. 103230588217SMike Christensen * Placed in vlds rather than ds module due to cirular dependency of 103330588217SMike Christensen * platsvc module which contains the mdeg code. 103430588217SMike Christensen */ 1035a600f50dSMike Christensen mdeg_handle_t vlds_mdeg_hdl; 103630588217SMike Christensen 103730588217SMike Christensen /* 1038a600f50dSMike Christensen * Look for "virtual-device-service" node among the 1039a600f50dSMike Christensen * "virtual-device" nodes. 104030588217SMike Christensen */ 1041a600f50dSMike Christensen static mdeg_prop_spec_t vlds_prop_template[] = { 1042a600f50dSMike Christensen { MDET_PROP_STR, "name", VLDS_MD_VIRT_ROOT_NAME }, 104330588217SMike Christensen { MDET_LIST_END, NULL, NULL } 104430588217SMike Christensen }; 104530588217SMike Christensen 1046a600f50dSMike Christensen static mdeg_node_spec_t vlds_node_template = 1047a600f50dSMike Christensen { VLDS_MD_VIRT_DEV_NAME, vlds_prop_template }; 104830588217SMike Christensen 104930588217SMike Christensen /* 105030588217SMike Christensen * Matching criteria passed to the MDEG to register interest 105130588217SMike Christensen * in changes to domain services port nodes identified by their 105230588217SMike Christensen * 'id' property. 105330588217SMike Christensen */ 1054a600f50dSMike Christensen static md_prop_match_t vlds_port_prop_match[] = { 105530588217SMike Christensen { MDET_PROP_VAL, "id" }, 105630588217SMike Christensen { MDET_LIST_END, NULL } 105730588217SMike Christensen }; 105830588217SMike Christensen 1059a600f50dSMike Christensen static mdeg_node_match_t vlds_port_match = { VLDS_MD_VIRT_PORT_NAME, 1060a600f50dSMike Christensen vlds_port_prop_match }; 106130588217SMike Christensen 106230588217SMike Christensen /* mdeg callback */ 106330588217SMike Christensen static int 1064a600f50dSMike Christensen vlds_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 106530588217SMike Christensen { 106630588217SMike Christensen _NOTE(ARGUNUSED(cb_argp)) 106730588217SMike Christensen int idx; 106830588217SMike Christensen uint64_t portno; 106930588217SMike Christensen int rv; 107030588217SMike Christensen md_t *mdp; 107130588217SMike Christensen mde_cookie_t node; 107230588217SMike Christensen 107330588217SMike Christensen if (resp == NULL) { 1074a600f50dSMike Christensen DS_DBG_VLDS(CE_NOTE, "vlds_mdeg_cb: no result returned"); 107530588217SMike Christensen return (MDEG_FAILURE); 107630588217SMike Christensen } 107730588217SMike Christensen 107830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: added=%d, removed=%d, matched=%d", __func__, 107930588217SMike Christensen resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem); 108030588217SMike Christensen 108130588217SMike Christensen /* process added ports */ 108230588217SMike Christensen for (idx = 0; idx < resp->added.nelem; idx++) { 108330588217SMike Christensen mdp = resp->added.mdp; 108430588217SMike Christensen node = resp->added.mdep[idx]; 108530588217SMike Christensen 108630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: processing added node 0x%lx", 108730588217SMike Christensen __func__, node); 108830588217SMike Christensen 108930588217SMike Christensen /* attempt to add a port */ 1090a600f50dSMike Christensen if ((rv = vlds_add_mdeg_port(mdp, node)) != MDEG_SUCCESS) { 109130588217SMike Christensen if (vlds_ports_inited) { 109230588217SMike Christensen cmn_err(CE_NOTE, "%s: unable to add port, " 109330588217SMike Christensen "err = %d", __func__, rv); 109430588217SMike Christensen } 109530588217SMike Christensen } 109630588217SMike Christensen } 109730588217SMike Christensen 109830588217SMike Christensen /* process removed ports */ 109930588217SMike Christensen for (idx = 0; idx < resp->removed.nelem; idx++) { 110030588217SMike Christensen mdp = resp->removed.mdp; 110130588217SMike Christensen node = resp->removed.mdep[idx]; 110230588217SMike Christensen 110330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: processing removed node 0x%lx", 110430588217SMike Christensen __func__, node); 110530588217SMike Christensen 110630588217SMike Christensen /* read in the port's id property */ 110730588217SMike Christensen if (md_get_prop_val(mdp, node, "id", &portno)) { 110830588217SMike Christensen cmn_err(CE_NOTE, "%s: node 0x%lx of removed list " 110930588217SMike Christensen "has no 'id' property", __func__, node); 111030588217SMike Christensen continue; 111130588217SMike Christensen } 111230588217SMike Christensen 111330588217SMike Christensen /* attempt to remove a port */ 111430588217SMike Christensen if ((rv = ds_remove_port(portno, 0)) != 0) { 111530588217SMike Christensen cmn_err(CE_NOTE, "%s: unable to remove port %lu, " 111630588217SMike Christensen " err %d", __func__, portno, rv); 111730588217SMike Christensen } 111830588217SMike Christensen } 111930588217SMike Christensen 112030588217SMike Christensen vlds_ports_inited = 1; 112130588217SMike Christensen 112230588217SMike Christensen return (MDEG_SUCCESS); 112330588217SMike Christensen } 112430588217SMike Christensen 112530588217SMike Christensen /* register callback to mdeg */ 112630588217SMike Christensen static int 1127a600f50dSMike Christensen vlds_mdeg_register(void) 112830588217SMike Christensen { 112930588217SMike Christensen int rv; 113030588217SMike Christensen 1131a600f50dSMike Christensen DS_DBG_VLDS(CE_NOTE, "vlds_mdeg_register: entered"); 113230588217SMike Christensen 113330588217SMike Christensen /* perform the registration */ 1134a600f50dSMike Christensen rv = mdeg_register(&vlds_node_template, &vlds_port_match, vlds_mdeg_cb, 1135a600f50dSMike Christensen NULL, &vlds_mdeg_hdl); 113630588217SMike Christensen 113730588217SMike Christensen if (rv != MDEG_SUCCESS) { 1138a600f50dSMike Christensen cmn_err(CE_NOTE, "vlds_mdeg_register: mdeg_register " 113930588217SMike Christensen "failed, err = %d", rv); 114030588217SMike Christensen return (DDI_FAILURE); 114130588217SMike Christensen } 114230588217SMike Christensen 114330588217SMike Christensen return (DDI_SUCCESS); 114430588217SMike Christensen } 114530588217SMike Christensen 114630588217SMike Christensen /* unregister callback from mdeg */ 114730588217SMike Christensen static int 1148a600f50dSMike Christensen vlds_mdeg_unregister(void) 114930588217SMike Christensen { 1150a600f50dSMike Christensen DS_DBG_VLDS(CE_NOTE, "vlds_mdeg_unregister: hdl=0x%lx", vlds_mdeg_hdl); 115130588217SMike Christensen 1152a600f50dSMike Christensen return (mdeg_unregister(vlds_mdeg_hdl)); 115330588217SMike Christensen } 115430588217SMike Christensen 115530588217SMike Christensen static int 1156a600f50dSMike Christensen vlds_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id) 115730588217SMike Christensen { 115830588217SMike Christensen int num_nodes, nchan; 115930588217SMike Christensen size_t listsz; 116030588217SMike Christensen mde_cookie_t *listp; 116130588217SMike Christensen 116230588217SMike Christensen /* 116330588217SMike Christensen * Find the channel-endpoint node(s) (which should be under this 116430588217SMike Christensen * port node) which contain the channel id(s). 116530588217SMike Christensen */ 116630588217SMike Christensen if ((num_nodes = md_node_count(mdp)) <= 0) { 116730588217SMike Christensen cmn_err(CE_NOTE, "%s: invalid number of channel-endpoint nodes " 116830588217SMike Christensen "found (%d)", __func__, num_nodes); 116930588217SMike Christensen return (-1); 117030588217SMike Christensen } 117130588217SMike Christensen 117230588217SMike Christensen /* allocate space for node list */ 117330588217SMike Christensen listsz = num_nodes * sizeof (mde_cookie_t); 117430588217SMike Christensen listp = kmem_alloc(listsz, KM_SLEEP); 117530588217SMike Christensen 117630588217SMike Christensen nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"), 117730588217SMike Christensen md_find_name(mdp, "fwd"), listp); 117830588217SMike Christensen 117930588217SMike Christensen if (nchan <= 0) { 118030588217SMike Christensen cmn_err(CE_NOTE, "%s: no channel-endpoint nodes found", 118130588217SMike Christensen __func__); 118230588217SMike Christensen kmem_free(listp, listsz); 118330588217SMike Christensen return (-1); 118430588217SMike Christensen } 118530588217SMike Christensen 118630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: %d channel-endpoint nodes found", __func__, 118730588217SMike Christensen nchan); 118830588217SMike Christensen 118930588217SMike Christensen /* use property from first node found */ 119030588217SMike Christensen if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) { 119130588217SMike Christensen cmn_err(CE_NOTE, "%s: channel-endpoint has no 'id' property", 119230588217SMike Christensen __func__); 119330588217SMike Christensen kmem_free(listp, listsz); 119430588217SMike Christensen return (-1); 119530588217SMike Christensen } 119630588217SMike Christensen 119730588217SMike Christensen kmem_free(listp, listsz); 119830588217SMike Christensen 119930588217SMike Christensen return (0); 120030588217SMike Christensen } 120130588217SMike Christensen 120230588217SMike Christensen /* add a DS services port */ 120330588217SMike Christensen static int 1204a600f50dSMike Christensen vlds_add_mdeg_port(md_t *mdp, mde_cookie_t node) 120530588217SMike Christensen { 120630588217SMike Christensen uint64_t portno; 120730588217SMike Christensen uint64_t ldc_id; 120830588217SMike Christensen int rv; 120930588217SMike Christensen uint64_t dhdl; 121030588217SMike Christensen char *dom_name; 121130588217SMike Christensen 121230588217SMike Christensen /* read in the port's id property */ 121330588217SMike Christensen if (md_get_prop_val(mdp, node, "id", &portno)) { 121430588217SMike Christensen cmn_err(CE_NOTE, "%s: node 0x%lx of added list has no " 121530588217SMike Christensen "'id' property", __func__, node); 121630588217SMike Christensen return (MDEG_FAILURE); 121730588217SMike Christensen } 121830588217SMike Christensen 121930588217SMike Christensen if (portno >= DS_MAX_PORTS) { 122030588217SMike Christensen cmn_err(CE_NOTE, "%s: found port number (%lu) " 122130588217SMike Christensen "larger than maximum supported number of ports", __func__, 122230588217SMike Christensen portno); 122330588217SMike Christensen return (MDEG_FAILURE); 122430588217SMike Christensen } 122530588217SMike Christensen 122630588217SMike Christensen /* get all channels for this device (currently only one) */ 1227a600f50dSMike Christensen if (vlds_get_port_channel(mdp, node, &ldc_id) == -1) { 122830588217SMike Christensen return (MDEG_FAILURE); 122930588217SMike Christensen } 123030588217SMike Christensen 1231a600f50dSMike Christensen if (md_get_prop_val(mdp, node, VLDS_MD_REM_DOMAIN_HDL, &dhdl) != 0) { 1232a600f50dSMike Christensen cmn_err(CE_NOTE, "!ds%lx: %s no %s property", portno, __func__, 1233a600f50dSMike Christensen VLDS_MD_REM_DOMAIN_HDL); 123430588217SMike Christensen dhdl = DS_DHDL_INVALID; 123530588217SMike Christensen } 123630588217SMike Christensen 1237a600f50dSMike Christensen if (md_get_prop_str(mdp, node, VLDS_MD_REM_DOMAIN_NAME, &dom_name) 1238a600f50dSMike Christensen != 0) { 1239a600f50dSMike Christensen cmn_err(CE_NOTE, "!ds%lx: %s no %s property", portno, __func__, 1240a600f50dSMike Christensen VLDS_MD_REM_DOMAIN_NAME); 124130588217SMike Christensen dom_name = NULL; 124230588217SMike Christensen } 124330588217SMike Christensen 124430588217SMike Christensen rv = ds_add_port(portno, ldc_id, dhdl, dom_name, vlds_ports_inited); 124530588217SMike Christensen 124630588217SMike Christensen if (rv != 0) { 124730588217SMike Christensen if (vlds_ports_inited) { 124830588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "ds%lx: %s LDC chan: %lx " 124930588217SMike Christensen "failed err = %d", portno, __func__, ldc_id, rv); 125030588217SMike Christensen } 125130588217SMike Christensen return (MDEG_FAILURE); 125230588217SMike Christensen } 125330588217SMike Christensen 125430588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "ds%lx: %s LDC chan: %lx inited", portno, 125530588217SMike Christensen __func__, ldc_id); 125630588217SMike Christensen 125730588217SMike Christensen return (MDEG_SUCCESS); 125830588217SMike Christensen } 125930588217SMike Christensen 126030588217SMike Christensen static void 1261a600f50dSMike Christensen vlds_mdeg_init(void) 1262a600f50dSMike Christensen { 1263a600f50dSMike Christensen md_t *mdp; 1264a600f50dSMike Christensen int num_nodes; 1265a600f50dSMike Christensen int listsz; 1266a600f50dSMike Christensen mde_cookie_t rootnode; 1267a600f50dSMike Christensen mde_cookie_t vldsnode; 1268a600f50dSMike Christensen mde_cookie_t *vlds_nodes = NULL; 1269a600f50dSMike Christensen int nvlds; 1270a600f50dSMike Christensen int i; 1271a600f50dSMike Christensen ds_domain_hdl_t dhdl; 1272a600f50dSMike Christensen char *dom_name; 1273a600f50dSMike Christensen char *svc_name; 1274a600f50dSMike Christensen 1275a600f50dSMike Christensen if ((mdp = md_get_handle()) == NULL) { 1276a600f50dSMike Christensen cmn_err(CE_NOTE, "Unable to initialize machine description"); 1277a600f50dSMike Christensen return; 1278a600f50dSMike Christensen } 1279a600f50dSMike Christensen 1280a600f50dSMike Christensen num_nodes = md_node_count(mdp); 1281a600f50dSMike Christensen ASSERT(num_nodes > 0); 1282a600f50dSMike Christensen 1283a600f50dSMike Christensen listsz = num_nodes * sizeof (mde_cookie_t); 1284a600f50dSMike Christensen 1285a600f50dSMike Christensen /* allocate temporary storage for MD scans */ 1286a600f50dSMike Christensen vlds_nodes = kmem_zalloc(listsz, KM_SLEEP); 1287a600f50dSMike Christensen 1288a600f50dSMike Christensen rootnode = md_root_node(mdp); 1289a600f50dSMike Christensen ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1290a600f50dSMike Christensen 1291a600f50dSMike Christensen /* 1292a600f50dSMike Christensen * Search for Virtual Domain Service node. 1293a600f50dSMike Christensen */ 1294a600f50dSMike Christensen nvlds = md_scan_dag(mdp, rootnode, md_find_name(mdp, 1295a600f50dSMike Christensen VLDS_MD_VIRT_DEV_NAME), md_find_name(mdp, "fwd"), vlds_nodes); 1296a600f50dSMike Christensen 1297a600f50dSMike Christensen if (nvlds <= 0) { 1298a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "No '%s' nodes in MD", 1299a600f50dSMike Christensen VLDS_MD_VIRT_DEV_NAME); 1300a600f50dSMike Christensen goto done; 1301a600f50dSMike Christensen } 1302a600f50dSMike Christensen 1303a600f50dSMike Christensen for (i = 0; i < nvlds; i++) { 1304a600f50dSMike Christensen if (md_get_prop_str(mdp, vlds_nodes[i], "name", &svc_name)) { 1305a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "%s: missing 'name' property for" 1306a600f50dSMike Christensen " IO node %d\n", __func__, i); 1307a600f50dSMike Christensen continue; 1308a600f50dSMike Christensen } 1309a600f50dSMike Christensen 1310a600f50dSMike Christensen if (strcmp(svc_name, VLDS_MD_VIRT_ROOT_NAME) == 0) { 1311a600f50dSMike Christensen vldsnode = vlds_nodes[i]; 1312a600f50dSMike Christensen break; 1313a600f50dSMike Christensen } 1314a600f50dSMike Christensen } 1315a600f50dSMike Christensen 1316a600f50dSMike Christensen if (i >= nvlds) { 1317a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "No '%s' node in MD", 1318a600f50dSMike Christensen VLDS_MD_VIRT_ROOT_NAME); 1319a600f50dSMike Christensen goto done; 1320a600f50dSMike Christensen } 1321a600f50dSMike Christensen 1322a600f50dSMike Christensen if (md_get_prop_val(mdp, vldsnode, VLDS_MD_DOMAIN_HDL, &dhdl) != 0) { 1323a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "No '%s' property for '%s' node in MD", 1324a600f50dSMike Christensen VLDS_MD_DOMAIN_HDL, VLDS_MD_VIRT_ROOT_NAME); 1325a600f50dSMike Christensen dhdl = DS_DHDL_INVALID; 1326a600f50dSMike Christensen } 1327a600f50dSMike Christensen if (md_get_prop_str(mdp, vldsnode, VLDS_MD_DOMAIN_NAME, &dom_name) 1328a600f50dSMike Christensen != 0) { 1329a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "No '%s' property for '%s' node in MD", 1330a600f50dSMike Christensen VLDS_MD_DOMAIN_NAME, VLDS_MD_VIRT_ROOT_NAME); 1331a600f50dSMike Christensen dom_name = NULL; 1332a600f50dSMike Christensen } 1333a600f50dSMike Christensen DS_DBG_MD(CE_NOTE, "My Domain Hdl: 0x%lx, Name: '%s'", dhdl, 1334a600f50dSMike Christensen dom_name == NULL ? "NULL" : dom_name); 1335a600f50dSMike Christensen ds_set_my_dom_hdl_name(dhdl, dom_name); 1336a600f50dSMike Christensen 1337a600f50dSMike Christensen done: 1338a600f50dSMike Christensen DS_FREE(vlds_nodes, listsz); 1339a600f50dSMike Christensen 1340a600f50dSMike Christensen (void) md_fini_handle(mdp); 1341a600f50dSMike Christensen } 1342a600f50dSMike Christensen 1343a600f50dSMike Christensen static void 134430588217SMike Christensen vlds_user_reg_cb(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 134530588217SMike Christensen { 134630588217SMike Christensen nvlist_t *nvl = NULL; 134730588217SMike Christensen ds_domain_hdl_t dhdl; 134830588217SMike Christensen char *servicep; 134930588217SMike Christensen uint32_t flags; 135030588217SMike Christensen int minor; 135130588217SMike Christensen vlds_state_t *sp; 135230588217SMike Christensen vlds_svc_info_t *dpsp; 135330588217SMike Christensen 135430588217SMike Christensen ds_cbarg_get_flags(arg, &flags); 135530588217SMike Christensen ASSERT((flags & DSSF_ISUSER) != 0); 135630588217SMike Christensen 135730588217SMike Christensen if ((flags & DSSF_DATACB_VALID) == 0) { 135830588217SMike Christensen /* 135930588217SMike Christensen * must allocate and init the svc read queue. 136030588217SMike Christensen */ 136130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: hdl: 0x%lx initing recvq", __func__, 136230588217SMike Christensen hdl); 136330588217SMike Christensen dpsp = DS_MALLOC(sizeof (vlds_svc_info_t)); 136430588217SMike Christensen vlds_recvq_init(dpsp); 136530588217SMike Christensen ds_cbarg_set_drv_per_svc_ptr(arg, dpsp); 136630588217SMike Christensen } 136730588217SMike Christensen 136830588217SMike Christensen if ((flags & DSSF_REGCB_VALID) != 0) { 136930588217SMike Christensen ds_cbarg_get_drv_info(arg, &minor); 137030588217SMike Christensen sp = ddi_get_soft_state(vlds_statep, minor); 137130588217SMike Christensen ASSERT(sp != NULL); 137230588217SMike Christensen ASSERT(sp->evchan != NULL); 137330588217SMike Christensen ds_cbarg_get_domain(arg, &dhdl); 137430588217SMike Christensen ds_cbarg_get_service_id(arg, &servicep); 137530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: regcb: hdl: 0x%lx, ver%d.%d, " 137630588217SMike Christensen " dhdl: 0x%lx", __func__, hdl, ver->major, 137730588217SMike Christensen ver->minor, dhdl); 137830588217SMike Christensen if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) || 137930588217SMike Christensen nvlist_add_uint64(nvl, VLDS_HDL, hdl) || 138030588217SMike Christensen nvlist_add_uint16(nvl, VLDS_VER_MAJOR, ver->major) || 138130588217SMike Christensen nvlist_add_uint16(nvl, VLDS_VER_MINOR, ver->minor) || 138230588217SMike Christensen nvlist_add_uint64(nvl, VLDS_DOMAIN_HDL, dhdl) || 138330588217SMike Christensen nvlist_add_string(nvl, VLDS_SERVICE_ID, servicep) || 138430588217SMike Christensen nvlist_add_boolean_value(nvl, VLDS_ISCLIENT, 138530588217SMike Christensen (flags & DSSF_ISCLIENT) != 0) || 138630588217SMike Christensen sysevent_evc_publish(sp->evchan, EC_VLDS, 138730588217SMike Christensen ESC_VLDS_REGISTER, "sun.com", "kernel", nvl, EVCH_SLEEP)) { 138830588217SMike Christensen cmn_err(CE_WARN, "Failed to send REG Callback"); 138930588217SMike Christensen } else { 139030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: sysevent_evc_publish " 139130588217SMike Christensen "succeeded", __func__); 139230588217SMike Christensen } 139330588217SMike Christensen nvlist_free(nvl); 139430588217SMike Christensen } 139530588217SMike Christensen } 139630588217SMike Christensen 139730588217SMike Christensen static void 139830588217SMike Christensen vlds_user_unreg_cb(ds_cb_arg_t arg) 139930588217SMike Christensen { 140030588217SMike Christensen nvlist_t *nvl = NULL; 140130588217SMike Christensen int minor; 140230588217SMike Christensen ds_svc_hdl_t hdl; 140330588217SMike Christensen vlds_state_t *sp; 140430588217SMike Christensen void *dpsp; 140530588217SMike Christensen uint32_t flags; 140630588217SMike Christensen 140730588217SMike Christensen ds_cbarg_get_flags(arg, &flags); 140830588217SMike Christensen ASSERT((flags & DSSF_ISUSER) != 0); 140930588217SMike Christensen 141030588217SMike Christensen if ((flags & DSSF_DATACB_VALID) == 0) { 141130588217SMike Christensen ds_cbarg_get_drv_per_svc_ptr(arg, &dpsp); 141230588217SMike Christensen if (dpsp) { 141330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: unregcb draining recvq", 141430588217SMike Christensen __func__); 141530588217SMike Christensen vlds_recvq_drain(dpsp); 141630588217SMike Christensen vlds_recvq_destroy(dpsp); 141730588217SMike Christensen ds_cbarg_set_drv_per_svc_ptr(arg, NULL); 141830588217SMike Christensen } 141930588217SMike Christensen } 142030588217SMike Christensen 142130588217SMike Christensen if ((flags & DSSF_UNREGCB_VALID) != 0) { 142230588217SMike Christensen ds_cbarg_get_hdl(arg, &hdl); 142330588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: unregcb hdl: 0x%lx", __func__, 142430588217SMike Christensen hdl); 142530588217SMike Christensen ds_cbarg_get_drv_info(arg, &minor); 142630588217SMike Christensen sp = ddi_get_soft_state(vlds_statep, minor); 142730588217SMike Christensen ASSERT(sp != NULL); 142830588217SMike Christensen ASSERT(sp->evchan != NULL); 142930588217SMike Christensen if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) || 143030588217SMike Christensen nvlist_add_uint64(nvl, VLDS_HDL, hdl) || 143130588217SMike Christensen sysevent_evc_publish(sp->evchan, EC_VLDS, 143230588217SMike Christensen ESC_VLDS_UNREGISTER, "sun.com", "kernel", nvl, 143330588217SMike Christensen EVCH_SLEEP)) { 143430588217SMike Christensen cmn_err(CE_WARN, "Failed to send UNREG Callback"); 143530588217SMike Christensen } 143630588217SMike Christensen nvlist_free(nvl); 143730588217SMike Christensen } 143830588217SMike Christensen } 143930588217SMike Christensen 144030588217SMike Christensen static void 144130588217SMike Christensen vlds_user_data_cb(ds_cb_arg_t arg, void *buf, size_t buflen) 144230588217SMike Christensen { 144330588217SMike Christensen nvlist_t *nvl = NULL; 144430588217SMike Christensen ds_svc_hdl_t hdl; 144530588217SMike Christensen int minor; 144630588217SMike Christensen void *dpsp; 144730588217SMike Christensen vlds_state_t *sp; 144830588217SMike Christensen uint32_t flags; 144930588217SMike Christensen 145030588217SMike Christensen ds_cbarg_get_flags(arg, &flags); 145130588217SMike Christensen ASSERT((flags & DSSF_ISUSER) != 0); 145230588217SMike Christensen 145330588217SMike Christensen if ((flags & DSSF_DATACB_VALID) == 0) { 145430588217SMike Christensen ds_cbarg_get_drv_per_svc_ptr(arg, &dpsp); 145530588217SMike Christensen ASSERT(dpsp != NULL); 145630588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: datacb: to recvq: buflen: %ld", 145730588217SMike Christensen __func__, buflen); 145830588217SMike Christensen (void) vlds_recvq_put_data(dpsp, buf, buflen); 145930588217SMike Christensen } else { 146030588217SMike Christensen ds_cbarg_get_hdl(arg, &hdl); 146130588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: datacb: usercb: hdl: 0x%lx, " 146230588217SMike Christensen " buflen: %ld", __func__, hdl, buflen); 146330588217SMike Christensen ds_cbarg_get_drv_info(arg, &minor); 146430588217SMike Christensen sp = ddi_get_soft_state(vlds_statep, minor); 146530588217SMike Christensen ASSERT(sp != NULL); 146630588217SMike Christensen ASSERT(sp->evchan != NULL); 146730588217SMike Christensen if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) || 146830588217SMike Christensen nvlist_add_uint64(nvl, VLDS_HDL, hdl) || 146930588217SMike Christensen nvlist_add_byte_array(nvl, VLDS_DATA, buf, buflen) || 147030588217SMike Christensen sysevent_evc_publish(sp->evchan, EC_VLDS, 147130588217SMike Christensen ESC_VLDS_DATA, "sun.com", "kernel", nvl, EVCH_SLEEP)) { 147230588217SMike Christensen cmn_err(CE_WARN, "Failed to send DATA Callback"); 147330588217SMike Christensen } 147430588217SMike Christensen } 147530588217SMike Christensen nvlist_free(nvl); 147630588217SMike Christensen } 147730588217SMike Christensen 147830588217SMike Christensen /* 147930588217SMike Christensen * Initialize receive queue if request is from user land but 148030588217SMike Christensen * data callback is null (implying user will be using ds_recv_msg). 148130588217SMike Christensen */ 148230588217SMike Christensen static void 148330588217SMike Christensen vlds_recvq_init(vlds_svc_info_t *dpsp) 148430588217SMike Christensen { 148530588217SMike Christensen dpsp->state = VLDS_RECV_OK; 148630588217SMike Christensen mutex_init(&dpsp->recv_lock, NULL, MUTEX_DRIVER, NULL); 148730588217SMike Christensen cv_init(&dpsp->recv_cv, NULL, CV_DRIVER, NULL); 148830588217SMike Christensen dpsp->recv_headp = NULL; 148930588217SMike Christensen dpsp->recv_tailp = NULL; 149030588217SMike Christensen dpsp->recv_size = 0; 1491ba9236fbSMike Christensen dpsp->recv_cnt = 0; 149230588217SMike Christensen } 149330588217SMike Christensen 149430588217SMike Christensen static void 149530588217SMike Christensen vlds_recvq_destroy(vlds_svc_info_t *dpsp) 149630588217SMike Christensen { 149730588217SMike Christensen ASSERT(dpsp->state == VLDS_RECV_UNREG_PENDING); 149830588217SMike Christensen ASSERT(dpsp->recv_size == 0); 1499ba9236fbSMike Christensen ASSERT(dpsp->recv_cnt == 0); 150030588217SMike Christensen ASSERT(dpsp->recv_headp == NULL); 150130588217SMike Christensen ASSERT(dpsp->recv_tailp == NULL); 150230588217SMike Christensen 150330588217SMike Christensen mutex_destroy(&dpsp->recv_lock); 150430588217SMike Christensen cv_destroy(&dpsp->recv_cv); 150530588217SMike Christensen DS_FREE(dpsp, sizeof (vlds_svc_info_t)); 150630588217SMike Christensen } 150730588217SMike Christensen 150830588217SMike Christensen static int 150930588217SMike Christensen vlds_recvq_get_data(vlds_svc_info_t *dpsp, void *buf, size_t buflen, 151030588217SMike Christensen size_t *msglenp, int mode) 151130588217SMike Christensen { 151230588217SMike Christensen vlds_recv_hdr_t *rhp; 151330588217SMike Christensen int rv; 151430588217SMike Christensen size_t msglen; 151530588217SMike Christensen 151630588217SMike Christensen mutex_enter(&dpsp->recv_lock); 151730588217SMike Christensen while (dpsp->recv_size == 0) { 1518ba9236fbSMike Christensen ASSERT(dpsp->recv_cnt == 0); 151930588217SMike Christensen if (dpsp->state == VLDS_RECV_UNREG_PENDING) 152030588217SMike Christensen break; 1521ba9236fbSMike Christensen 1522ba9236fbSMike Christensen if (dpsp->state == VLDS_RECV_OVERFLOW) { 1523ba9236fbSMike Christensen DS_DBG_RCVQ(CE_NOTE, "%s: user data queue overflow", 1524ba9236fbSMike Christensen __func__); 1525ba9236fbSMike Christensen dpsp->state = VLDS_RECV_OK; 1526ba9236fbSMike Christensen mutex_exit(&dpsp->recv_lock); 1527ba9236fbSMike Christensen return (ENOBUFS); 1528ba9236fbSMike Christensen } 152930588217SMike Christensen /* 153030588217SMike Christensen * Passing in a buflen of 0 allows user to poll for msgs. 153130588217SMike Christensen */ 153230588217SMike Christensen if (buflen == 0) { 153330588217SMike Christensen mutex_exit(&dpsp->recv_lock); 153430588217SMike Christensen *msglenp = 0; 153530588217SMike Christensen return (EFBIG); 153630588217SMike Christensen } 153730588217SMike Christensen dpsp->recv_nreaders += 1; 153830588217SMike Christensen rv = cv_wait_sig(&dpsp->recv_cv, &dpsp->recv_lock); 153930588217SMike Christensen dpsp->recv_nreaders -= 1; 154030588217SMike Christensen if (rv == 0) { 154130588217SMike Christensen DS_DBG_RCVQ(CE_NOTE, "%s: signal EINTR", __func__); 154230588217SMike Christensen mutex_exit(&dpsp->recv_lock); 154330588217SMike Christensen return (EINTR); 154430588217SMike Christensen } 154530588217SMike Christensen } 154630588217SMike Christensen if (dpsp->state == VLDS_RECV_UNREG_PENDING) { 154730588217SMike Christensen DS_DBG_RCVQ(CE_NOTE, "%s: unreg pending", __func__); 154830588217SMike Christensen cv_broadcast(&dpsp->recv_cv); 154930588217SMike Christensen mutex_exit(&dpsp->recv_lock); 155030588217SMike Christensen return (EINVAL); 155130588217SMike Christensen } 155230588217SMike Christensen ASSERT(dpsp->recv_headp != NULL); 155330588217SMike Christensen rhp = dpsp->recv_headp; 155430588217SMike Christensen 155530588217SMike Christensen /* 155630588217SMike Christensen * Don't transfer truncated data, return EFBIG error if user-supplied 155730588217SMike Christensen * buffer is too small. 155830588217SMike Christensen */ 155930588217SMike Christensen if (rhp->datasz > buflen) { 156030588217SMike Christensen *msglenp = rhp->datasz; 156130588217SMike Christensen mutex_exit(&dpsp->recv_lock); 156230588217SMike Christensen return (EFBIG); 156330588217SMike Christensen } 156430588217SMike Christensen if (rhp == dpsp->recv_tailp) { 156530588217SMike Christensen dpsp->recv_headp = NULL; 156630588217SMike Christensen dpsp->recv_tailp = NULL; 156730588217SMike Christensen } else { 156830588217SMike Christensen dpsp->recv_headp = rhp->next; 156930588217SMike Christensen ASSERT(dpsp->recv_headp != NULL); 157030588217SMike Christensen } 1571ba9236fbSMike Christensen ASSERT(dpsp->recv_cnt > 0); 157230588217SMike Christensen dpsp->recv_size -= rhp->datasz; 1573ba9236fbSMike Christensen dpsp->recv_cnt -= 1; 157430588217SMike Christensen mutex_exit(&dpsp->recv_lock); 157530588217SMike Christensen 157630588217SMike Christensen msglen = rhp->datasz; 157730588217SMike Christensen rv = ddi_copyout(rhp->data, buf, msglen, mode); 157830588217SMike Christensen 157930588217SMike Christensen if (rv == 0) { 158030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: user data dequeued msglen: %ld", 158130588217SMike Christensen __func__, rhp->datasz); 158230588217SMike Christensen DS_DUMP_MSG(DS_DBG_FLAG_VLDS, rhp->data, rhp->datasz); 158330588217SMike Christensen } 158430588217SMike Christensen 158530588217SMike Christensen DS_FREE(rhp->data, rhp->datasz); 158630588217SMike Christensen DS_FREE(rhp, sizeof (vlds_recv_hdr_t)); 158730588217SMike Christensen 158830588217SMike Christensen if (rv != 0) { 158930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: copyout failed", __func__); 159030588217SMike Christensen return (EFAULT); 159130588217SMike Christensen } 159230588217SMike Christensen 159330588217SMike Christensen *msglenp = msglen; 159430588217SMike Christensen return (0); 159530588217SMike Christensen } 159630588217SMike Christensen 159730588217SMike Christensen uint64_t vlds_recv_drain_delay_time = 1 * MILLISEC; 159830588217SMike Christensen 159930588217SMike Christensen static void 160030588217SMike Christensen vlds_recvq_drain(vlds_svc_info_t *dpsp) 160130588217SMike Christensen { 160230588217SMike Christensen vlds_recv_hdr_t *rhp, *nextp; 160330588217SMike Christensen 160430588217SMike Christensen mutex_enter(&dpsp->recv_lock); 160530588217SMike Christensen dpsp->state = VLDS_RECV_UNREG_PENDING; 160630588217SMike Christensen for (rhp = dpsp->recv_tailp; rhp != NULL; rhp = nextp) { 160730588217SMike Christensen nextp = rhp->next; 160830588217SMike Christensen DS_FREE(rhp->data, rhp->datasz); 160930588217SMike Christensen DS_FREE(rhp, sizeof (vlds_recv_hdr_t)); 161030588217SMike Christensen } 161130588217SMike Christensen dpsp->recv_headp = NULL; 161230588217SMike Christensen dpsp->recv_tailp = NULL; 161330588217SMike Christensen dpsp->recv_size = 0; 1614ba9236fbSMike Christensen dpsp->recv_cnt = 0; 161530588217SMike Christensen 161630588217SMike Christensen /* 161730588217SMike Christensen * Make sure other readers have exited. 161830588217SMike Christensen */ 161930588217SMike Christensen while (dpsp->recv_nreaders > 0) { 162030588217SMike Christensen cv_broadcast(&dpsp->recv_cv); 162130588217SMike Christensen mutex_exit(&dpsp->recv_lock); 162230588217SMike Christensen delay(vlds_recv_drain_delay_time); 162330588217SMike Christensen mutex_enter(&dpsp->recv_lock); 162430588217SMike Christensen } 162530588217SMike Christensen 162630588217SMike Christensen mutex_exit(&dpsp->recv_lock); 162730588217SMike Christensen } 162830588217SMike Christensen 162930588217SMike Christensen static int 163030588217SMike Christensen vlds_recvq_put_data(vlds_svc_info_t *dpsp, void *buf, size_t buflen) 163130588217SMike Christensen { 163230588217SMike Christensen vlds_recv_hdr_t *rhp; 163330588217SMike Christensen 163430588217SMike Christensen mutex_enter(&dpsp->recv_lock); 163530588217SMike Christensen if (dpsp->state != VLDS_RECV_UNREG_PENDING) { 1636ba9236fbSMike Christensen /* 1637ba9236fbSMike Christensen * If we've already encountered an overflow, or there 1638ba9236fbSMike Christensen * are pending messages and either queue size and 1639ba9236fbSMike Christensen * message limits will be exceeded with this message, 1640ba9236fbSMike Christensen * we mark the recvq as overflowed and return an ENOBUFS 1641ba9236fbSMike Christensen * error. This allows the enqueuing of one big message 1642ba9236fbSMike Christensen * or several little messages. 1643ba9236fbSMike Christensen */ 1644ba9236fbSMike Christensen if ((dpsp->state == VLDS_RECV_OVERFLOW) || 1645ba9236fbSMike Christensen ((dpsp->recv_cnt != 0) && 1646ba9236fbSMike Christensen ((dpsp->recv_size + buflen) > vlds_recvq_maxsize) || 1647ba9236fbSMike Christensen ((dpsp->recv_cnt + 1) > vlds_recvq_maxmsg))) { 1648ba9236fbSMike Christensen DS_DBG_RCVQ(CE_NOTE, "%s: user data queue overflow", 1649ba9236fbSMike Christensen __func__); 1650ba9236fbSMike Christensen dpsp->state = VLDS_RECV_OVERFLOW; 1651ba9236fbSMike Christensen cv_broadcast(&dpsp->recv_cv); 1652ba9236fbSMike Christensen mutex_exit(&dpsp->recv_lock); 1653ba9236fbSMike Christensen return (ENOBUFS); 1654ba9236fbSMike Christensen } 1655ba9236fbSMike Christensen 165630588217SMike Christensen DS_DBG_RCVQ(CE_NOTE, "%s: user data enqueued msglen: %ld", 165730588217SMike Christensen __func__, buflen); 165830588217SMike Christensen DS_DUMP_MSG(DS_DBG_FLAG_RCVQ, buf, buflen); 165930588217SMike Christensen rhp = DS_MALLOC(sizeof (vlds_recv_hdr_t)); 166030588217SMike Christensen rhp->data = DS_MALLOC(buflen); 166130588217SMike Christensen (void) memcpy(rhp->data, buf, buflen); 166230588217SMike Christensen rhp->datasz = buflen; 166330588217SMike Christensen rhp->next = NULL; 166430588217SMike Christensen if (dpsp->recv_headp == NULL) { 166530588217SMike Christensen dpsp->recv_headp = rhp; 166630588217SMike Christensen dpsp->recv_tailp = rhp; 166730588217SMike Christensen } else { 166830588217SMike Christensen dpsp->recv_tailp->next = rhp; 166930588217SMike Christensen dpsp->recv_tailp = rhp; 167030588217SMike Christensen } 167130588217SMike Christensen dpsp->recv_size += rhp->datasz; 1672ba9236fbSMike Christensen dpsp->recv_cnt += 1; 167330588217SMike Christensen cv_broadcast(&dpsp->recv_cv); 167430588217SMike Christensen } 167530588217SMike Christensen mutex_exit(&dpsp->recv_lock); 167630588217SMike Christensen return (0); 167730588217SMike Christensen } 167830588217SMike Christensen 167930588217SMike Christensen static int 168030588217SMike Christensen vlds_recv_msg(ds_svc_hdl_t hdl, void *buf, size_t buflen, size_t *msglenp, 168130588217SMike Christensen int mode) 168230588217SMike Christensen { 168330588217SMike Christensen void *dpsp; 168430588217SMike Christensen ds_cb_arg_t cbarg; 168530588217SMike Christensen uint32_t flags; 168630588217SMike Christensen int rv; 168730588217SMike Christensen 168830588217SMike Christensen if ((rv = ds_hdl_get_cbarg(hdl, &cbarg)) != 0) { 168930588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: handle %lx not found (%d)", __func__, 169030588217SMike Christensen hdl, rv); 169130588217SMike Christensen return (rv); 169230588217SMike Christensen } 169330588217SMike Christensen ds_cbarg_get_flags(cbarg, &flags); 169430588217SMike Christensen if ((flags & DSSF_ISUSER) == 0 || (flags & DSSF_DATACB_VALID) != 0) { 169530588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: invalid flags: %x", __func__, flags); 169630588217SMike Christensen return (EINVAL); 169730588217SMike Christensen } 169830588217SMike Christensen ds_cbarg_get_drv_per_svc_ptr(cbarg, &dpsp); 169930588217SMike Christensen if (dpsp == NULL) { 170030588217SMike Christensen DS_DBG_VLDS(CE_NOTE, "%s: recv on non-ready handle: %x", 170130588217SMike Christensen __func__, flags); 170230588217SMike Christensen return (ENXIO); 170330588217SMike Christensen } 170430588217SMike Christensen rv = vlds_recvq_get_data(dpsp, buf, buflen, msglenp, mode); 170530588217SMike Christensen return (rv); 170630588217SMike Christensen } 1707