1*e11c3f44Smeem /* 2*e11c3f44Smeem * CDDL HEADER START 3*e11c3f44Smeem * 4*e11c3f44Smeem * The contents of this file are subject to the terms of the 5*e11c3f44Smeem * Common Development and Distribution License (the "License"). 6*e11c3f44Smeem * You may not use this file except in compliance with the License. 7*e11c3f44Smeem * 8*e11c3f44Smeem * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*e11c3f44Smeem * or http://www.opensolaris.org/os/licensing. 10*e11c3f44Smeem * See the License for the specific language governing permissions 11*e11c3f44Smeem * and limitations under the License. 12*e11c3f44Smeem * 13*e11c3f44Smeem * When distributing Covered Code, include this CDDL HEADER in each 14*e11c3f44Smeem * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*e11c3f44Smeem * If applicable, add the following below this CDDL HEADER, with the 16*e11c3f44Smeem * fields enclosed by brackets "[]" replaced with your own identifying 17*e11c3f44Smeem * information: Portions Copyright [yyyy] [name of copyright owner] 18*e11c3f44Smeem * 19*e11c3f44Smeem * CDDL HEADER END 20*e11c3f44Smeem */ 21*e11c3f44Smeem /* 22*e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*e11c3f44Smeem * Use is subject to license terms. 24*e11c3f44Smeem */ 25*e11c3f44Smeem 26*e11c3f44Smeem /* 27*e11c3f44Smeem * DLPI stub driver; currently supports VNI and IPMP stub devices. 28*e11c3f44Smeem */ 29*e11c3f44Smeem 30*e11c3f44Smeem #include <sys/conf.h> 31*e11c3f44Smeem #include <sys/ddi.h> 32*e11c3f44Smeem #include <sys/sunddi.h> 33*e11c3f44Smeem #include <sys/dlpi.h> 34*e11c3f44Smeem #include <sys/stat.h> 35*e11c3f44Smeem #include <sys/strsun.h> 36*e11c3f44Smeem #include <sys/stropts.h> 37*e11c3f44Smeem #include <sys/types.h> 38*e11c3f44Smeem #include <sys/id_space.h> 39*e11c3f44Smeem #include <sys/sysmacros.h> 40*e11c3f44Smeem #include <sys/kmem.h> 41*e11c3f44Smeem #include <sys/modctl.h> 42*e11c3f44Smeem #include <sys/mkdev.h> 43*e11c3f44Smeem #include <sys/sdt.h> 44*e11c3f44Smeem 45*e11c3f44Smeem #include "dlpistub_impl.h" 46*e11c3f44Smeem 47*e11c3f44Smeem static id_space_t *ds_minors; 48*e11c3f44Smeem static dev_info_t *ds_dip; 49*e11c3f44Smeem 50*e11c3f44Smeem /* 51*e11c3f44Smeem * DL_INFO_ACK template. 52*e11c3f44Smeem */ 53*e11c3f44Smeem static dl_info_ack_t ds_infoack = { 54*e11c3f44Smeem DL_INFO_ACK, /* dl_primitive */ 55*e11c3f44Smeem 0, /* dl_max_sdu */ 56*e11c3f44Smeem 0, /* dl_min_sdu */ 57*e11c3f44Smeem 0, /* dl_addr_length */ 58*e11c3f44Smeem 0, /* dl_mac_type */ 59*e11c3f44Smeem 0, /* dl_reserved */ 60*e11c3f44Smeem 0, /* dl_current_state */ 61*e11c3f44Smeem 0, /* dl_sap_length */ 62*e11c3f44Smeem DL_CLDLS, /* dl_service_mode */ 63*e11c3f44Smeem 0, /* dl_qos_length */ 64*e11c3f44Smeem 0, /* dl_qos_offset */ 65*e11c3f44Smeem 0, /* dl_qos_range_length */ 66*e11c3f44Smeem 0, /* dl_qos_range_offset */ 67*e11c3f44Smeem DL_STYLE2, /* dl_provider_style */ 68*e11c3f44Smeem 0, /* dl_addr_offset */ 69*e11c3f44Smeem DL_VERSION_2, /* dl_version */ 70*e11c3f44Smeem 0, /* dl_brdcst_addr_length */ 71*e11c3f44Smeem 0, /* dl_brdcst_addr_offset */ 72*e11c3f44Smeem 0 /* dl_growth */ 73*e11c3f44Smeem }; 74*e11c3f44Smeem 75*e11c3f44Smeem static int 76*e11c3f44Smeem ds_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 77*e11c3f44Smeem { 78*e11c3f44Smeem if (cmd != DDI_ATTACH) 79*e11c3f44Smeem return (DDI_FAILURE); 80*e11c3f44Smeem 81*e11c3f44Smeem if (ddi_create_minor_node(dip, "vni", S_IFCHR, DS_MINOR_VNI, 82*e11c3f44Smeem DDI_PSEUDO, 0) == DDI_FAILURE || 83*e11c3f44Smeem ddi_create_minor_node(dip, "ipmpstub", S_IFCHR, DS_MINOR_IPMP, 84*e11c3f44Smeem DDI_PSEUDO, 0) == DDI_FAILURE) { 85*e11c3f44Smeem ddi_remove_minor_node(dip, NULL); 86*e11c3f44Smeem cmn_err(CE_NOTE, "ds_attach: cannot create minor nodes"); 87*e11c3f44Smeem return (DDI_FAILURE); 88*e11c3f44Smeem } 89*e11c3f44Smeem 90*e11c3f44Smeem ds_dip = dip; 91*e11c3f44Smeem ds_minors = id_space_create("ds_minors", DS_MINOR_START, MAXMIN32); 92*e11c3f44Smeem return (DDI_SUCCESS); 93*e11c3f44Smeem } 94*e11c3f44Smeem 95*e11c3f44Smeem static int 96*e11c3f44Smeem ds_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 97*e11c3f44Smeem { 98*e11c3f44Smeem if (cmd != DDI_DETACH) 99*e11c3f44Smeem return (DDI_FAILURE); 100*e11c3f44Smeem 101*e11c3f44Smeem id_space_destroy(ds_minors); 102*e11c3f44Smeem ds_minors = NULL; 103*e11c3f44Smeem ASSERT(dip == ds_dip); 104*e11c3f44Smeem ddi_remove_minor_node(dip, NULL); 105*e11c3f44Smeem ds_dip = NULL; 106*e11c3f44Smeem return (DDI_SUCCESS); 107*e11c3f44Smeem } 108*e11c3f44Smeem 109*e11c3f44Smeem /* ARGSUSED */ 110*e11c3f44Smeem static int 111*e11c3f44Smeem ds_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 112*e11c3f44Smeem { 113*e11c3f44Smeem int error = DDI_FAILURE; 114*e11c3f44Smeem 115*e11c3f44Smeem switch (infocmd) { 116*e11c3f44Smeem case DDI_INFO_DEVT2INSTANCE: 117*e11c3f44Smeem *result = (void *)0; 118*e11c3f44Smeem error = DDI_SUCCESS; 119*e11c3f44Smeem break; 120*e11c3f44Smeem case DDI_INFO_DEVT2DEVINFO: 121*e11c3f44Smeem if (ds_dip != NULL) { 122*e11c3f44Smeem *result = ds_dip; 123*e11c3f44Smeem error = DDI_SUCCESS; 124*e11c3f44Smeem } 125*e11c3f44Smeem break; 126*e11c3f44Smeem } 127*e11c3f44Smeem return (error); 128*e11c3f44Smeem } 129*e11c3f44Smeem 130*e11c3f44Smeem /* ARGSUSED */ 131*e11c3f44Smeem static int 132*e11c3f44Smeem ds_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 133*e11c3f44Smeem { 134*e11c3f44Smeem int type; 135*e11c3f44Smeem dlpistub_t *dsp; 136*e11c3f44Smeem 137*e11c3f44Smeem if (sflag == CLONEOPEN || sflag == MODOPEN) 138*e11c3f44Smeem return (EINVAL); 139*e11c3f44Smeem 140*e11c3f44Smeem if (q->q_ptr != NULL) 141*e11c3f44Smeem return (0); 142*e11c3f44Smeem 143*e11c3f44Smeem switch (getminor(*devp)) { 144*e11c3f44Smeem case DS_MINOR_VNI: 145*e11c3f44Smeem type = SUNW_DL_VNI; 146*e11c3f44Smeem break; 147*e11c3f44Smeem case DS_MINOR_IPMP: 148*e11c3f44Smeem type = SUNW_DL_IPMP; 149*e11c3f44Smeem break; 150*e11c3f44Smeem default: 151*e11c3f44Smeem return (ENXIO); 152*e11c3f44Smeem } 153*e11c3f44Smeem 154*e11c3f44Smeem dsp = kmem_zalloc(sizeof (dlpistub_t), KM_SLEEP); 155*e11c3f44Smeem dsp->ds_type = type; 156*e11c3f44Smeem dsp->ds_minor = (minor_t)id_alloc(ds_minors); 157*e11c3f44Smeem dsp->ds_state = DL_UNATTACHED; 158*e11c3f44Smeem *devp = makedevice(getmajor(*devp), dsp->ds_minor); 159*e11c3f44Smeem q->q_ptr = WR(q)->q_ptr = dsp; 160*e11c3f44Smeem qprocson(q); 161*e11c3f44Smeem 162*e11c3f44Smeem return (0); 163*e11c3f44Smeem } 164*e11c3f44Smeem 165*e11c3f44Smeem /* ARGSUSED */ 166*e11c3f44Smeem static int 167*e11c3f44Smeem ds_close(queue_t *q, int flag, cred_t *credp) 168*e11c3f44Smeem { 169*e11c3f44Smeem dlpistub_t *dsp = q->q_ptr; 170*e11c3f44Smeem 171*e11c3f44Smeem qprocsoff(q); 172*e11c3f44Smeem q->q_ptr = WR(q)->q_ptr = NULL; 173*e11c3f44Smeem 174*e11c3f44Smeem id_free(ds_minors, dsp->ds_minor); 175*e11c3f44Smeem kmem_free(dsp, sizeof (dlpistub_t)); 176*e11c3f44Smeem 177*e11c3f44Smeem return (0); 178*e11c3f44Smeem } 179*e11c3f44Smeem 180*e11c3f44Smeem static int 181*e11c3f44Smeem ds_badprim(queue_t *q, mblk_t *mp, t_scalar_t prim) 182*e11c3f44Smeem { 183*e11c3f44Smeem dlerrorack(q, mp, prim, DL_BADPRIM, 0); 184*e11c3f44Smeem return (0); 185*e11c3f44Smeem } 186*e11c3f44Smeem 187*e11c3f44Smeem static int 188*e11c3f44Smeem ds_outstate(queue_t *q, mblk_t *mp, t_scalar_t prim) 189*e11c3f44Smeem { 190*e11c3f44Smeem dlerrorack(q, mp, prim, DL_OUTSTATE, 0); 191*e11c3f44Smeem return (0); 192*e11c3f44Smeem } 193*e11c3f44Smeem 194*e11c3f44Smeem static int 195*e11c3f44Smeem ds_wput(queue_t *q, mblk_t *mp) 196*e11c3f44Smeem { 197*e11c3f44Smeem union DL_primitives *dlp; 198*e11c3f44Smeem dl_info_ack_t *dlip; 199*e11c3f44Smeem dlpistub_t *dsp = q->q_ptr; 200*e11c3f44Smeem t_scalar_t prim; 201*e11c3f44Smeem 202*e11c3f44Smeem switch (DB_TYPE(mp)) { 203*e11c3f44Smeem case M_PROTO: 204*e11c3f44Smeem case M_PCPROTO: 205*e11c3f44Smeem if (MBLKL(mp) < sizeof (t_scalar_t)) { 206*e11c3f44Smeem dlerrorack(q, mp, DL_PRIM_INVAL, DL_UNSUPPORTED, 0); 207*e11c3f44Smeem return (0); 208*e11c3f44Smeem } 209*e11c3f44Smeem 210*e11c3f44Smeem dlp = (void *)mp->b_rptr; 211*e11c3f44Smeem prim = dlp->dl_primitive; 212*e11c3f44Smeem switch (prim) { 213*e11c3f44Smeem case DL_ATTACH_REQ: 214*e11c3f44Smeem if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) 215*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 216*e11c3f44Smeem 217*e11c3f44Smeem if (dsp->ds_state != DL_UNATTACHED) 218*e11c3f44Smeem return (ds_outstate(q, mp, prim)); 219*e11c3f44Smeem 220*e11c3f44Smeem dsp->ds_state = DL_UNBOUND; 221*e11c3f44Smeem dlokack(q, mp, DL_ATTACH_REQ); 222*e11c3f44Smeem break; 223*e11c3f44Smeem 224*e11c3f44Smeem case DL_BIND_REQ: 225*e11c3f44Smeem if (MBLKL(mp) < DL_BIND_REQ_SIZE) 226*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 227*e11c3f44Smeem 228*e11c3f44Smeem if (dsp->ds_state != DL_UNBOUND) 229*e11c3f44Smeem return (ds_outstate(q, mp, prim)); 230*e11c3f44Smeem 231*e11c3f44Smeem dsp->ds_state = DL_IDLE; 232*e11c3f44Smeem dlbindack(q, mp, dlp->bind_req.dl_sap, NULL, 0, 0, 0); 233*e11c3f44Smeem break; 234*e11c3f44Smeem 235*e11c3f44Smeem case DL_INFO_REQ: 236*e11c3f44Smeem if (MBLKL(mp) < DL_INFO_REQ_SIZE) 237*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 238*e11c3f44Smeem 239*e11c3f44Smeem mp = mexchange(q, mp, sizeof (dl_info_ack_t), 240*e11c3f44Smeem M_PCPROTO, DL_INFO_ACK); 241*e11c3f44Smeem if (mp != NULL) { 242*e11c3f44Smeem dlip = (void *)mp->b_rptr; 243*e11c3f44Smeem *dlip = ds_infoack; 244*e11c3f44Smeem dlip->dl_mac_type = dsp->ds_type; 245*e11c3f44Smeem dlip->dl_current_state = dsp->ds_state; 246*e11c3f44Smeem qreply(q, mp); 247*e11c3f44Smeem } 248*e11c3f44Smeem break; 249*e11c3f44Smeem 250*e11c3f44Smeem case DL_PHYS_ADDR_REQ: 251*e11c3f44Smeem if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) 252*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 253*e11c3f44Smeem 254*e11c3f44Smeem dlphysaddrack(q, mp, NULL, 0); 255*e11c3f44Smeem break; 256*e11c3f44Smeem 257*e11c3f44Smeem case DL_UNBIND_REQ: 258*e11c3f44Smeem if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) 259*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 260*e11c3f44Smeem 261*e11c3f44Smeem if (dsp->ds_state != DL_IDLE) 262*e11c3f44Smeem return (ds_outstate(q, mp, prim)); 263*e11c3f44Smeem 264*e11c3f44Smeem dsp->ds_state = DL_UNBOUND; 265*e11c3f44Smeem dlokack(q, mp, DL_UNBIND_REQ); 266*e11c3f44Smeem break; 267*e11c3f44Smeem 268*e11c3f44Smeem case DL_DETACH_REQ: 269*e11c3f44Smeem if (MBLKL(mp) < DL_DETACH_REQ_SIZE) 270*e11c3f44Smeem return (ds_badprim(q, mp, prim)); 271*e11c3f44Smeem 272*e11c3f44Smeem if (dsp->ds_state != DL_UNBOUND) 273*e11c3f44Smeem return (ds_outstate(q, mp, prim)); 274*e11c3f44Smeem 275*e11c3f44Smeem dsp->ds_state = DL_UNATTACHED; 276*e11c3f44Smeem dlokack(q, mp, DL_DETACH_REQ); 277*e11c3f44Smeem break; 278*e11c3f44Smeem 279*e11c3f44Smeem case DL_UNITDATA_REQ: 280*e11c3f44Smeem DTRACE_PROBE2(dlpistub__data, dlpistub_t *, dsp, 281*e11c3f44Smeem mblk_t *, mp); 282*e11c3f44Smeem freemsg(mp); 283*e11c3f44Smeem break; 284*e11c3f44Smeem 285*e11c3f44Smeem default: 286*e11c3f44Smeem dlerrorack(q, mp, prim, DL_UNSUPPORTED, 0); 287*e11c3f44Smeem } 288*e11c3f44Smeem break; 289*e11c3f44Smeem 290*e11c3f44Smeem case M_IOCTL: 291*e11c3f44Smeem miocnak(q, mp, 0, EINVAL); 292*e11c3f44Smeem break; 293*e11c3f44Smeem 294*e11c3f44Smeem case M_FLUSH: 295*e11c3f44Smeem *mp->b_rptr &= ~FLUSHW; 296*e11c3f44Smeem if (*mp->b_rptr & FLUSHR) 297*e11c3f44Smeem qreply(q, mp); 298*e11c3f44Smeem else 299*e11c3f44Smeem freemsg(mp); 300*e11c3f44Smeem break; 301*e11c3f44Smeem default: 302*e11c3f44Smeem freemsg(mp); 303*e11c3f44Smeem break; 304*e11c3f44Smeem } 305*e11c3f44Smeem 306*e11c3f44Smeem return (0); 307*e11c3f44Smeem } 308*e11c3f44Smeem 309*e11c3f44Smeem static struct module_info ds_minfo = { 310*e11c3f44Smeem DS_IDNUM, /* mi_idnum */ 311*e11c3f44Smeem "dlpistub", /* mi_idname */ 312*e11c3f44Smeem 0, /* mi_minpsz */ 313*e11c3f44Smeem INFPSZ, /* mi_maxpsz */ 314*e11c3f44Smeem 0, /* mi_hiwat */ 315*e11c3f44Smeem 0, /* mi_lowat */ 316*e11c3f44Smeem }; 317*e11c3f44Smeem 318*e11c3f44Smeem static struct qinit ds_rinit = { 319*e11c3f44Smeem NULL, /* qi_putp */ 320*e11c3f44Smeem NULL, /* qi_srvp */ 321*e11c3f44Smeem ds_open, /* qi_qopen */ 322*e11c3f44Smeem ds_close, /* qi_qclose */ 323*e11c3f44Smeem NULL, /* qi_qadmin */ 324*e11c3f44Smeem &ds_minfo, /* qi_minfo */ 325*e11c3f44Smeem }; 326*e11c3f44Smeem 327*e11c3f44Smeem static struct qinit ds_winit = { 328*e11c3f44Smeem ds_wput, /* qi_putp */ 329*e11c3f44Smeem NULL, /* qi_srvp */ 330*e11c3f44Smeem NULL, /* qi_qopen */ 331*e11c3f44Smeem NULL, /* qi_qclose */ 332*e11c3f44Smeem NULL, /* qi_qadmin */ 333*e11c3f44Smeem &ds_minfo, /* qi_minfo */ 334*e11c3f44Smeem }; 335*e11c3f44Smeem 336*e11c3f44Smeem static struct streamtab ds_info = { 337*e11c3f44Smeem &ds_rinit, /* st_rdinit */ 338*e11c3f44Smeem &ds_winit /* st_wrinit */ 339*e11c3f44Smeem }; 340*e11c3f44Smeem 341*e11c3f44Smeem DDI_DEFINE_STREAM_OPS(ds_ops, nulldev, nulldev, ds_attach, ds_detach, 342*e11c3f44Smeem nodev, ds_devinfo, D_MP|D_MTPERMOD, &ds_info, ddi_quiesce_not_supported); 343*e11c3f44Smeem 344*e11c3f44Smeem static struct modldrv modldrv = { 345*e11c3f44Smeem &mod_driverops, 346*e11c3f44Smeem "DLPI stub driver", 347*e11c3f44Smeem &ds_ops, 348*e11c3f44Smeem }; 349*e11c3f44Smeem 350*e11c3f44Smeem static struct modlinkage modlinkage = { 351*e11c3f44Smeem MODREV_1, &modldrv, NULL 352*e11c3f44Smeem }; 353*e11c3f44Smeem 354*e11c3f44Smeem int 355*e11c3f44Smeem _init(void) 356*e11c3f44Smeem { 357*e11c3f44Smeem return (mod_install(&modlinkage)); 358*e11c3f44Smeem } 359*e11c3f44Smeem 360*e11c3f44Smeem int 361*e11c3f44Smeem _fini(void) 362*e11c3f44Smeem { 363*e11c3f44Smeem return (mod_remove(&modlinkage)); 364*e11c3f44Smeem } 365*e11c3f44Smeem 366*e11c3f44Smeem int 367*e11c3f44Smeem _info(struct modinfo *modinfop) 368*e11c3f44Smeem { 369*e11c3f44Smeem return (mod_info(&modlinkage, modinfop)); 370*e11c3f44Smeem } 371