xref: /onnv-gate/usr/src/uts/common/io/dld/dld_drv.c (revision 733:6872c0c268a4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Data-Link Driver
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include	<sys/conf.h>
34269Sericheng #include	<sys/mkdev.h>
35269Sericheng #include	<sys/modctl.h>
360Sstevel@tonic-gate #include	<sys/stat.h>
37269Sericheng #include	<sys/strsun.h>
38269Sericheng #include	<sys/dld.h>
39269Sericheng #include	<sys/dld_impl.h>
40269Sericheng #include	<sys/dls_impl.h>
410Sstevel@tonic-gate #include	<inet/common.h>
420Sstevel@tonic-gate 
43269Sericheng /*
44269Sericheng  * dld control node state, one per open control node session.
45269Sericheng  */
46269Sericheng typedef struct dld_ctl_str_s {
47269Sericheng 	minor_t cs_minor;
48269Sericheng 	queue_t *cs_wq;
49269Sericheng } dld_ctl_str_t;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static void	drv_init(void);
520Sstevel@tonic-gate static int	drv_fini(void);
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
550Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
560Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
570Sstevel@tonic-gate 
58269Sericheng /*
59269Sericheng  * The following entry points are private to dld and are used for control
60269Sericheng  * operations only. The entry points exported to mac drivers are defined
61269Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
62269Sericheng  */
630Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
640Sstevel@tonic-gate static int	drv_close(queue_t *);
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
670Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
70269Sericheng uint32_t	dld_opt = 0;		/* Global options */
71269Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static	struct	module_info	drv_info = {
740Sstevel@tonic-gate 	0,			/* mi_idnum */
750Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
760Sstevel@tonic-gate 	0,			/* mi_minpsz */
770Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
780Sstevel@tonic-gate 	1,			/* mi_hiwat */
790Sstevel@tonic-gate 	0			/* mi_lowat */
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
830Sstevel@tonic-gate 	NULL,			/* qi_putp */
840Sstevel@tonic-gate 	NULL,			/* qi_srvp */
850Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
860Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
870Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
880Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
890Sstevel@tonic-gate 	NULL			/* qi_mstat */
900Sstevel@tonic-gate };
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
930Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
940Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
950Sstevel@tonic-gate 	NULL,			/* qi_qopen */
960Sstevel@tonic-gate 	NULL,			/* qi_qclose */
970Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
980Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
990Sstevel@tonic-gate 	NULL			/* qi_mstat */
1000Sstevel@tonic-gate };
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1030Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1040Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1050Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1060Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
110269Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Module linkage information for the kernel.
1140Sstevel@tonic-gate  */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1190Sstevel@tonic-gate 	&mod_driverops,
1200Sstevel@tonic-gate 	DLD_INFO,
1210Sstevel@tonic-gate 	&drv_ops
1220Sstevel@tonic-gate };
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1250Sstevel@tonic-gate 	MODREV_1,
1260Sstevel@tonic-gate 	&drv_modldrv,
1270Sstevel@tonic-gate 	NULL
1280Sstevel@tonic-gate };
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate int
1310Sstevel@tonic-gate _init(void)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	int	err;
1340Sstevel@tonic-gate 
135269Sericheng 	drv_init();
136269Sericheng 
1370Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1380Sstevel@tonic-gate 		return (err);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	return (0);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
1440Sstevel@tonic-gate _fini(void)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	int	err;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1490Sstevel@tonic-gate 		return (err);
1500Sstevel@tonic-gate 
151269Sericheng 	if (drv_fini() != 0) {
152269Sericheng 		(void) mod_install(&drv_modlinkage);
153269Sericheng 		return (DDI_FAILURE);
154269Sericheng 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	return (err);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate int
1600Sstevel@tonic-gate _info(struct modinfo *modinfop)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
167269Sericheng  * Initialize component modules.
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate static void
1700Sstevel@tonic-gate drv_init(void)
1710Sstevel@tonic-gate {
172269Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
173269Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1740Sstevel@tonic-gate 	dld_str_init();
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static int
1780Sstevel@tonic-gate drv_fini(void)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	int	err;
1810Sstevel@tonic-gate 
182269Sericheng 	if ((err = dld_str_fini()) != 0)
1830Sstevel@tonic-gate 		return (err);
1840Sstevel@tonic-gate 
185269Sericheng 	vmem_destroy(dld_ctl_vmem);
1860Sstevel@tonic-gate 	return (0);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate /*ARGSUSED*/
1930Sstevel@tonic-gate static int
1940Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	if (dld_dip == NULL)
1970Sstevel@tonic-gate 		return (DDI_FAILURE);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	switch (cmd) {
2000Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2010Sstevel@tonic-gate 		*resp = (void *)0;
2020Sstevel@tonic-gate 		break;
2030Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2040Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2050Sstevel@tonic-gate 		break;
2060Sstevel@tonic-gate 	default:
2070Sstevel@tonic-gate 		return (DDI_FAILURE);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	return (DDI_SUCCESS);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate static void
2170Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2200Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2210Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2250Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2260Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2300Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2310Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * devo_attach: attach(9e)
2370Sstevel@tonic-gate  */
2380Sstevel@tonic-gate static int
2390Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2420Sstevel@tonic-gate 		return (DDI_FAILURE);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	drv_set_opt(dip);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2520Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2530Sstevel@tonic-gate 		return (DDI_FAILURE);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	dld_dip = dip;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	ddi_report_dev(dip);
2610Sstevel@tonic-gate 	return (DDI_SUCCESS);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  * devo_detach: detach(9e)
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate static int
2680Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2710Sstevel@tonic-gate 		return (DDI_FAILURE);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/*
2760Sstevel@tonic-gate 	 * Remove the control node.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2790Sstevel@tonic-gate 	dld_dip = NULL;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	return (DDI_SUCCESS);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
285269Sericheng  * dld control node open procedure.
2860Sstevel@tonic-gate  */
2870Sstevel@tonic-gate /*ARGSUSED*/
2880Sstevel@tonic-gate static int
2890Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2900Sstevel@tonic-gate {
291269Sericheng 	dld_ctl_str_t	*ctls;
2920Sstevel@tonic-gate 	minor_t		minor;
293269Sericheng 	queue_t *oq =	OTHERQ(rq);
2940Sstevel@tonic-gate 
295269Sericheng 	if (sflag == MODOPEN)
296269Sericheng 		return (ENOTSUP);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
3000Sstevel@tonic-gate 	 * ever get opened once.
3010Sstevel@tonic-gate 	 */
3020Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3030Sstevel@tonic-gate 		return (EBUSY);
3040Sstevel@tonic-gate 
305269Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
306269Sericheng 	if (minor == 0)
307269Sericheng 		return (ENOMEM);
3080Sstevel@tonic-gate 
309269Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
310269Sericheng 	if (ctls == NULL) {
311269Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
312269Sericheng 		return (ENOMEM);
313269Sericheng 	}
3140Sstevel@tonic-gate 
315269Sericheng 	ctls->cs_minor = minor;
316269Sericheng 	ctls->cs_wq = WR(rq);
3170Sstevel@tonic-gate 
318269Sericheng 	rq->q_ptr = ctls;
319269Sericheng 	oq->q_ptr = ctls;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/*
3220Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	qprocson(rq);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3280Sstevel@tonic-gate 	 */
329269Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3300Sstevel@tonic-gate 	return (0);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
334269Sericheng  * dld control node close procedure.
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate static int
3370Sstevel@tonic-gate drv_close(queue_t *rq)
3380Sstevel@tonic-gate {
339269Sericheng 	dld_ctl_str_t	*ctls;
3400Sstevel@tonic-gate 
341269Sericheng 	ctls = rq->q_ptr;
342269Sericheng 	ASSERT(ctls != NULL);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3460Sstevel@tonic-gate 	 */
3470Sstevel@tonic-gate 	qprocsoff(rq);
3480Sstevel@tonic-gate 
349269Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
3500Sstevel@tonic-gate 
351269Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
352269Sericheng 
3530Sstevel@tonic-gate 	return (0);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate /*
357269Sericheng  * DLDIOCATTR
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate static void
360269Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
3610Sstevel@tonic-gate {
362269Sericheng 	dld_ioc_attr_t *diap;
363269Sericheng 	dls_vlan_t	*dvp = NULL;
364269Sericheng 	dls_link_t	*dlp = NULL;
365269Sericheng 	int		err;
366269Sericheng 	queue_t		*q = ctls->cs_wq;
367269Sericheng 
368269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
369269Sericheng 		goto failed;
370269Sericheng 
371269Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
372269Sericheng 	diap->dia_name[IFNAMSIZ - 1] = '\0';
373269Sericheng 
374269Sericheng 	if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) {
375269Sericheng 		err = ENOENT;
376269Sericheng 		goto failed;
377269Sericheng 	}
378269Sericheng 
379269Sericheng 	dlp = dvp->dv_dlp;
380269Sericheng 	(void) strlcpy(diap->dia_dev, dlp->dl_dev, MAXNAMELEN);
381269Sericheng 	diap->dia_port = dlp->dl_port;
382269Sericheng 	diap->dia_vid = dvp->dv_id;
383269Sericheng 	diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max;
384269Sericheng 
385269Sericheng 	dls_vlan_rele(dvp);
386269Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
387269Sericheng 	return;
388269Sericheng 
389269Sericheng failed:
390269Sericheng 	ASSERT(err != 0);
391269Sericheng 	if (err == ENOENT) {
392269Sericheng 		char	devname[MAXNAMELEN];
393269Sericheng 		uint_t	instance;
394269Sericheng 		major_t	major;
395269Sericheng 
396269Sericheng 		/*
397269Sericheng 		 * Try to detect if the specified device is gldv3
398269Sericheng 		 * and return ENODEV if it is not.
399269Sericheng 		 */
400269Sericheng 		if (ddi_parse(diap->dia_name, devname, &instance) == 0 &&
401269Sericheng 		    (major = ddi_name_to_major(devname)) != (major_t)-1 &&
402269Sericheng 		    !GLDV3_DRV(major))
403269Sericheng 			err = ENODEV;
404269Sericheng 	}
405269Sericheng 	miocnak(q, mp, 0, err);
406269Sericheng }
407269Sericheng 
408269Sericheng 
409269Sericheng /*
410269Sericheng  * DLDIOCVLAN
411269Sericheng  */
412269Sericheng typedef struct dld_ioc_vlan_state {
413269Sericheng 	uint_t		bytes_left;
414*733Skrgopi 	dld_ioc_vlan_t	*divp;
415269Sericheng 	dld_vlan_info_t	*vlanp;
416269Sericheng } dld_ioc_vlan_state_t;
417269Sericheng 
418269Sericheng static int
419269Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg)
420269Sericheng {
421269Sericheng 	dld_ioc_vlan_state_t	*statep = arg;
4220Sstevel@tonic-gate 
423*733Skrgopi 	/*
424*733Skrgopi 	 * passed buffer space is limited to 65536 bytes. So
425*733Skrgopi 	 * copy only the vlans associated with the passed link.
426*733Skrgopi 	 */
427*733Skrgopi 	if (strcmp(dvp->dv_dlp->dl_dev, statep->divp->div_name) == 0 &&
428*733Skrgopi 	    dvp->dv_dlp->dl_port == statep->divp->div_port &&
429*733Skrgopi 	    dvp->dv_id != 0) {
430*733Skrgopi 		if (statep->bytes_left < sizeof (dld_vlan_info_t))
431*733Skrgopi 			return (ENOSPC);
432269Sericheng 
433*733Skrgopi 		(void) strlcpy(statep->vlanp->dvi_name,
434*733Skrgopi 		    dvp->dv_name, IFNAMSIZ);
435*733Skrgopi 		statep->divp->div_count++;
436*733Skrgopi 		statep->bytes_left -= sizeof (dld_vlan_info_t);
437*733Skrgopi 		statep->vlanp += 1;
438*733Skrgopi 	}
439269Sericheng 	return (0);
440269Sericheng }
441269Sericheng 
442269Sericheng static void
443269Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
444269Sericheng {
445269Sericheng 	dld_ioc_vlan_t		*divp;
446269Sericheng 	dld_ioc_vlan_state_t	state;
447269Sericheng 	int			err = EINVAL;
448269Sericheng 	queue_t			*q = ctls->cs_wq;
449*733Skrgopi 	mblk_t			*bp;
450269Sericheng 
451269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0)
452269Sericheng 		goto failed;
453269Sericheng 
454*733Skrgopi 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
455*733Skrgopi 		goto failed;
456*733Skrgopi 
457*733Skrgopi 	freemsg(mp->b_cont);
458*733Skrgopi 	mp->b_cont = bp;
459*733Skrgopi 	divp = (dld_ioc_vlan_t *)bp->b_rptr;
460*733Skrgopi 	divp->div_count = 0;
461*733Skrgopi 	state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t);
462*733Skrgopi 	state.divp = divp;
463269Sericheng 	state.vlanp = (dld_vlan_info_t *)(divp + 1);
464269Sericheng 
465269Sericheng 	err = dls_vlan_walk(drv_ioc_vlan_info, &state);
466269Sericheng 	if (err != 0)
467269Sericheng 		goto failed;
4680Sstevel@tonic-gate 
469269Sericheng 	miocack(q, mp, sizeof (dld_ioc_vlan_t) +
470*733Skrgopi 	    state.divp->div_count * sizeof (dld_vlan_info_t), 0);
471269Sericheng 	return;
472269Sericheng 
473269Sericheng failed:
474269Sericheng 	ASSERT(err != 0);
475269Sericheng 	miocnak(q, mp, 0, err);
476269Sericheng }
477269Sericheng 
478269Sericheng 
479269Sericheng /*
480269Sericheng  * Process an IOCTL message received by the control node.
481269Sericheng  */
482269Sericheng static void
483269Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
484269Sericheng {
485269Sericheng 	uint_t	cmd;
486269Sericheng 
487269Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
488269Sericheng 	switch (cmd) {
489269Sericheng 	case DLDIOCATTR:
490269Sericheng 		drv_ioc_attr(ctls, mp);
491269Sericheng 		return;
492269Sericheng 	case DLDIOCVLAN:
493269Sericheng 		drv_ioc_vlan(ctls, mp);
494269Sericheng 		return;
495269Sericheng 	default:
496269Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
497269Sericheng 		return;
498269Sericheng 	}
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /*
502269Sericheng  * Write side put routine of the dld control node.
5030Sstevel@tonic-gate  */
5040Sstevel@tonic-gate static void
505269Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
5060Sstevel@tonic-gate {
507269Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
5080Sstevel@tonic-gate 
509269Sericheng 	switch (mp->b_datap->db_type) {
510269Sericheng 	case M_IOCTL:
511269Sericheng 		drv_ioc(ctls, mp);
512269Sericheng 		break;
513269Sericheng 	default:
514269Sericheng 		freemsg(mp);
515269Sericheng 		break;
516269Sericheng 	}
517269Sericheng }
5180Sstevel@tonic-gate 
519269Sericheng /*
520269Sericheng  * Write-side service procedure.
521269Sericheng  */
522269Sericheng void
523269Sericheng drv_uw_srv(queue_t *q)
524269Sericheng {
525269Sericheng 	mblk_t *mp;
5260Sstevel@tonic-gate 
527269Sericheng 	while (mp = getq(q))
528269Sericheng 		drv_uw_put(q, mp);
5290Sstevel@tonic-gate }
530