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
ds_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
ds_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
ds_devinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
ds_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)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
ds_close(queue_t * q,int flag,cred_t * credp)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
ds_badprim(queue_t * q,mblk_t * mp,t_scalar_t prim)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
ds_outstate(queue_t * q,mblk_t * mp,t_scalar_t prim)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
ds_wput(queue_t * q,mblk_t * mp)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
_init(void)355*e11c3f44Smeem _init(void)
356*e11c3f44Smeem {
357*e11c3f44Smeem return (mod_install(&modlinkage));
358*e11c3f44Smeem }
359*e11c3f44Smeem
360*e11c3f44Smeem int
_fini(void)361*e11c3f44Smeem _fini(void)
362*e11c3f44Smeem {
363*e11c3f44Smeem return (mod_remove(&modlinkage));
364*e11c3f44Smeem }
365*e11c3f44Smeem
366*e11c3f44Smeem int
_info(struct modinfo * modinfop)367*e11c3f44Smeem _info(struct modinfo *modinfop)
368*e11c3f44Smeem {
369*e11c3f44Smeem return (mod_info(&modlinkage, modinfop));
370*e11c3f44Smeem }
371