1*1ae08745Sheppo /* 2*1ae08745Sheppo * CDDL HEADER START 3*1ae08745Sheppo * 4*1ae08745Sheppo * The contents of this file are subject to the terms of the 5*1ae08745Sheppo * Common Development and Distribution License (the "License"). 6*1ae08745Sheppo * You may not use this file except in compliance with the License. 7*1ae08745Sheppo * 8*1ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 10*1ae08745Sheppo * See the License for the specific language governing permissions 11*1ae08745Sheppo * and limitations under the License. 12*1ae08745Sheppo * 13*1ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1ae08745Sheppo * 19*1ae08745Sheppo * CDDL HEADER END 20*1ae08745Sheppo */ 21*1ae08745Sheppo 22*1ae08745Sheppo /* 23*1ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1ae08745Sheppo * Use is subject to license terms. 25*1ae08745Sheppo */ 26*1ae08745Sheppo 27*1ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 28*1ae08745Sheppo 29*1ae08745Sheppo #include <sys/types.h> 30*1ae08745Sheppo #include <sys/file.h> 31*1ae08745Sheppo #include <sys/errno.h> 32*1ae08745Sheppo #include <sys/uio.h> 33*1ae08745Sheppo #include <sys/open.h> 34*1ae08745Sheppo #include <sys/cred.h> 35*1ae08745Sheppo #include <sys/kmem.h> 36*1ae08745Sheppo #include <sys/conf.h> 37*1ae08745Sheppo #include <sys/cmn_err.h> 38*1ae08745Sheppo #include <sys/ksynch.h> 39*1ae08745Sheppo #include <sys/modctl.h> 40*1ae08745Sheppo #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 41*1ae08745Sheppo #include <sys/debug.h> 42*1ae08745Sheppo #include <sys/sysmacros.h> 43*1ae08745Sheppo #include <sys/types.h> 44*1ae08745Sheppo #include <sys/cred.h> 45*1ae08745Sheppo #include <sys/promif.h> 46*1ae08745Sheppo #include <sys/ddi.h> 47*1ae08745Sheppo #include <sys/sunddi.h> 48*1ae08745Sheppo #include <sys/cyclic.h> 49*1ae08745Sheppo #include <sys/note.h> 50*1ae08745Sheppo #include <sys/mach_descrip.h> 51*1ae08745Sheppo #include <sys/mdeg.h> 52*1ae08745Sheppo #include <sys/ldc.h> 53*1ae08745Sheppo #include <sys/vldc_impl.h> 54*1ae08745Sheppo 55*1ae08745Sheppo /* 56*1ae08745Sheppo * Function prototypes. 57*1ae08745Sheppo */ 58*1ae08745Sheppo 59*1ae08745Sheppo /* DDI entrypoints */ 60*1ae08745Sheppo static int vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 61*1ae08745Sheppo static int vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 62*1ae08745Sheppo static int vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred); 63*1ae08745Sheppo static int vldc_close(dev_t dev, int flag, int otyp, cred_t *cred); 64*1ae08745Sheppo static int vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 65*1ae08745Sheppo cred_t *credp, int *rvalp); 66*1ae08745Sheppo static int vldc_read(dev_t dev, struct uio *uiop, cred_t *credp); 67*1ae08745Sheppo static int vldc_write(dev_t dev, struct uio *uiop, cred_t *credp); 68*1ae08745Sheppo static int vldc_chpoll(dev_t dev, short events, int anyyet, 69*1ae08745Sheppo short *reventsp, struct pollhead **phpp); 70*1ae08745Sheppo 71*1ae08745Sheppo /* Internal functions */ 72*1ae08745Sheppo static uint_t i_vldc_cb(uint64_t event, caddr_t arg); 73*1ae08745Sheppo static int i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 74*1ae08745Sheppo static int i_vldc_mdeg_register(vldc_t *vldcp); 75*1ae08745Sheppo static int i_vldc_mdeg_unregister(vldc_t *vldcp); 76*1ae08745Sheppo static int i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node); 77*1ae08745Sheppo static int i_vldc_remove_port(vldc_t *vldcp, uint_t portno); 78*1ae08745Sheppo static int i_vldc_close_port(vldc_t *vldcp, uint_t portno); 79*1ae08745Sheppo 80*1ae08745Sheppo /* soft state structure */ 81*1ae08745Sheppo static void *vldc_ssp; 82*1ae08745Sheppo 83*1ae08745Sheppo /* 84*1ae08745Sheppo * Matching criteria passed to the MDEG to register interest 85*1ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 86*1ae08745Sheppo * 'id' property. 87*1ae08745Sheppo */ 88*1ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 89*1ae08745Sheppo { MDET_PROP_VAL, "id" }, 90*1ae08745Sheppo { MDET_LIST_END, NULL } 91*1ae08745Sheppo }; 92*1ae08745Sheppo 93*1ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 94*1ae08745Sheppo vport_prop_match }; 95*1ae08745Sheppo 96*1ae08745Sheppo /* 97*1ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 98*1ae08745Sheppo * 'virtual-device-port' nodes that do not belong to the specified 99*1ae08745Sheppo * node. This template is copied for each vldc instance and filled 100*1ae08745Sheppo * in with the appropriate 'name' and 'cfg-handle' values before 101*1ae08745Sheppo * being passed to the MDEG. 102*1ae08745Sheppo */ 103*1ae08745Sheppo static mdeg_prop_spec_t vldc_prop_template[] = { 104*1ae08745Sheppo { MDET_PROP_STR, "name", NULL }, 105*1ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 106*1ae08745Sheppo { MDET_LIST_END, NULL, NULL } 107*1ae08745Sheppo }; 108*1ae08745Sheppo 109*1ae08745Sheppo #define VLDC_MDEG_PROP_NAME(specp) ((specp)[0].ps_str) 110*1ae08745Sheppo #define VLDC_SET_MDEG_PROP_NAME(specp, name) ((specp)[0].ps_str = (name)) 111*1ae08745Sheppo #define VLDC_SET_MDEG_PROP_INST(specp, inst) ((specp)[1].ps_val = (inst)) 112*1ae08745Sheppo 113*1ae08745Sheppo 114*1ae08745Sheppo static struct cb_ops vldc_cb_ops = { 115*1ae08745Sheppo vldc_open, /* open */ 116*1ae08745Sheppo vldc_close, /* close */ 117*1ae08745Sheppo nodev, /* strategy */ 118*1ae08745Sheppo nodev, /* print */ 119*1ae08745Sheppo nodev, /* dump */ 120*1ae08745Sheppo vldc_read, /* read */ 121*1ae08745Sheppo vldc_write, /* write */ 122*1ae08745Sheppo vldc_ioctl, /* ioctl */ 123*1ae08745Sheppo nodev, /* devmap */ 124*1ae08745Sheppo nodev, /* mmap */ 125*1ae08745Sheppo ddi_segmap, /* segmap */ 126*1ae08745Sheppo vldc_chpoll, /* chpoll */ 127*1ae08745Sheppo ddi_prop_op, /* prop_op */ 128*1ae08745Sheppo NULL, /* stream */ 129*1ae08745Sheppo D_NEW | D_MP /* flag */ 130*1ae08745Sheppo }; 131*1ae08745Sheppo 132*1ae08745Sheppo static struct dev_ops vldc_ops = { 133*1ae08745Sheppo DEVO_REV, /* rev */ 134*1ae08745Sheppo 0, /* ref count */ 135*1ae08745Sheppo ddi_getinfo_1to1, /* getinfo */ 136*1ae08745Sheppo nulldev, /* identify */ 137*1ae08745Sheppo nulldev, /* probe */ 138*1ae08745Sheppo vldc_attach, /* attach */ 139*1ae08745Sheppo vldc_detach, /* detach */ 140*1ae08745Sheppo nodev, /* reset */ 141*1ae08745Sheppo &vldc_cb_ops, /* cb_ops */ 142*1ae08745Sheppo (struct bus_ops *)NULL /* bus_ops */ 143*1ae08745Sheppo }; 144*1ae08745Sheppo 145*1ae08745Sheppo extern struct mod_ops mod_driverops; 146*1ae08745Sheppo 147*1ae08745Sheppo static struct modldrv md = { 148*1ae08745Sheppo &mod_driverops, /* Type - it is a driver */ 149*1ae08745Sheppo "sun4v Virtual LDC Driver %I%", /* Name of the module */ 150*1ae08745Sheppo &vldc_ops, /* driver specific ops */ 151*1ae08745Sheppo }; 152*1ae08745Sheppo 153*1ae08745Sheppo static struct modlinkage ml = { 154*1ae08745Sheppo MODREV_1, 155*1ae08745Sheppo &md, 156*1ae08745Sheppo NULL 157*1ae08745Sheppo }; 158*1ae08745Sheppo 159*1ae08745Sheppo /* maximum MTU and cookie size tunables */ 160*1ae08745Sheppo uint32_t vldc_max_mtu = VLDC_MAX_MTU; 161*1ae08745Sheppo uint64_t vldc_max_cookie = VLDC_MAX_COOKIE; 162*1ae08745Sheppo 163*1ae08745Sheppo 164*1ae08745Sheppo #ifdef DEBUG 165*1ae08745Sheppo 166*1ae08745Sheppo /* 167*1ae08745Sheppo * Print debug messages 168*1ae08745Sheppo * 169*1ae08745Sheppo * set vldcdbg to 0x7 to enable all messages 170*1ae08745Sheppo * 171*1ae08745Sheppo * 0x4 - Warnings 172*1ae08745Sheppo * 0x2 - All debug messages (most verbose) 173*1ae08745Sheppo * 0x1 - Minimal debug messages 174*1ae08745Sheppo */ 175*1ae08745Sheppo 176*1ae08745Sheppo int vldcdbg = 0x0; 177*1ae08745Sheppo 178*1ae08745Sheppo static void 179*1ae08745Sheppo vldcdebug(const char *fmt, ...) 180*1ae08745Sheppo { 181*1ae08745Sheppo char buf[512]; 182*1ae08745Sheppo va_list ap; 183*1ae08745Sheppo 184*1ae08745Sheppo va_start(ap, fmt); 185*1ae08745Sheppo (void) vsnprintf(buf, sizeof (buf), fmt, ap); 186*1ae08745Sheppo va_end(ap); 187*1ae08745Sheppo 188*1ae08745Sheppo cmn_err(CE_CONT, "?%s", buf); 189*1ae08745Sheppo } 190*1ae08745Sheppo 191*1ae08745Sheppo #define D1 if (vldcdbg & 0x01) vldcdebug 192*1ae08745Sheppo #define D2 if (vldcdbg & 0x02) vldcdebug 193*1ae08745Sheppo #define DWARN if (vldcdbg & 0x04) vldcdebug 194*1ae08745Sheppo 195*1ae08745Sheppo #else /* not DEBUG */ 196*1ae08745Sheppo 197*1ae08745Sheppo #define D1 if (0) printf 198*1ae08745Sheppo #define D2 if (0) printf 199*1ae08745Sheppo #define DWARN if (0) printf 200*1ae08745Sheppo 201*1ae08745Sheppo #endif /* not DEBUG */ 202*1ae08745Sheppo 203*1ae08745Sheppo 204*1ae08745Sheppo /* _init(9E): initialize the loadable module */ 205*1ae08745Sheppo int 206*1ae08745Sheppo _init(void) 207*1ae08745Sheppo { 208*1ae08745Sheppo int error; 209*1ae08745Sheppo 210*1ae08745Sheppo /* init the soft state structure */ 211*1ae08745Sheppo error = ddi_soft_state_init(&vldc_ssp, sizeof (vldc_t), 1); 212*1ae08745Sheppo if (error != 0) { 213*1ae08745Sheppo return (error); 214*1ae08745Sheppo } 215*1ae08745Sheppo 216*1ae08745Sheppo /* Link the driver into the system */ 217*1ae08745Sheppo error = mod_install(&ml); 218*1ae08745Sheppo 219*1ae08745Sheppo return (error); 220*1ae08745Sheppo } 221*1ae08745Sheppo 222*1ae08745Sheppo /* _info(9E): return information about the loadable module */ 223*1ae08745Sheppo int 224*1ae08745Sheppo _info(struct modinfo *modinfop) 225*1ae08745Sheppo { 226*1ae08745Sheppo /* Report status of the dynamically loadable driver module */ 227*1ae08745Sheppo return (mod_info(&ml, modinfop)); 228*1ae08745Sheppo } 229*1ae08745Sheppo 230*1ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 231*1ae08745Sheppo int 232*1ae08745Sheppo _fini(void) 233*1ae08745Sheppo { 234*1ae08745Sheppo int error; 235*1ae08745Sheppo 236*1ae08745Sheppo /* Unlink the driver module from the system */ 237*1ae08745Sheppo if ((error = mod_remove(&ml)) == 0) { 238*1ae08745Sheppo /* 239*1ae08745Sheppo * We have successfully "removed" the driver. 240*1ae08745Sheppo * destroy soft state 241*1ae08745Sheppo */ 242*1ae08745Sheppo ddi_soft_state_fini(&vldc_ssp); 243*1ae08745Sheppo } 244*1ae08745Sheppo 245*1ae08745Sheppo return (error); 246*1ae08745Sheppo } 247*1ae08745Sheppo 248*1ae08745Sheppo /* ldc callback */ 249*1ae08745Sheppo static uint_t 250*1ae08745Sheppo i_vldc_cb(uint64_t event, caddr_t arg) 251*1ae08745Sheppo { 252*1ae08745Sheppo vldc_port_t *vport = (vldc_port_t *)arg; 253*1ae08745Sheppo short pollevents = 0; 254*1ae08745Sheppo int rv; 255*1ae08745Sheppo 256*1ae08745Sheppo D1("i_vldc_cb: callback invoked port=%d, event=0x%lx\n", 257*1ae08745Sheppo vport->number, event); 258*1ae08745Sheppo 259*1ae08745Sheppo if (event & LDC_EVT_UP) { 260*1ae08745Sheppo pollevents |= POLLOUT; 261*1ae08745Sheppo vport->hanged_up = B_FALSE; 262*1ae08745Sheppo 263*1ae08745Sheppo } else if (event & LDC_EVT_DOWN) { 264*1ae08745Sheppo pollevents |= POLLHUP; 265*1ae08745Sheppo vport->hanged_up = B_TRUE; 266*1ae08745Sheppo 267*1ae08745Sheppo } else if (event & LDC_EVT_RESET) { 268*1ae08745Sheppo /* do an ldc_up because we can't be sure the other side will */ 269*1ae08745Sheppo if ((rv = ldc_up(vport->ldc_handle)) != 0) 270*1ae08745Sheppo if (rv != ECONNREFUSED) 271*1ae08745Sheppo DWARN("i_vldc_cb: port@%d failed to" 272*1ae08745Sheppo " bring up LDC channel=%ld, err=%d\n", 273*1ae08745Sheppo vport->number, vport->ldc_id, rv); 274*1ae08745Sheppo } 275*1ae08745Sheppo 276*1ae08745Sheppo if (event & LDC_EVT_READ) 277*1ae08745Sheppo pollevents |= POLLIN; 278*1ae08745Sheppo 279*1ae08745Sheppo if (pollevents != 0) { 280*1ae08745Sheppo D1("i_vldc_cb: port@%d pollwakeup=0x%x\n", 281*1ae08745Sheppo vport->number, pollevents); 282*1ae08745Sheppo pollwakeup(&vport->poll, pollevents); 283*1ae08745Sheppo } 284*1ae08745Sheppo 285*1ae08745Sheppo return (LDC_SUCCESS); 286*1ae08745Sheppo } 287*1ae08745Sheppo 288*1ae08745Sheppo /* mdeg callback */ 289*1ae08745Sheppo static int 290*1ae08745Sheppo i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 291*1ae08745Sheppo { 292*1ae08745Sheppo vldc_t *vldcp; 293*1ae08745Sheppo int idx; 294*1ae08745Sheppo uint64_t portno; 295*1ae08745Sheppo int rv; 296*1ae08745Sheppo md_t *mdp; 297*1ae08745Sheppo mde_cookie_t node; 298*1ae08745Sheppo 299*1ae08745Sheppo if (resp == NULL) { 300*1ae08745Sheppo D1("i_vldc_mdeg_cb: no result returned\n"); 301*1ae08745Sheppo return (MDEG_FAILURE); 302*1ae08745Sheppo } 303*1ae08745Sheppo 304*1ae08745Sheppo vldcp = (vldc_t *)cb_argp; 305*1ae08745Sheppo 306*1ae08745Sheppo mutex_enter(&vldcp->lock); 307*1ae08745Sheppo if (vldcp->detaching == B_TRUE) { 308*1ae08745Sheppo D1("i_vldc_mdeg_cb: detach in progress\n"); 309*1ae08745Sheppo mutex_exit(&vldcp->lock); 310*1ae08745Sheppo return (MDEG_FAILURE); 311*1ae08745Sheppo } 312*1ae08745Sheppo 313*1ae08745Sheppo D1("i_vldc_mdeg_cb: added=%d, removed=%d, matched=%d\n", 314*1ae08745Sheppo resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem); 315*1ae08745Sheppo 316*1ae08745Sheppo /* process added ports */ 317*1ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 318*1ae08745Sheppo mdp = resp->added.mdp; 319*1ae08745Sheppo node = resp->added.mdep[idx]; 320*1ae08745Sheppo 321*1ae08745Sheppo D1("i_vldc_mdeg_cb: processing added node 0x%lx\n", node); 322*1ae08745Sheppo 323*1ae08745Sheppo /* attempt to add a port */ 324*1ae08745Sheppo if ((rv = i_vldc_add_port(vldcp, mdp, node)) != MDEG_SUCCESS) { 325*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to add port, " 326*1ae08745Sheppo "err = %d", rv); 327*1ae08745Sheppo } 328*1ae08745Sheppo } 329*1ae08745Sheppo 330*1ae08745Sheppo /* process removed ports */ 331*1ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 332*1ae08745Sheppo mdp = resp->removed.mdp; 333*1ae08745Sheppo node = resp->removed.mdep[idx]; 334*1ae08745Sheppo 335*1ae08745Sheppo D1("i_vldc_mdeg_cb: processing removed node 0x%lx\n", node); 336*1ae08745Sheppo 337*1ae08745Sheppo /* read in the port's id property */ 338*1ae08745Sheppo if (md_get_prop_val(mdp, node, "id", &portno)) { 339*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: node 0x%lx of " 340*1ae08745Sheppo "removed list has no 'id' property", node); 341*1ae08745Sheppo continue; 342*1ae08745Sheppo } 343*1ae08745Sheppo 344*1ae08745Sheppo /* attempt to remove a port */ 345*1ae08745Sheppo if ((rv = i_vldc_remove_port(vldcp, portno)) != 0) { 346*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to remove " 347*1ae08745Sheppo "port %lu, err %d", portno, rv); 348*1ae08745Sheppo } 349*1ae08745Sheppo } 350*1ae08745Sheppo 351*1ae08745Sheppo /* 352*1ae08745Sheppo * Currently no support for updating already active ports. So, ignore 353*1ae08745Sheppo * the match_curr and match_prev arrays for now. 354*1ae08745Sheppo */ 355*1ae08745Sheppo 356*1ae08745Sheppo mutex_exit(&vldcp->lock); 357*1ae08745Sheppo 358*1ae08745Sheppo return (MDEG_SUCCESS); 359*1ae08745Sheppo } 360*1ae08745Sheppo 361*1ae08745Sheppo /* register callback to mdeg */ 362*1ae08745Sheppo static int 363*1ae08745Sheppo i_vldc_mdeg_register(vldc_t *vldcp) 364*1ae08745Sheppo { 365*1ae08745Sheppo mdeg_prop_spec_t *pspecp; 366*1ae08745Sheppo mdeg_node_spec_t *inst_specp; 367*1ae08745Sheppo mdeg_handle_t mdeg_hdl; 368*1ae08745Sheppo size_t templatesz; 369*1ae08745Sheppo int inst; 370*1ae08745Sheppo char *name; 371*1ae08745Sheppo size_t namesz; 372*1ae08745Sheppo char *nameprop; 373*1ae08745Sheppo int rv; 374*1ae08745Sheppo 375*1ae08745Sheppo /* get the unique vldc instance assigned by the LDom manager */ 376*1ae08745Sheppo inst = ddi_prop_get_int(DDI_DEV_T_ANY, vldcp->dip, 377*1ae08745Sheppo DDI_PROP_DONTPASS, "reg", -1); 378*1ae08745Sheppo if (inst == -1) { 379*1ae08745Sheppo cmn_err(CE_NOTE, "?vldc%d has no 'reg' property", 380*1ae08745Sheppo ddi_get_instance(vldcp->dip)); 381*1ae08745Sheppo return (DDI_FAILURE); 382*1ae08745Sheppo } 383*1ae08745Sheppo 384*1ae08745Sheppo /* get the name of the vldc instance */ 385*1ae08745Sheppo rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip, 386*1ae08745Sheppo DDI_PROP_DONTPASS, "name", &nameprop); 387*1ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 388*1ae08745Sheppo cmn_err(CE_NOTE, "?vldc%d has no 'name' property", 389*1ae08745Sheppo ddi_get_instance(vldcp->dip)); 390*1ae08745Sheppo return (DDI_FAILURE); 391*1ae08745Sheppo } 392*1ae08745Sheppo 393*1ae08745Sheppo D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst); 394*1ae08745Sheppo 395*1ae08745Sheppo /* 396*1ae08745Sheppo * Allocate and initialize a per-instance copy 397*1ae08745Sheppo * of the global property spec array that will 398*1ae08745Sheppo * uniquely identify this vldc instance. 399*1ae08745Sheppo */ 400*1ae08745Sheppo templatesz = sizeof (vldc_prop_template); 401*1ae08745Sheppo pspecp = kmem_alloc(templatesz, KM_SLEEP); 402*1ae08745Sheppo 403*1ae08745Sheppo bcopy(vldc_prop_template, pspecp, templatesz); 404*1ae08745Sheppo 405*1ae08745Sheppo /* copy in the name property */ 406*1ae08745Sheppo namesz = strlen(nameprop) + 1; 407*1ae08745Sheppo name = kmem_alloc(namesz, KM_SLEEP); 408*1ae08745Sheppo 409*1ae08745Sheppo bcopy(nameprop, name, namesz); 410*1ae08745Sheppo VLDC_SET_MDEG_PROP_NAME(pspecp, name); 411*1ae08745Sheppo 412*1ae08745Sheppo /* copy in the instance property */ 413*1ae08745Sheppo VLDC_SET_MDEG_PROP_INST(pspecp, inst); 414*1ae08745Sheppo 415*1ae08745Sheppo /* initialize the complete prop spec structure */ 416*1ae08745Sheppo inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 417*1ae08745Sheppo inst_specp->namep = "virtual-device"; 418*1ae08745Sheppo inst_specp->specp = pspecp; 419*1ae08745Sheppo 420*1ae08745Sheppo /* perform the registration */ 421*1ae08745Sheppo rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb, 422*1ae08745Sheppo vldcp, &mdeg_hdl); 423*1ae08745Sheppo 424*1ae08745Sheppo if (rv != MDEG_SUCCESS) { 425*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register " 426*1ae08745Sheppo "failed, err = %d", rv); 427*1ae08745Sheppo kmem_free(name, namesz); 428*1ae08745Sheppo kmem_free(pspecp, templatesz); 429*1ae08745Sheppo kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 430*1ae08745Sheppo return (DDI_FAILURE); 431*1ae08745Sheppo } 432*1ae08745Sheppo 433*1ae08745Sheppo /* save off data that will be needed later */ 434*1ae08745Sheppo vldcp->inst_spec = inst_specp; 435*1ae08745Sheppo vldcp->mdeg_hdl = mdeg_hdl; 436*1ae08745Sheppo 437*1ae08745Sheppo return (DDI_SUCCESS); 438*1ae08745Sheppo } 439*1ae08745Sheppo 440*1ae08745Sheppo /* unregister callback from mdeg */ 441*1ae08745Sheppo static int 442*1ae08745Sheppo i_vldc_mdeg_unregister(vldc_t *vldcp) 443*1ae08745Sheppo { 444*1ae08745Sheppo char *name; 445*1ae08745Sheppo int rv; 446*1ae08745Sheppo 447*1ae08745Sheppo D1("i_vldc_mdeg_unregister: hdl=0x%lx\n", vldcp->mdeg_hdl); 448*1ae08745Sheppo 449*1ae08745Sheppo rv = mdeg_unregister(vldcp->mdeg_hdl); 450*1ae08745Sheppo if (rv != MDEG_SUCCESS) { 451*1ae08745Sheppo return (rv); 452*1ae08745Sheppo } 453*1ae08745Sheppo 454*1ae08745Sheppo /* 455*1ae08745Sheppo * Clean up cached MDEG data 456*1ae08745Sheppo */ 457*1ae08745Sheppo name = VLDC_MDEG_PROP_NAME(vldcp->inst_spec->specp); 458*1ae08745Sheppo if (name != NULL) { 459*1ae08745Sheppo kmem_free(name, strlen(name) + 1); 460*1ae08745Sheppo } 461*1ae08745Sheppo kmem_free(vldcp->inst_spec->specp, sizeof (vldc_prop_template)); 462*1ae08745Sheppo vldcp->inst_spec->specp = NULL; 463*1ae08745Sheppo 464*1ae08745Sheppo kmem_free(vldcp->inst_spec, sizeof (mdeg_node_spec_t)); 465*1ae08745Sheppo vldcp->inst_spec = NULL; 466*1ae08745Sheppo 467*1ae08745Sheppo return (MDEG_SUCCESS); 468*1ae08745Sheppo } 469*1ae08745Sheppo 470*1ae08745Sheppo static int 471*1ae08745Sheppo i_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id) 472*1ae08745Sheppo { 473*1ae08745Sheppo int num_nodes, nchan; 474*1ae08745Sheppo size_t listsz; 475*1ae08745Sheppo mde_cookie_t *listp; 476*1ae08745Sheppo 477*1ae08745Sheppo /* 478*1ae08745Sheppo * Find the channel-endpoint node(s) (which should be under this 479*1ae08745Sheppo * port node) which contain the channel id(s). 480*1ae08745Sheppo */ 481*1ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 482*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of " 483*1ae08745Sheppo "channel-endpoint nodes found (%d)", num_nodes); 484*1ae08745Sheppo return (-1); 485*1ae08745Sheppo } 486*1ae08745Sheppo 487*1ae08745Sheppo /* allocate space for node list */ 488*1ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 489*1ae08745Sheppo listp = kmem_alloc(listsz, KM_SLEEP); 490*1ae08745Sheppo 491*1ae08745Sheppo nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"), 492*1ae08745Sheppo md_find_name(mdp, "fwd"), listp); 493*1ae08745Sheppo 494*1ae08745Sheppo if (nchan <= 0) { 495*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint" 496*1ae08745Sheppo " nodes found"); 497*1ae08745Sheppo kmem_free(listp, listsz); 498*1ae08745Sheppo return (-1); 499*1ae08745Sheppo } 500*1ae08745Sheppo 501*1ae08745Sheppo D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan); 502*1ae08745Sheppo 503*1ae08745Sheppo /* use property from first node found */ 504*1ae08745Sheppo if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) { 505*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint " 506*1ae08745Sheppo "has no 'id' property"); 507*1ae08745Sheppo kmem_free(listp, listsz); 508*1ae08745Sheppo return (-1); 509*1ae08745Sheppo } 510*1ae08745Sheppo 511*1ae08745Sheppo kmem_free(listp, listsz); 512*1ae08745Sheppo 513*1ae08745Sheppo return (0); 514*1ae08745Sheppo } 515*1ae08745Sheppo 516*1ae08745Sheppo /* add a vldc port */ 517*1ae08745Sheppo static int 518*1ae08745Sheppo i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node) 519*1ae08745Sheppo { 520*1ae08745Sheppo vldc_port_t *vport; 521*1ae08745Sheppo char *sname; 522*1ae08745Sheppo uint64_t portno; 523*1ae08745Sheppo int vldc_inst; 524*1ae08745Sheppo minor_t minor; 525*1ae08745Sheppo int minor_idx; 526*1ae08745Sheppo boolean_t new_minor; 527*1ae08745Sheppo int rv; 528*1ae08745Sheppo 529*1ae08745Sheppo /* read in the port's id property */ 530*1ae08745Sheppo if (md_get_prop_val(mdp, node, "id", &portno)) { 531*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: node 0x%lx of added " 532*1ae08745Sheppo "list has no 'id' property", node); 533*1ae08745Sheppo return (MDEG_FAILURE); 534*1ae08745Sheppo } 535*1ae08745Sheppo 536*1ae08745Sheppo if (portno >= VLDC_MAX_PORTS) { 537*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: found port number (%lu) " 538*1ae08745Sheppo "larger than maximum supported number of ports", portno); 539*1ae08745Sheppo return (MDEG_FAILURE); 540*1ae08745Sheppo } 541*1ae08745Sheppo 542*1ae08745Sheppo vport = &(vldcp->port[portno]); 543*1ae08745Sheppo 544*1ae08745Sheppo if (vport->minorp != NULL) { 545*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)" 546*1ae08745Sheppo " which is already bound", portno); 547*1ae08745Sheppo return (MDEG_FAILURE); 548*1ae08745Sheppo } 549*1ae08745Sheppo 550*1ae08745Sheppo vport->number = portno; 551*1ae08745Sheppo 552*1ae08745Sheppo /* get all channels for this device (currently only one) */ 553*1ae08745Sheppo if (i_vldc_get_port_channel(mdp, node, &vport->ldc_id) == -1) { 554*1ae08745Sheppo return (MDEG_FAILURE); 555*1ae08745Sheppo } 556*1ae08745Sheppo 557*1ae08745Sheppo /* set the default MTU */ 558*1ae08745Sheppo vport->mtu = VLDC_DEFAULT_MTU; 559*1ae08745Sheppo 560*1ae08745Sheppo /* get the service being exported by this port */ 561*1ae08745Sheppo if (md_get_prop_str(mdp, node, "vldc-svc-name", &sname)) { 562*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: vdevice has no " 563*1ae08745Sheppo "'vldc-svc-name' property"); 564*1ae08745Sheppo return (MDEG_FAILURE); 565*1ae08745Sheppo } 566*1ae08745Sheppo 567*1ae08745Sheppo /* minor number look up */ 568*1ae08745Sheppo for (minor_idx = 0; minor_idx < vldcp->minors_assigned; 569*1ae08745Sheppo minor_idx++) { 570*1ae08745Sheppo if (strcmp(vldcp->minor_tbl[minor_idx].sname, sname) == 0) { 571*1ae08745Sheppo /* found previously assigned minor number */ 572*1ae08745Sheppo break; 573*1ae08745Sheppo } 574*1ae08745Sheppo } 575*1ae08745Sheppo 576*1ae08745Sheppo new_minor = B_FALSE; 577*1ae08745Sheppo if (minor_idx == vldcp->minors_assigned) { 578*1ae08745Sheppo /* end of lookup - assign new minor number */ 579*1ae08745Sheppo if (vldcp->minors_assigned == VLDC_MAX_MINORS) { 580*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: too many minor " 581*1ae08745Sheppo "nodes (%d)", minor_idx); 582*1ae08745Sheppo return (MDEG_FAILURE); 583*1ae08745Sheppo } 584*1ae08745Sheppo 585*1ae08745Sheppo (void) strlcpy(vldcp->minor_tbl[minor_idx].sname, 586*1ae08745Sheppo sname, MAXPATHLEN); 587*1ae08745Sheppo 588*1ae08745Sheppo vldcp->minors_assigned++; 589*1ae08745Sheppo new_minor = B_TRUE; 590*1ae08745Sheppo } 591*1ae08745Sheppo 592*1ae08745Sheppo ASSERT(vldcp->minor_tbl[minor_idx].portno == VLDC_INVALID_PORTNO); 593*1ae08745Sheppo 594*1ae08745Sheppo vport->minorp = &vldcp->minor_tbl[minor_idx]; 595*1ae08745Sheppo vldcp->minor_tbl[minor_idx].portno = portno; 596*1ae08745Sheppo vldcp->minor_tbl[minor_idx].in_use = 0; 597*1ae08745Sheppo 598*1ae08745Sheppo D1("i_vldc_add_port: port@%d mtu=%d, ldc=%ld, service=%s\n", 599*1ae08745Sheppo vport->number, vport->mtu, vport->ldc_id, sname); 600*1ae08745Sheppo 601*1ae08745Sheppo /* 602*1ae08745Sheppo * Create a minor node. The minor number is 603*1ae08745Sheppo * (vldc_inst << VLDC_INST_SHIFT) | minor_idx 604*1ae08745Sheppo */ 605*1ae08745Sheppo vldc_inst = ddi_get_instance(vldcp->dip); 606*1ae08745Sheppo 607*1ae08745Sheppo minor = (vldc_inst << VLDC_INST_SHIFT) | (minor_idx); 608*1ae08745Sheppo 609*1ae08745Sheppo rv = ddi_create_minor_node(vldcp->dip, sname, S_IFCHR, 610*1ae08745Sheppo minor, DDI_NT_SERIAL, 0); 611*1ae08745Sheppo 612*1ae08745Sheppo if (rv != DDI_SUCCESS) { 613*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_add_port: failed to create minor" 614*1ae08745Sheppo "node (%u), err = %d", minor, rv); 615*1ae08745Sheppo vldcp->minor_tbl[minor_idx].portno = VLDC_INVALID_PORTNO; 616*1ae08745Sheppo if (new_minor) { 617*1ae08745Sheppo vldcp->minors_assigned--; 618*1ae08745Sheppo } 619*1ae08745Sheppo return (MDEG_FAILURE); 620*1ae08745Sheppo } 621*1ae08745Sheppo 622*1ae08745Sheppo /* 623*1ae08745Sheppo * The port is now bound to a minor node and is initially in the 624*1ae08745Sheppo * closed state. 625*1ae08745Sheppo */ 626*1ae08745Sheppo vport->status = VLDC_PORT_CLOSED; 627*1ae08745Sheppo 628*1ae08745Sheppo D1("i_vldc_add_port: port %lu initialized\n", portno); 629*1ae08745Sheppo 630*1ae08745Sheppo return (MDEG_SUCCESS); 631*1ae08745Sheppo } 632*1ae08745Sheppo 633*1ae08745Sheppo /* remove a vldc port */ 634*1ae08745Sheppo static int 635*1ae08745Sheppo i_vldc_remove_port(vldc_t *vldcp, uint_t portno) 636*1ae08745Sheppo { 637*1ae08745Sheppo vldc_port_t *vport; 638*1ae08745Sheppo vldc_minor_t *vminor; 639*1ae08745Sheppo 640*1ae08745Sheppo vport = &(vldcp->port[portno]); 641*1ae08745Sheppo vminor = vport->minorp; 642*1ae08745Sheppo if (vminor == NULL) { 643*1ae08745Sheppo cmn_err(CE_NOTE, "?i_vldc_remove_port: trying to remove a " 644*1ae08745Sheppo "port (%u) which is not bound", portno); 645*1ae08745Sheppo return (MDEG_FAILURE); 646*1ae08745Sheppo } 647*1ae08745Sheppo 648*1ae08745Sheppo /* 649*1ae08745Sheppo * Make sure that all new attempts to open or use the minor node 650*1ae08745Sheppo * associated with the port will fail. 651*1ae08745Sheppo */ 652*1ae08745Sheppo mutex_enter(&vminor->lock); 653*1ae08745Sheppo vminor->portno = VLDC_INVALID_PORTNO; 654*1ae08745Sheppo mutex_exit(&vminor->lock); 655*1ae08745Sheppo 656*1ae08745Sheppo /* send hangup to anyone polling */ 657*1ae08745Sheppo pollwakeup(&vport->poll, POLLHUP); 658*1ae08745Sheppo 659*1ae08745Sheppo /* Now wait for all current users of the minor node to finish. */ 660*1ae08745Sheppo mutex_enter(&vminor->lock); 661*1ae08745Sheppo while (vminor->in_use > 0) { 662*1ae08745Sheppo cv_wait(&vminor->cv, &vminor->lock); 663*1ae08745Sheppo } 664*1ae08745Sheppo 665*1ae08745Sheppo if ((vport->status == VLDC_PORT_READY) || 666*1ae08745Sheppo (vport->status == VLDC_PORT_OPEN)) { 667*1ae08745Sheppo /* close the port before it is torn down */ 668*1ae08745Sheppo (void) i_vldc_close_port(vldcp, portno); 669*1ae08745Sheppo } 670*1ae08745Sheppo 671*1ae08745Sheppo /* remove minor node */ 672*1ae08745Sheppo ddi_remove_minor_node(vldcp->dip, vport->minorp->sname); 673*1ae08745Sheppo vport->minorp = NULL; 674*1ae08745Sheppo 675*1ae08745Sheppo mutex_exit(&vminor->lock); 676*1ae08745Sheppo 677*1ae08745Sheppo D1("i_vldc_remove_port: removed vldc port %u\n", portno); 678*1ae08745Sheppo 679*1ae08745Sheppo return (MDEG_SUCCESS); 680*1ae08745Sheppo } 681*1ae08745Sheppo 682*1ae08745Sheppo /* close a ldc channel */ 683*1ae08745Sheppo static int 684*1ae08745Sheppo i_vldc_ldc_close(vldc_port_t *vport) 685*1ae08745Sheppo { 686*1ae08745Sheppo int rv = 0; 687*1ae08745Sheppo int err; 688*1ae08745Sheppo 689*1ae08745Sheppo err = ldc_close(vport->ldc_handle); 690*1ae08745Sheppo if (err != 0) 691*1ae08745Sheppo rv = err; 692*1ae08745Sheppo err = ldc_unreg_callback(vport->ldc_handle); 693*1ae08745Sheppo if ((err != 0) && (rv != 0)) 694*1ae08745Sheppo rv = err; 695*1ae08745Sheppo err = ldc_fini(vport->ldc_handle); 696*1ae08745Sheppo if ((err != 0) && (rv != 0)) 697*1ae08745Sheppo rv = err; 698*1ae08745Sheppo 699*1ae08745Sheppo return (rv); 700*1ae08745Sheppo } 701*1ae08745Sheppo 702*1ae08745Sheppo /* close a vldc port */ 703*1ae08745Sheppo static int 704*1ae08745Sheppo i_vldc_close_port(vldc_t *vldcp, uint_t portno) 705*1ae08745Sheppo { 706*1ae08745Sheppo vldc_port_t *vport; 707*1ae08745Sheppo int rv; 708*1ae08745Sheppo 709*1ae08745Sheppo vport = &(vldcp->port[portno]); 710*1ae08745Sheppo 711*1ae08745Sheppo ASSERT(MUTEX_HELD(&vport->minorp->lock)); 712*1ae08745Sheppo 713*1ae08745Sheppo if (vport->status == VLDC_PORT_CLOSED) { 714*1ae08745Sheppo /* nothing to do */ 715*1ae08745Sheppo DWARN("i_vldc_close_port: port %d in an unexpected " 716*1ae08745Sheppo "state (%d)\n", portno, vport->status); 717*1ae08745Sheppo return (DDI_SUCCESS); 718*1ae08745Sheppo } 719*1ae08745Sheppo 720*1ae08745Sheppo rv = DDI_SUCCESS; 721*1ae08745Sheppo if (vport->status == VLDC_PORT_READY) { 722*1ae08745Sheppo rv = i_vldc_ldc_close(vport); 723*1ae08745Sheppo } else { 724*1ae08745Sheppo ASSERT(vport->status == VLDC_PORT_OPEN); 725*1ae08745Sheppo } 726*1ae08745Sheppo 727*1ae08745Sheppo /* free memory */ 728*1ae08745Sheppo kmem_free(vport->send_buf, vport->mtu); 729*1ae08745Sheppo kmem_free(vport->recv_buf, vport->mtu); 730*1ae08745Sheppo 731*1ae08745Sheppo vport->status = VLDC_PORT_CLOSED; 732*1ae08745Sheppo 733*1ae08745Sheppo return (rv); 734*1ae08745Sheppo } 735*1ae08745Sheppo 736*1ae08745Sheppo /* 737*1ae08745Sheppo * attach(9E): attach a device to the system. 738*1ae08745Sheppo * called once for each instance of the device on the system. 739*1ae08745Sheppo */ 740*1ae08745Sheppo static int 741*1ae08745Sheppo vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 742*1ae08745Sheppo { 743*1ae08745Sheppo int i, instance; 744*1ae08745Sheppo vldc_t *vldcp; 745*1ae08745Sheppo 746*1ae08745Sheppo switch (cmd) { 747*1ae08745Sheppo 748*1ae08745Sheppo case DDI_ATTACH: 749*1ae08745Sheppo 750*1ae08745Sheppo instance = ddi_get_instance(dip); 751*1ae08745Sheppo 752*1ae08745Sheppo if (ddi_soft_state_zalloc(vldc_ssp, instance) != DDI_SUCCESS) { 753*1ae08745Sheppo return (DDI_FAILURE); 754*1ae08745Sheppo } 755*1ae08745Sheppo 756*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 757*1ae08745Sheppo if (vldcp == NULL) { 758*1ae08745Sheppo ddi_soft_state_free(vldc_ssp, instance); 759*1ae08745Sheppo return (ENXIO); 760*1ae08745Sheppo } 761*1ae08745Sheppo 762*1ae08745Sheppo D1("vldc_attach: DDI_ATTACH instance=%d\n", instance); 763*1ae08745Sheppo 764*1ae08745Sheppo mutex_init(&vldcp->lock, NULL, MUTEX_DRIVER, NULL); 765*1ae08745Sheppo vldcp->dip = dip; 766*1ae08745Sheppo vldcp->detaching = B_FALSE; 767*1ae08745Sheppo 768*1ae08745Sheppo for (i = 0; i < VLDC_MAX_PORTS; i++) { 769*1ae08745Sheppo /* No minor node association to start with */ 770*1ae08745Sheppo vldcp->port[i].minorp = NULL; 771*1ae08745Sheppo } 772*1ae08745Sheppo 773*1ae08745Sheppo for (i = 0; i < VLDC_MAX_MINORS; i++) { 774*1ae08745Sheppo mutex_init(&(vldcp->minor_tbl[i].lock), NULL, 775*1ae08745Sheppo MUTEX_DRIVER, NULL); 776*1ae08745Sheppo cv_init(&(vldcp->minor_tbl[i].cv), NULL, 777*1ae08745Sheppo CV_DRIVER, NULL); 778*1ae08745Sheppo /* No port association to start with */ 779*1ae08745Sheppo vldcp->minor_tbl[i].portno = VLDC_INVALID_PORTNO; 780*1ae08745Sheppo } 781*1ae08745Sheppo 782*1ae08745Sheppo /* Register for MD update notification */ 783*1ae08745Sheppo if (i_vldc_mdeg_register(vldcp) != DDI_SUCCESS) { 784*1ae08745Sheppo ddi_soft_state_free(vldc_ssp, instance); 785*1ae08745Sheppo return (DDI_FAILURE); 786*1ae08745Sheppo } 787*1ae08745Sheppo 788*1ae08745Sheppo return (DDI_SUCCESS); 789*1ae08745Sheppo 790*1ae08745Sheppo case DDI_RESUME: 791*1ae08745Sheppo 792*1ae08745Sheppo return (DDI_SUCCESS); 793*1ae08745Sheppo 794*1ae08745Sheppo default: 795*1ae08745Sheppo 796*1ae08745Sheppo return (DDI_FAILURE); 797*1ae08745Sheppo } 798*1ae08745Sheppo } 799*1ae08745Sheppo 800*1ae08745Sheppo /* 801*1ae08745Sheppo * detach(9E): detach a device from the system. 802*1ae08745Sheppo */ 803*1ae08745Sheppo static int 804*1ae08745Sheppo vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 805*1ae08745Sheppo { 806*1ae08745Sheppo int i, instance; 807*1ae08745Sheppo vldc_t *vldcp; 808*1ae08745Sheppo 809*1ae08745Sheppo switch (cmd) { 810*1ae08745Sheppo 811*1ae08745Sheppo case DDI_DETACH: 812*1ae08745Sheppo 813*1ae08745Sheppo instance = ddi_get_instance(dip); 814*1ae08745Sheppo 815*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 816*1ae08745Sheppo if (vldcp == NULL) { 817*1ae08745Sheppo return (DDI_FAILURE); 818*1ae08745Sheppo } 819*1ae08745Sheppo 820*1ae08745Sheppo D1("vldc_detach: DDI_DETACH instance=%d\n", instance); 821*1ae08745Sheppo 822*1ae08745Sheppo mutex_enter(&vldcp->lock); 823*1ae08745Sheppo 824*1ae08745Sheppo /* Fail the detach if all ports have not been removed. */ 825*1ae08745Sheppo for (i = 0; i < VLDC_MAX_MINORS; i++) { 826*1ae08745Sheppo if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 827*1ae08745Sheppo D1("vldc_detach: vldc@%d:%d is bound, " 828*1ae08745Sheppo "detach failed\n", 829*1ae08745Sheppo instance, vldcp->minor_tbl[i].portno); 830*1ae08745Sheppo mutex_exit(&vldcp->lock); 831*1ae08745Sheppo return (DDI_FAILURE); 832*1ae08745Sheppo } 833*1ae08745Sheppo } 834*1ae08745Sheppo 835*1ae08745Sheppo /* 836*1ae08745Sheppo * Prevent MDEG from adding new ports before the callback can 837*1ae08745Sheppo * be unregistered. The lock can't be held accross the 838*1ae08745Sheppo * unregistration call because a callback may be in progress 839*1ae08745Sheppo * and blocked on the lock. 840*1ae08745Sheppo */ 841*1ae08745Sheppo vldcp->detaching = B_TRUE; 842*1ae08745Sheppo 843*1ae08745Sheppo mutex_exit(&vldcp->lock); 844*1ae08745Sheppo 845*1ae08745Sheppo if (i_vldc_mdeg_unregister(vldcp) != MDEG_SUCCESS) { 846*1ae08745Sheppo vldcp->detaching = B_FALSE; 847*1ae08745Sheppo return (DDI_FAILURE); 848*1ae08745Sheppo } 849*1ae08745Sheppo 850*1ae08745Sheppo /* Tear down all bound ports and free resources. */ 851*1ae08745Sheppo for (i = 0; i < VLDC_MAX_MINORS; i++) { 852*1ae08745Sheppo if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 853*1ae08745Sheppo (void) i_vldc_remove_port(vldcp, i); 854*1ae08745Sheppo } 855*1ae08745Sheppo mutex_destroy(&(vldcp->minor_tbl[i].lock)); 856*1ae08745Sheppo cv_destroy(&(vldcp->minor_tbl[i].cv)); 857*1ae08745Sheppo } 858*1ae08745Sheppo 859*1ae08745Sheppo mutex_destroy(&vldcp->lock); 860*1ae08745Sheppo ddi_soft_state_free(vldc_ssp, instance); 861*1ae08745Sheppo 862*1ae08745Sheppo return (DDI_SUCCESS); 863*1ae08745Sheppo 864*1ae08745Sheppo case DDI_SUSPEND: 865*1ae08745Sheppo 866*1ae08745Sheppo return (DDI_SUCCESS); 867*1ae08745Sheppo 868*1ae08745Sheppo default: 869*1ae08745Sheppo 870*1ae08745Sheppo return (DDI_FAILURE); 871*1ae08745Sheppo } 872*1ae08745Sheppo } 873*1ae08745Sheppo 874*1ae08745Sheppo /* cb_open */ 875*1ae08745Sheppo static int 876*1ae08745Sheppo vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred) 877*1ae08745Sheppo { 878*1ae08745Sheppo _NOTE(ARGUNUSED(flag, otyp, cred)) 879*1ae08745Sheppo 880*1ae08745Sheppo int instance; 881*1ae08745Sheppo minor_t minor; 882*1ae08745Sheppo uint64_t portno; 883*1ae08745Sheppo vldc_t *vldcp; 884*1ae08745Sheppo vldc_port_t *vport; 885*1ae08745Sheppo vldc_minor_t *vminor; 886*1ae08745Sheppo 887*1ae08745Sheppo minor = getminor(*devp); 888*1ae08745Sheppo instance = VLDCINST(minor); 889*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 890*1ae08745Sheppo if (vldcp == NULL) 891*1ae08745Sheppo return (ENXIO); 892*1ae08745Sheppo 893*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 894*1ae08745Sheppo mutex_enter(&vminor->lock); 895*1ae08745Sheppo portno = vminor->portno; 896*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 897*1ae08745Sheppo mutex_exit(&vminor->lock); 898*1ae08745Sheppo return (ENXIO); 899*1ae08745Sheppo } 900*1ae08745Sheppo 901*1ae08745Sheppo vport = &(vldcp->port[portno]); 902*1ae08745Sheppo 903*1ae08745Sheppo D1("vldc_open: opening vldc@%d:%lu\n", instance, portno); 904*1ae08745Sheppo 905*1ae08745Sheppo if (vport->status != VLDC_PORT_CLOSED) { 906*1ae08745Sheppo mutex_exit(&vminor->lock); 907*1ae08745Sheppo return (EBUSY); 908*1ae08745Sheppo } 909*1ae08745Sheppo 910*1ae08745Sheppo vport->recv_buf = kmem_alloc(vport->mtu, KM_SLEEP); 911*1ae08745Sheppo vport->send_buf = kmem_alloc(vport->mtu, KM_SLEEP); 912*1ae08745Sheppo 913*1ae08745Sheppo vport->is_stream = B_FALSE; /* assume not a stream */ 914*1ae08745Sheppo vport->hanged_up = B_FALSE; 915*1ae08745Sheppo 916*1ae08745Sheppo vport->status = VLDC_PORT_OPEN; 917*1ae08745Sheppo 918*1ae08745Sheppo mutex_exit(&vminor->lock); 919*1ae08745Sheppo 920*1ae08745Sheppo return (DDI_SUCCESS); 921*1ae08745Sheppo } 922*1ae08745Sheppo 923*1ae08745Sheppo /* cb_close */ 924*1ae08745Sheppo static int 925*1ae08745Sheppo vldc_close(dev_t dev, int flag, int otyp, cred_t *cred) 926*1ae08745Sheppo { 927*1ae08745Sheppo _NOTE(ARGUNUSED(flag, otyp, cred)) 928*1ae08745Sheppo 929*1ae08745Sheppo int instance; 930*1ae08745Sheppo minor_t minor; 931*1ae08745Sheppo uint64_t portno; 932*1ae08745Sheppo vldc_t *vldcp; 933*1ae08745Sheppo vldc_minor_t *vminor; 934*1ae08745Sheppo int rv; 935*1ae08745Sheppo 936*1ae08745Sheppo minor = getminor(dev); 937*1ae08745Sheppo instance = VLDCINST(minor); 938*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 939*1ae08745Sheppo if (vldcp == NULL) { 940*1ae08745Sheppo return (ENXIO); 941*1ae08745Sheppo } 942*1ae08745Sheppo 943*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 944*1ae08745Sheppo mutex_enter(&vminor->lock); 945*1ae08745Sheppo portno = vminor->portno; 946*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 947*1ae08745Sheppo mutex_exit(&vminor->lock); 948*1ae08745Sheppo return (ENOLINK); 949*1ae08745Sheppo } 950*1ae08745Sheppo 951*1ae08745Sheppo D1("vldc_close: closing vldc@%d:%lu\n", instance, portno); 952*1ae08745Sheppo 953*1ae08745Sheppo rv = i_vldc_close_port(vldcp, portno); 954*1ae08745Sheppo 955*1ae08745Sheppo mutex_exit(&vminor->lock); 956*1ae08745Sheppo 957*1ae08745Sheppo return (rv); 958*1ae08745Sheppo } 959*1ae08745Sheppo 960*1ae08745Sheppo static int 961*1ae08745Sheppo vldc_set_ldc_mode(vldc_port_t *vport, vldc_t *vldcp, int channel_mode) 962*1ae08745Sheppo { 963*1ae08745Sheppo ldc_attr_t attr; 964*1ae08745Sheppo int rv; 965*1ae08745Sheppo 966*1ae08745Sheppo ASSERT(MUTEX_HELD(&vport->minorp->lock)); 967*1ae08745Sheppo 968*1ae08745Sheppo /* validate mode */ 969*1ae08745Sheppo switch (channel_mode) { 970*1ae08745Sheppo case LDC_MODE_STREAM: 971*1ae08745Sheppo vport->is_stream = B_TRUE; 972*1ae08745Sheppo break; 973*1ae08745Sheppo case LDC_MODE_RAW: 974*1ae08745Sheppo case LDC_MODE_UNRELIABLE: 975*1ae08745Sheppo case LDC_MODE_RELIABLE: 976*1ae08745Sheppo vport->is_stream = B_FALSE; 977*1ae08745Sheppo break; 978*1ae08745Sheppo default: 979*1ae08745Sheppo return (EINVAL); 980*1ae08745Sheppo } 981*1ae08745Sheppo 982*1ae08745Sheppo if (vport->status == VLDC_PORT_READY) { 983*1ae08745Sheppo rv = i_vldc_ldc_close(vport); 984*1ae08745Sheppo vport->status = VLDC_PORT_OPEN; 985*1ae08745Sheppo if (rv != 0) { 986*1ae08745Sheppo DWARN("vldc_set_ldc_mode: i_vldc_ldc_close " 987*1ae08745Sheppo "failed, rv=%d\n", rv); 988*1ae08745Sheppo return (rv); 989*1ae08745Sheppo } 990*1ae08745Sheppo } 991*1ae08745Sheppo 992*1ae08745Sheppo D1("vldc_set_ldc_mode: vport status %d, mode %d\n", 993*1ae08745Sheppo vport->status, channel_mode); 994*1ae08745Sheppo 995*1ae08745Sheppo vport->ldc_mode = channel_mode; 996*1ae08745Sheppo 997*1ae08745Sheppo /* initialize the channel */ 998*1ae08745Sheppo attr.devclass = LDC_DEV_SERIAL; 999*1ae08745Sheppo attr.instance = ddi_get_instance(vldcp->dip); 1000*1ae08745Sheppo attr.qlen = VLDC_QUEUE_LEN; 1001*1ae08745Sheppo attr.mode = vport->ldc_mode; 1002*1ae08745Sheppo 1003*1ae08745Sheppo if ((rv = ldc_init(vport->ldc_id, &attr, 1004*1ae08745Sheppo &vport->ldc_handle)) != 0) { 1005*1ae08745Sheppo DWARN("vldc_ioctl_opt_op: ldc_init failed, rv=%d\n", rv); 1006*1ae08745Sheppo goto error_init; 1007*1ae08745Sheppo } 1008*1ae08745Sheppo 1009*1ae08745Sheppo /* register it */ 1010*1ae08745Sheppo if ((rv = ldc_reg_callback(vport->ldc_handle, 1011*1ae08745Sheppo i_vldc_cb, (caddr_t)vport)) != 0) { 1012*1ae08745Sheppo DWARN("vldc_ioctl_opt_op: ldc_reg_callback failed, rv=%d\n", 1013*1ae08745Sheppo rv); 1014*1ae08745Sheppo goto error_reg; 1015*1ae08745Sheppo } 1016*1ae08745Sheppo 1017*1ae08745Sheppo /* open the channel */ 1018*1ae08745Sheppo if ((rv = ldc_open(vport->ldc_handle)) != 0) { 1019*1ae08745Sheppo DWARN("vldc_ioctl_opt_op: ldc_open failed, rv=%d\n", rv); 1020*1ae08745Sheppo goto error_open; 1021*1ae08745Sheppo } 1022*1ae08745Sheppo 1023*1ae08745Sheppo vport->status = VLDC_PORT_READY; 1024*1ae08745Sheppo 1025*1ae08745Sheppo /* 1026*1ae08745Sheppo * Attempt to bring the channel up, but do not 1027*1ae08745Sheppo * fail if the other end is not up yet. 1028*1ae08745Sheppo */ 1029*1ae08745Sheppo rv = ldc_up(vport->ldc_handle); 1030*1ae08745Sheppo 1031*1ae08745Sheppo if (rv == ECONNREFUSED) { 1032*1ae08745Sheppo D1("vldc_ioctl_opt_op: remote endpoint not up yet\n"); 1033*1ae08745Sheppo } else if (rv != 0) { 1034*1ae08745Sheppo DWARN("vldc_ioctl_opt_op: ldc_up failed, rv=%d\n", rv); 1035*1ae08745Sheppo goto error_up; 1036*1ae08745Sheppo } 1037*1ae08745Sheppo 1038*1ae08745Sheppo D1("vldc_ioctl_opt_op: ldc %ld initialized successfully\n", 1039*1ae08745Sheppo vport->ldc_id); 1040*1ae08745Sheppo 1041*1ae08745Sheppo return (0); 1042*1ae08745Sheppo 1043*1ae08745Sheppo error_up: 1044*1ae08745Sheppo vport->status = VLDC_PORT_OPEN; 1045*1ae08745Sheppo (void) ldc_close(vport->ldc_handle); 1046*1ae08745Sheppo error_open: 1047*1ae08745Sheppo (void) ldc_unreg_callback(vport->ldc_handle); 1048*1ae08745Sheppo error_reg: 1049*1ae08745Sheppo (void) ldc_fini(vport->ldc_handle); 1050*1ae08745Sheppo error_init: 1051*1ae08745Sheppo return (rv); 1052*1ae08745Sheppo } 1053*1ae08745Sheppo 1054*1ae08745Sheppo /* ioctl to read cookie */ 1055*1ae08745Sheppo static int 1056*1ae08745Sheppo i_vldc_ioctl_read_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1057*1ae08745Sheppo int mode) 1058*1ae08745Sheppo { 1059*1ae08745Sheppo vldc_data_t copy_info; 1060*1ae08745Sheppo caddr_t buf; 1061*1ae08745Sheppo uint64_t len; 1062*1ae08745Sheppo int rv; 1063*1ae08745Sheppo 1064*1ae08745Sheppo if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) == -1) { 1065*1ae08745Sheppo return (EFAULT); 1066*1ae08745Sheppo } 1067*1ae08745Sheppo 1068*1ae08745Sheppo len = copy_info.length; 1069*1ae08745Sheppo if (len > vldc_max_cookie) { 1070*1ae08745Sheppo return (EINVAL); 1071*1ae08745Sheppo } 1072*1ae08745Sheppo 1073*1ae08745Sheppo /* allocate a temporary buffer */ 1074*1ae08745Sheppo buf = kmem_alloc(len, KM_SLEEP); 1075*1ae08745Sheppo 1076*1ae08745Sheppo mutex_enter(&vport->minorp->lock); 1077*1ae08745Sheppo 1078*1ae08745Sheppo D2("i_vldc_ioctl_read_cookie: vldc@%d:%d reading from 0x%lx " 1079*1ae08745Sheppo "size 0x%lx to 0x%lx\n", vldc_instance, vport->number, 1080*1ae08745Sheppo copy_info.dst_addr, copy_info.length, copy_info.src_addr); 1081*1ae08745Sheppo 1082*1ae08745Sheppo /* read from the HV into the temporary buffer */ 1083*1ae08745Sheppo rv = ldc_mem_rdwr_pa(vport->ldc_handle, buf, &len, 1084*1ae08745Sheppo (caddr_t)copy_info.dst_addr, LDC_COPY_IN); 1085*1ae08745Sheppo if (rv != 0) { 1086*1ae08745Sheppo DWARN("i_vldc_ioctl_read_cookie: vldc@%d:%d cannot read " 1087*1ae08745Sheppo "address 0x%lx, rv=%d\n", vldc_instance, vport->number, 1088*1ae08745Sheppo copy_info.dst_addr, rv); 1089*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1090*1ae08745Sheppo kmem_free(buf, copy_info.length); 1091*1ae08745Sheppo return (EFAULT); 1092*1ae08745Sheppo } 1093*1ae08745Sheppo 1094*1ae08745Sheppo D2("i_vldc_ioctl_read_cookie: vldc@%d:%d read succeeded\n", 1095*1ae08745Sheppo vldc_instance, vport->number); 1096*1ae08745Sheppo 1097*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1098*1ae08745Sheppo 1099*1ae08745Sheppo /* copy data from temporary buffer out to the caller and free buffer */ 1100*1ae08745Sheppo rv = ddi_copyout(buf, (caddr_t)copy_info.src_addr, len, mode); 1101*1ae08745Sheppo kmem_free(buf, copy_info.length); 1102*1ae08745Sheppo if (rv != 0) { 1103*1ae08745Sheppo return (EFAULT); 1104*1ae08745Sheppo } 1105*1ae08745Sheppo 1106*1ae08745Sheppo /* set the structure to reflect outcome */ 1107*1ae08745Sheppo copy_info.length = len; 1108*1ae08745Sheppo if (ddi_copyout(©_info, arg, sizeof (copy_info), mode) != 0) { 1109*1ae08745Sheppo return (EFAULT); 1110*1ae08745Sheppo } 1111*1ae08745Sheppo 1112*1ae08745Sheppo return (0); 1113*1ae08745Sheppo } 1114*1ae08745Sheppo 1115*1ae08745Sheppo /* ioctl to write cookie */ 1116*1ae08745Sheppo static int 1117*1ae08745Sheppo i_vldc_ioctl_write_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1118*1ae08745Sheppo int mode) 1119*1ae08745Sheppo { 1120*1ae08745Sheppo vldc_data_t copy_info; 1121*1ae08745Sheppo caddr_t buf; 1122*1ae08745Sheppo uint64_t len; 1123*1ae08745Sheppo int rv; 1124*1ae08745Sheppo 1125*1ae08745Sheppo if (ddi_copyin((caddr_t)arg, ©_info, 1126*1ae08745Sheppo sizeof (copy_info), mode) != 0) { 1127*1ae08745Sheppo return (EFAULT); 1128*1ae08745Sheppo } 1129*1ae08745Sheppo 1130*1ae08745Sheppo len = copy_info.length; 1131*1ae08745Sheppo if (len > vldc_max_cookie) { 1132*1ae08745Sheppo return (EINVAL); 1133*1ae08745Sheppo } 1134*1ae08745Sheppo 1135*1ae08745Sheppo D2("i_vldc_ioctl_write_cookie: vldc@%d:%d writing 0x%lx size 0x%lx " 1136*1ae08745Sheppo "to 0x%lx\n", vldc_instance, vport->number, copy_info.src_addr, 1137*1ae08745Sheppo copy_info.length, copy_info.dst_addr); 1138*1ae08745Sheppo 1139*1ae08745Sheppo /* allocate a temporary buffer */ 1140*1ae08745Sheppo buf = kmem_alloc(len, KM_SLEEP); 1141*1ae08745Sheppo 1142*1ae08745Sheppo /* copy into the temporary buffer the data to be written to the HV */ 1143*1ae08745Sheppo if (ddi_copyin((caddr_t)copy_info.src_addr, buf, 1144*1ae08745Sheppo copy_info.length, mode) != 0) { 1145*1ae08745Sheppo kmem_free(buf, copy_info.length); 1146*1ae08745Sheppo return (EFAULT); 1147*1ae08745Sheppo } 1148*1ae08745Sheppo 1149*1ae08745Sheppo mutex_enter(&vport->minorp->lock); 1150*1ae08745Sheppo 1151*1ae08745Sheppo /* write the data from the temporary buffer to the HV */ 1152*1ae08745Sheppo rv = ldc_mem_rdwr_pa(vport->ldc_handle, buf, &len, 1153*1ae08745Sheppo (caddr_t)copy_info.dst_addr, LDC_COPY_OUT); 1154*1ae08745Sheppo if (rv != 0) { 1155*1ae08745Sheppo DWARN("i_vldc_ioctl_write_cookie: vldc@%d:%d failed to write at" 1156*1ae08745Sheppo " address 0x%lx\n, rv=%d", vldc_instance, vport->number, 1157*1ae08745Sheppo copy_info.dst_addr, rv); 1158*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1159*1ae08745Sheppo kmem_free(buf, copy_info.length); 1160*1ae08745Sheppo return (EFAULT); 1161*1ae08745Sheppo } 1162*1ae08745Sheppo 1163*1ae08745Sheppo D2("i_vldc_ioctl_write_cookie: vldc@%d:%d write succeeded\n", 1164*1ae08745Sheppo vldc_instance, vport->number); 1165*1ae08745Sheppo 1166*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1167*1ae08745Sheppo 1168*1ae08745Sheppo kmem_free(buf, copy_info.length); 1169*1ae08745Sheppo 1170*1ae08745Sheppo /* set the structure to reflect outcome */ 1171*1ae08745Sheppo copy_info.length = len; 1172*1ae08745Sheppo if (ddi_copyout(©_info, (caddr_t)arg, 1173*1ae08745Sheppo sizeof (copy_info), mode) != 0) { 1174*1ae08745Sheppo return (EFAULT); 1175*1ae08745Sheppo } 1176*1ae08745Sheppo 1177*1ae08745Sheppo return (0); 1178*1ae08745Sheppo } 1179*1ae08745Sheppo 1180*1ae08745Sheppo /* vldc specific ioctl option commands */ 1181*1ae08745Sheppo static int 1182*1ae08745Sheppo i_vldc_ioctl_opt_op(vldc_port_t *vport, vldc_t *vldcp, void *arg, int mode) 1183*1ae08745Sheppo { 1184*1ae08745Sheppo vldc_opt_op_t vldc_cmd; 1185*1ae08745Sheppo uint32_t new_mtu; 1186*1ae08745Sheppo int rv = 0; 1187*1ae08745Sheppo 1188*1ae08745Sheppo if (ddi_copyin(arg, &vldc_cmd, sizeof (vldc_cmd), mode) != 0) { 1189*1ae08745Sheppo return (EFAULT); 1190*1ae08745Sheppo } 1191*1ae08745Sheppo 1192*1ae08745Sheppo D1("vldc_ioctl_opt_op: op %d\n", vldc_cmd.opt_sel); 1193*1ae08745Sheppo 1194*1ae08745Sheppo switch (vldc_cmd.opt_sel) { 1195*1ae08745Sheppo 1196*1ae08745Sheppo case VLDC_OPT_MTU_SZ: 1197*1ae08745Sheppo 1198*1ae08745Sheppo if (vldc_cmd.op_sel == VLDC_OP_GET) { 1199*1ae08745Sheppo vldc_cmd.opt_val = vport->mtu; 1200*1ae08745Sheppo if (ddi_copyout(&vldc_cmd, arg, 1201*1ae08745Sheppo sizeof (vldc_cmd), mode) == -1) { 1202*1ae08745Sheppo return (EFAULT); 1203*1ae08745Sheppo } 1204*1ae08745Sheppo } else { 1205*1ae08745Sheppo new_mtu = vldc_cmd.opt_val; 1206*1ae08745Sheppo 1207*1ae08745Sheppo if ((new_mtu < LDC_PACKET_SIZE) || 1208*1ae08745Sheppo (new_mtu > vldc_max_mtu)) { 1209*1ae08745Sheppo return (EINVAL); 1210*1ae08745Sheppo } 1211*1ae08745Sheppo 1212*1ae08745Sheppo mutex_enter(&vport->minorp->lock); 1213*1ae08745Sheppo 1214*1ae08745Sheppo if ((vport->status != VLDC_PORT_CLOSED) && 1215*1ae08745Sheppo (new_mtu != vport->mtu)) { 1216*1ae08745Sheppo /* 1217*1ae08745Sheppo * The port has buffers allocated since it is 1218*1ae08745Sheppo * not closed plus the MTU size has changed. 1219*1ae08745Sheppo * Reallocate the buffers to the new MTU size. 1220*1ae08745Sheppo */ 1221*1ae08745Sheppo kmem_free(vport->recv_buf, vport->mtu); 1222*1ae08745Sheppo vport->recv_buf = kmem_alloc(new_mtu, KM_SLEEP); 1223*1ae08745Sheppo 1224*1ae08745Sheppo kmem_free(vport->send_buf, vport->mtu); 1225*1ae08745Sheppo vport->send_buf = kmem_alloc(new_mtu, KM_SLEEP); 1226*1ae08745Sheppo 1227*1ae08745Sheppo vport->mtu = new_mtu; 1228*1ae08745Sheppo } 1229*1ae08745Sheppo 1230*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1231*1ae08745Sheppo } 1232*1ae08745Sheppo 1233*1ae08745Sheppo break; 1234*1ae08745Sheppo 1235*1ae08745Sheppo case VLDC_OPT_STATUS: 1236*1ae08745Sheppo 1237*1ae08745Sheppo if (vldc_cmd.op_sel == VLDC_OP_GET) { 1238*1ae08745Sheppo vldc_cmd.opt_val = vport->status; 1239*1ae08745Sheppo if (ddi_copyout(&vldc_cmd, arg, 1240*1ae08745Sheppo sizeof (vldc_cmd), mode) == -1) { 1241*1ae08745Sheppo return (EFAULT); 1242*1ae08745Sheppo } 1243*1ae08745Sheppo } else { 1244*1ae08745Sheppo return (ENOTSUP); 1245*1ae08745Sheppo } 1246*1ae08745Sheppo 1247*1ae08745Sheppo break; 1248*1ae08745Sheppo 1249*1ae08745Sheppo case VLDC_OPT_MODE: 1250*1ae08745Sheppo 1251*1ae08745Sheppo if (vldc_cmd.op_sel == VLDC_OP_GET) { 1252*1ae08745Sheppo vldc_cmd.opt_val = vport->ldc_mode; 1253*1ae08745Sheppo if (ddi_copyout(&vldc_cmd, arg, 1254*1ae08745Sheppo sizeof (vldc_cmd), mode) == -1) { 1255*1ae08745Sheppo return (EFAULT); 1256*1ae08745Sheppo } 1257*1ae08745Sheppo } else { 1258*1ae08745Sheppo mutex_enter(&vport->minorp->lock); 1259*1ae08745Sheppo rv = vldc_set_ldc_mode(vport, vldcp, vldc_cmd.opt_val); 1260*1ae08745Sheppo mutex_exit(&vport->minorp->lock); 1261*1ae08745Sheppo } 1262*1ae08745Sheppo 1263*1ae08745Sheppo break; 1264*1ae08745Sheppo 1265*1ae08745Sheppo default: 1266*1ae08745Sheppo 1267*1ae08745Sheppo D1("vldc_ioctl_opt_op: unsupported op %d\n", vldc_cmd.opt_sel); 1268*1ae08745Sheppo return (ENOTSUP); 1269*1ae08745Sheppo } 1270*1ae08745Sheppo 1271*1ae08745Sheppo return (rv); 1272*1ae08745Sheppo } 1273*1ae08745Sheppo 1274*1ae08745Sheppo /* cb_ioctl */ 1275*1ae08745Sheppo static int 1276*1ae08745Sheppo vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1277*1ae08745Sheppo int *rvalp) 1278*1ae08745Sheppo { 1279*1ae08745Sheppo _NOTE(ARGUNUSED(credp, rvalp)) 1280*1ae08745Sheppo 1281*1ae08745Sheppo int rv = EINVAL; 1282*1ae08745Sheppo int instance; 1283*1ae08745Sheppo minor_t minor; 1284*1ae08745Sheppo uint64_t portno; 1285*1ae08745Sheppo vldc_t *vldcp; 1286*1ae08745Sheppo vldc_port_t *vport; 1287*1ae08745Sheppo vldc_minor_t *vminor; 1288*1ae08745Sheppo 1289*1ae08745Sheppo minor = getminor(dev); 1290*1ae08745Sheppo instance = VLDCINST(minor); 1291*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 1292*1ae08745Sheppo if (vldcp == NULL) { 1293*1ae08745Sheppo return (ENXIO); 1294*1ae08745Sheppo } 1295*1ae08745Sheppo 1296*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 1297*1ae08745Sheppo mutex_enter(&vminor->lock); 1298*1ae08745Sheppo portno = vminor->portno; 1299*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 1300*1ae08745Sheppo mutex_exit(&vminor->lock); 1301*1ae08745Sheppo return (ENOLINK); 1302*1ae08745Sheppo } 1303*1ae08745Sheppo vminor->in_use += 1; 1304*1ae08745Sheppo mutex_exit(&vminor->lock); 1305*1ae08745Sheppo 1306*1ae08745Sheppo vport = &(vldcp->port[portno]); 1307*1ae08745Sheppo 1308*1ae08745Sheppo D1("vldc_ioctl: vldc@%d:%lu cmd=0x%x\n", instance, portno, cmd); 1309*1ae08745Sheppo 1310*1ae08745Sheppo switch (cmd) { 1311*1ae08745Sheppo 1312*1ae08745Sheppo case VLDC_IOCTL_OPT_OP: 1313*1ae08745Sheppo 1314*1ae08745Sheppo rv = i_vldc_ioctl_opt_op(vport, vldcp, (void *)arg, mode); 1315*1ae08745Sheppo break; 1316*1ae08745Sheppo 1317*1ae08745Sheppo case VLDC_IOCTL_READ_COOKIE: 1318*1ae08745Sheppo 1319*1ae08745Sheppo rv = i_vldc_ioctl_read_cookie(vport, instance, 1320*1ae08745Sheppo (void *)arg, mode); 1321*1ae08745Sheppo break; 1322*1ae08745Sheppo 1323*1ae08745Sheppo case VLDC_IOCTL_WRITE_COOKIE: 1324*1ae08745Sheppo 1325*1ae08745Sheppo rv = i_vldc_ioctl_write_cookie(vport, instance, 1326*1ae08745Sheppo (void *)arg, mode); 1327*1ae08745Sheppo break; 1328*1ae08745Sheppo 1329*1ae08745Sheppo default: 1330*1ae08745Sheppo 1331*1ae08745Sheppo DWARN("vldc_ioctl: vldc@%d:%lu unknown cmd=0x%x\n", 1332*1ae08745Sheppo instance, portno, cmd); 1333*1ae08745Sheppo rv = EINVAL; 1334*1ae08745Sheppo break; 1335*1ae08745Sheppo } 1336*1ae08745Sheppo 1337*1ae08745Sheppo mutex_enter(&vminor->lock); 1338*1ae08745Sheppo vminor->in_use -= 1; 1339*1ae08745Sheppo if (vminor->in_use == 0) { 1340*1ae08745Sheppo cv_signal(&vminor->cv); 1341*1ae08745Sheppo } 1342*1ae08745Sheppo mutex_exit(&vminor->lock); 1343*1ae08745Sheppo 1344*1ae08745Sheppo D1("vldc_ioctl: rv=%d\n", rv); 1345*1ae08745Sheppo 1346*1ae08745Sheppo return (rv); 1347*1ae08745Sheppo } 1348*1ae08745Sheppo 1349*1ae08745Sheppo /* cb_read */ 1350*1ae08745Sheppo static int 1351*1ae08745Sheppo vldc_read(dev_t dev, struct uio *uiop, cred_t *credp) 1352*1ae08745Sheppo { 1353*1ae08745Sheppo _NOTE(ARGUNUSED(credp)) 1354*1ae08745Sheppo 1355*1ae08745Sheppo int instance; 1356*1ae08745Sheppo minor_t minor; 1357*1ae08745Sheppo size_t size = 0; 1358*1ae08745Sheppo uint64_t portno; 1359*1ae08745Sheppo vldc_t *vldcp; 1360*1ae08745Sheppo vldc_port_t *vport; 1361*1ae08745Sheppo vldc_minor_t *vminor; 1362*1ae08745Sheppo int rv = 0; 1363*1ae08745Sheppo 1364*1ae08745Sheppo minor = getminor(dev); 1365*1ae08745Sheppo instance = VLDCINST(minor); 1366*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 1367*1ae08745Sheppo if (vldcp == NULL) { 1368*1ae08745Sheppo return (ENXIO); 1369*1ae08745Sheppo } 1370*1ae08745Sheppo 1371*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 1372*1ae08745Sheppo mutex_enter(&vminor->lock); 1373*1ae08745Sheppo portno = vminor->portno; 1374*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 1375*1ae08745Sheppo mutex_exit(&vminor->lock); 1376*1ae08745Sheppo return (ENOLINK); 1377*1ae08745Sheppo } 1378*1ae08745Sheppo 1379*1ae08745Sheppo D2("vldc_read: vldc@%d:%lu reading data\n", instance, portno); 1380*1ae08745Sheppo 1381*1ae08745Sheppo vport = &(vldcp->port[portno]); 1382*1ae08745Sheppo 1383*1ae08745Sheppo /* check the port status */ 1384*1ae08745Sheppo if (vport->status != VLDC_PORT_READY) { 1385*1ae08745Sheppo DWARN("vldc_read: vldc@%d:%lu not in the ready state\n", 1386*1ae08745Sheppo instance, portno); 1387*1ae08745Sheppo mutex_exit(&vminor->lock); 1388*1ae08745Sheppo return (ENOTACTIVE); 1389*1ae08745Sheppo } 1390*1ae08745Sheppo 1391*1ae08745Sheppo /* read data */ 1392*1ae08745Sheppo size = MIN(vport->mtu, uiop->uio_resid); 1393*1ae08745Sheppo rv = ldc_read(vport->ldc_handle, vport->recv_buf, &size); 1394*1ae08745Sheppo 1395*1ae08745Sheppo D2("vldc_read: vldc@%d:%lu ldc_read size=%ld, rv=%d\n", 1396*1ae08745Sheppo instance, portno, size, rv); 1397*1ae08745Sheppo 1398*1ae08745Sheppo if (rv == 0) { 1399*1ae08745Sheppo if (size != 0) { 1400*1ae08745Sheppo rv = uiomove(vport->recv_buf, size, UIO_READ, uiop); 1401*1ae08745Sheppo } else { 1402*1ae08745Sheppo rv = EWOULDBLOCK; 1403*1ae08745Sheppo } 1404*1ae08745Sheppo } else { 1405*1ae08745Sheppo switch (rv) { 1406*1ae08745Sheppo case ENOBUFS: 1407*1ae08745Sheppo break; 1408*1ae08745Sheppo case ETIMEDOUT: 1409*1ae08745Sheppo case EWOULDBLOCK: 1410*1ae08745Sheppo rv = EWOULDBLOCK; 1411*1ae08745Sheppo break; 1412*1ae08745Sheppo default: 1413*1ae08745Sheppo rv = ECONNRESET; 1414*1ae08745Sheppo break; 1415*1ae08745Sheppo } 1416*1ae08745Sheppo } 1417*1ae08745Sheppo 1418*1ae08745Sheppo mutex_exit(&vminor->lock); 1419*1ae08745Sheppo 1420*1ae08745Sheppo return (rv); 1421*1ae08745Sheppo } 1422*1ae08745Sheppo 1423*1ae08745Sheppo /* cb_write */ 1424*1ae08745Sheppo static int 1425*1ae08745Sheppo vldc_write(dev_t dev, struct uio *uiop, cred_t *credp) 1426*1ae08745Sheppo { 1427*1ae08745Sheppo _NOTE(ARGUNUSED(credp)) 1428*1ae08745Sheppo 1429*1ae08745Sheppo int instance; 1430*1ae08745Sheppo minor_t minor; 1431*1ae08745Sheppo size_t size; 1432*1ae08745Sheppo size_t orig_size; 1433*1ae08745Sheppo uint64_t portno; 1434*1ae08745Sheppo vldc_t *vldcp; 1435*1ae08745Sheppo vldc_port_t *vport; 1436*1ae08745Sheppo vldc_minor_t *vminor; 1437*1ae08745Sheppo int rv = EINVAL; 1438*1ae08745Sheppo 1439*1ae08745Sheppo minor = getminor(dev); 1440*1ae08745Sheppo instance = VLDCINST(minor); 1441*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 1442*1ae08745Sheppo if (vldcp == NULL) { 1443*1ae08745Sheppo return (ENXIO); 1444*1ae08745Sheppo } 1445*1ae08745Sheppo 1446*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 1447*1ae08745Sheppo mutex_enter(&vminor->lock); 1448*1ae08745Sheppo portno = vminor->portno; 1449*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 1450*1ae08745Sheppo mutex_exit(&vminor->lock); 1451*1ae08745Sheppo return (ENOLINK); 1452*1ae08745Sheppo } 1453*1ae08745Sheppo 1454*1ae08745Sheppo vport = &(vldcp->port[portno]); 1455*1ae08745Sheppo 1456*1ae08745Sheppo /* check the port status */ 1457*1ae08745Sheppo if (vport->status != VLDC_PORT_READY) { 1458*1ae08745Sheppo DWARN("vldc_write: vldc@%d:%lu not in the ready state\n", 1459*1ae08745Sheppo instance, portno); 1460*1ae08745Sheppo mutex_exit(&vminor->lock); 1461*1ae08745Sheppo return (ENOTACTIVE); 1462*1ae08745Sheppo } 1463*1ae08745Sheppo 1464*1ae08745Sheppo orig_size = uiop->uio_resid; 1465*1ae08745Sheppo size = orig_size; 1466*1ae08745Sheppo 1467*1ae08745Sheppo if (size > vport->mtu) { 1468*1ae08745Sheppo if (vport->is_stream) { 1469*1ae08745Sheppo /* can only send MTU size at a time */ 1470*1ae08745Sheppo size = vport->mtu; 1471*1ae08745Sheppo } else { 1472*1ae08745Sheppo mutex_exit(&vminor->lock); 1473*1ae08745Sheppo return (EMSGSIZE); 1474*1ae08745Sheppo } 1475*1ae08745Sheppo } 1476*1ae08745Sheppo 1477*1ae08745Sheppo D2("vldc_write: vldc@%d:%lu writing %lu bytes\n", instance, portno, 1478*1ae08745Sheppo size); 1479*1ae08745Sheppo 1480*1ae08745Sheppo rv = uiomove(vport->send_buf, size, UIO_WRITE, uiop); 1481*1ae08745Sheppo if (rv == 0) { 1482*1ae08745Sheppo rv = ldc_write(vport->ldc_handle, (caddr_t)vport->send_buf, 1483*1ae08745Sheppo &size); 1484*1ae08745Sheppo if (rv != 0) { 1485*1ae08745Sheppo DWARN("vldc_write: vldc@%d:%lu failed writing %lu " 1486*1ae08745Sheppo "bytes rv=%d\n", instance, portno, size, rv); 1487*1ae08745Sheppo } 1488*1ae08745Sheppo } else { 1489*1ae08745Sheppo size = 0; 1490*1ae08745Sheppo } 1491*1ae08745Sheppo 1492*1ae08745Sheppo mutex_exit(&vminor->lock); 1493*1ae08745Sheppo 1494*1ae08745Sheppo /* resid is total number of bytes *not* sent */ 1495*1ae08745Sheppo uiop->uio_resid = orig_size - size; 1496*1ae08745Sheppo 1497*1ae08745Sheppo return (rv); 1498*1ae08745Sheppo } 1499*1ae08745Sheppo 1500*1ae08745Sheppo /* cb_chpoll */ 1501*1ae08745Sheppo static int 1502*1ae08745Sheppo vldc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 1503*1ae08745Sheppo struct pollhead **phpp) 1504*1ae08745Sheppo { 1505*1ae08745Sheppo int instance; 1506*1ae08745Sheppo minor_t minor; 1507*1ae08745Sheppo uint64_t portno; 1508*1ae08745Sheppo vldc_t *vldcp; 1509*1ae08745Sheppo vldc_port_t *vport; 1510*1ae08745Sheppo vldc_minor_t *vminor; 1511*1ae08745Sheppo ldc_status_t ldc_state; 1512*1ae08745Sheppo boolean_t isempty; 1513*1ae08745Sheppo int rv; 1514*1ae08745Sheppo 1515*1ae08745Sheppo minor = getminor(dev); 1516*1ae08745Sheppo instance = VLDCINST(minor); 1517*1ae08745Sheppo vldcp = ddi_get_soft_state(vldc_ssp, instance); 1518*1ae08745Sheppo if (vldcp == NULL) { 1519*1ae08745Sheppo return (ENXIO); 1520*1ae08745Sheppo } 1521*1ae08745Sheppo 1522*1ae08745Sheppo vminor = VLDCMINOR(vldcp, minor); 1523*1ae08745Sheppo mutex_enter(&vminor->lock); 1524*1ae08745Sheppo portno = vminor->portno; 1525*1ae08745Sheppo if (portno == VLDC_INVALID_PORTNO) { 1526*1ae08745Sheppo mutex_exit(&vminor->lock); 1527*1ae08745Sheppo return (ENOLINK); 1528*1ae08745Sheppo } 1529*1ae08745Sheppo 1530*1ae08745Sheppo vport = &(vldcp->port[portno]); 1531*1ae08745Sheppo 1532*1ae08745Sheppo /* check the port status */ 1533*1ae08745Sheppo if (vport->status != VLDC_PORT_READY) { 1534*1ae08745Sheppo mutex_exit(&vminor->lock); 1535*1ae08745Sheppo return (ENOTACTIVE); 1536*1ae08745Sheppo } 1537*1ae08745Sheppo 1538*1ae08745Sheppo D2("vldc_chpoll: vldc@%d:%lu polling events 0x%x\n", 1539*1ae08745Sheppo instance, portno, events); 1540*1ae08745Sheppo 1541*1ae08745Sheppo rv = ldc_status(vport->ldc_handle, &ldc_state); 1542*1ae08745Sheppo if (rv != 0) { 1543*1ae08745Sheppo DWARN("vldc_chpoll: vldc@%d:%lu could not get ldc status, " 1544*1ae08745Sheppo "rv=%d\n", instance, portno, rv); 1545*1ae08745Sheppo mutex_exit(&vminor->lock); 1546*1ae08745Sheppo return (EBADFD); 1547*1ae08745Sheppo } 1548*1ae08745Sheppo 1549*1ae08745Sheppo *reventsp = 0; 1550*1ae08745Sheppo 1551*1ae08745Sheppo if (ldc_state == LDC_UP) { 1552*1ae08745Sheppo /* 1553*1ae08745Sheppo * Check if the receive queue is empty and if not, signal that 1554*1ae08745Sheppo * there is data ready to read. 1555*1ae08745Sheppo */ 1556*1ae08745Sheppo if (events & POLLIN) { 1557*1ae08745Sheppo if ((ldc_chkq(vport->ldc_handle, &isempty) == 0) && 1558*1ae08745Sheppo (isempty == B_FALSE)) { 1559*1ae08745Sheppo *reventsp |= POLLIN; 1560*1ae08745Sheppo } 1561*1ae08745Sheppo } 1562*1ae08745Sheppo 1563*1ae08745Sheppo if (events & POLLOUT) 1564*1ae08745Sheppo *reventsp |= POLLOUT; 1565*1ae08745Sheppo 1566*1ae08745Sheppo } else if (vport->hanged_up) { 1567*1ae08745Sheppo *reventsp |= POLLHUP; 1568*1ae08745Sheppo vport->hanged_up = B_FALSE; 1569*1ae08745Sheppo } 1570*1ae08745Sheppo 1571*1ae08745Sheppo mutex_exit(&vminor->lock); 1572*1ae08745Sheppo 1573*1ae08745Sheppo if (((*reventsp) == 0) && (!anyyet)) { 1574*1ae08745Sheppo *phpp = &vport->poll; 1575*1ae08745Sheppo } 1576*1ae08745Sheppo 1577*1ae08745Sheppo D2("vldc_chpoll: vldc@%d:%lu ev=0x%x, rev=0x%x\n", 1578*1ae08745Sheppo instance, portno, events, *reventsp); 1579*1ae08745Sheppo 1580*1ae08745Sheppo return (0); 1581*1ae08745Sheppo } 1582