xref: /illumos-gate/usr/src/uts/common/io/dld/dld_drv.c (revision ba2e4443695ee6a6f420a35cd4fc3d3346d22932)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*ba2e4443Sseb  * Common Development and Distribution License (the "License").
6*ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*ba2e4443Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Data-Link Driver
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include	<sys/conf.h>
33210db224Sericheng #include	<sys/mkdev.h>
347c478bd9Sstevel@tonic-gate #include	<sys/modctl.h>
35210db224Sericheng #include	<sys/stat.h>
36210db224Sericheng #include	<sys/strsun.h>
377c478bd9Sstevel@tonic-gate #include	<sys/dld.h>
387c478bd9Sstevel@tonic-gate #include	<sys/dld_impl.h>
39210db224Sericheng #include	<sys/dls_impl.h>
40210db224Sericheng #include	<inet/common.h>
41210db224Sericheng 
42210db224Sericheng /*
43210db224Sericheng  * dld control node state, one per open control node session.
44210db224Sericheng  */
45210db224Sericheng typedef struct dld_ctl_str_s {
46210db224Sericheng 	minor_t cs_minor;
47210db224Sericheng 	queue_t *cs_wq;
48210db224Sericheng } dld_ctl_str_t;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void	drv_init(void);
517c478bd9Sstevel@tonic-gate static int	drv_fini(void);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
547c478bd9Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
557c478bd9Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
567c478bd9Sstevel@tonic-gate 
57210db224Sericheng /*
58210db224Sericheng  * The following entry points are private to dld and are used for control
59210db224Sericheng  * operations only. The entry points exported to mac drivers are defined
60210db224Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
61210db224Sericheng  */
627c478bd9Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
637c478bd9Sstevel@tonic-gate static int	drv_close(queue_t *);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
667c478bd9Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
69210db224Sericheng uint32_t	dld_opt = 0;		/* Global options */
70210db224Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static	struct	module_info	drv_info = {
737c478bd9Sstevel@tonic-gate 	0,			/* mi_idnum */
747c478bd9Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
757c478bd9Sstevel@tonic-gate 	0,			/* mi_minpsz */
767c478bd9Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
777c478bd9Sstevel@tonic-gate 	1,			/* mi_hiwat */
787c478bd9Sstevel@tonic-gate 	0			/* mi_lowat */
797c478bd9Sstevel@tonic-gate };
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
827c478bd9Sstevel@tonic-gate 	NULL,			/* qi_putp */
837c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
847c478bd9Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
857c478bd9Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
867c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
877c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
887c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
927c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
937c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
947c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
957c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
967c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
977c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
987c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1027c478bd9Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1037c478bd9Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1047c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1057c478bd9Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1067c478bd9Sstevel@tonic-gate };
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
109210db224Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1187c478bd9Sstevel@tonic-gate 	&mod_driverops,
1197c478bd9Sstevel@tonic-gate 	DLD_INFO,
1207c478bd9Sstevel@tonic-gate 	&drv_ops
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1247c478bd9Sstevel@tonic-gate 	MODREV_1,
1257c478bd9Sstevel@tonic-gate 	&drv_modldrv,
1267c478bd9Sstevel@tonic-gate 	NULL
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate int
1307c478bd9Sstevel@tonic-gate _init(void)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	int	err;
1337c478bd9Sstevel@tonic-gate 
134210db224Sericheng 	drv_init();
135210db224Sericheng 
1367c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1377c478bd9Sstevel@tonic-gate 		return (err);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	return (0);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate int
1437c478bd9Sstevel@tonic-gate _fini(void)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	int	err;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1487c478bd9Sstevel@tonic-gate 		return (err);
1497c478bd9Sstevel@tonic-gate 
150210db224Sericheng 	if (drv_fini() != 0) {
151210db224Sericheng 		(void) mod_install(&drv_modlinkage);
152210db224Sericheng 		return (DDI_FAILURE);
153210db224Sericheng 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	return (err);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate int
1597c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
166210db224Sericheng  * Initialize component modules.
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate static void
1697c478bd9Sstevel@tonic-gate drv_init(void)
1707c478bd9Sstevel@tonic-gate {
171210db224Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
172210db224Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1737c478bd9Sstevel@tonic-gate 	dld_str_init();
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate static int
1777c478bd9Sstevel@tonic-gate drv_fini(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	int	err;
1807c478bd9Sstevel@tonic-gate 
181210db224Sericheng 	if ((err = dld_str_fini()) != 0)
1827c478bd9Sstevel@tonic-gate 		return (err);
1837c478bd9Sstevel@tonic-gate 
184210db224Sericheng 	vmem_destroy(dld_ctl_vmem);
1857c478bd9Sstevel@tonic-gate 	return (0);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1927c478bd9Sstevel@tonic-gate static int
1937c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	if (dld_dip == NULL)
1967c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	switch (cmd) {
1997c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2007c478bd9Sstevel@tonic-gate 		*resp = (void *)0;
2017c478bd9Sstevel@tonic-gate 		break;
2027c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2037c478bd9Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2047c478bd9Sstevel@tonic-gate 		break;
2057c478bd9Sstevel@tonic-gate 	default:
2067c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate static void
2167c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2197c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2207c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2247c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2257c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2297c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2307c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * devo_attach: attach(9e)
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate static int
2387c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2417c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	drv_set_opt(dip);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/*
2487c478bd9Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2497c478bd9Sstevel@tonic-gate 	 */
2507c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2517c478bd9Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2527c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	dld_dip = dip;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2587c478bd9Sstevel@tonic-gate 	 */
2597c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
2607c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate  * devo_detach: detach(9e)
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate static int
2677c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2707c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/*
2757c478bd9Sstevel@tonic-gate 	 * Remove the control node.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2787c478bd9Sstevel@tonic-gate 	dld_dip = NULL;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
284210db224Sericheng  * dld control node open procedure.
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2877c478bd9Sstevel@tonic-gate static int
2887c478bd9Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2897c478bd9Sstevel@tonic-gate {
290210db224Sericheng 	dld_ctl_str_t	*ctls;
2917c478bd9Sstevel@tonic-gate 	minor_t		minor;
292210db224Sericheng 	queue_t *oq =	OTHERQ(rq);
2937c478bd9Sstevel@tonic-gate 
294210db224Sericheng 	if (sflag == MODOPEN)
295210db224Sericheng 		return (ENOTSUP);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/*
2987c478bd9Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
2997c478bd9Sstevel@tonic-gate 	 * ever get opened once.
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3027c478bd9Sstevel@tonic-gate 		return (EBUSY);
3037c478bd9Sstevel@tonic-gate 
304210db224Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
305210db224Sericheng 	if (minor == 0)
306210db224Sericheng 		return (ENOMEM);
3077c478bd9Sstevel@tonic-gate 
308210db224Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
309210db224Sericheng 	if (ctls == NULL) {
310210db224Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
311210db224Sericheng 		return (ENOMEM);
312210db224Sericheng 	}
3137c478bd9Sstevel@tonic-gate 
314210db224Sericheng 	ctls->cs_minor = minor;
315210db224Sericheng 	ctls->cs_wq = WR(rq);
3167c478bd9Sstevel@tonic-gate 
317210db224Sericheng 	rq->q_ptr = ctls;
318210db224Sericheng 	oq->q_ptr = ctls;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	qprocson(rq);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3277c478bd9Sstevel@tonic-gate 	 */
328210db224Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3297c478bd9Sstevel@tonic-gate 	return (0);
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
333210db224Sericheng  * dld control node close procedure.
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate static int
3367c478bd9Sstevel@tonic-gate drv_close(queue_t *rq)
3377c478bd9Sstevel@tonic-gate {
338210db224Sericheng 	dld_ctl_str_t	*ctls;
3397c478bd9Sstevel@tonic-gate 
340210db224Sericheng 	ctls = rq->q_ptr;
341210db224Sericheng 	ASSERT(ctls != NULL);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	qprocsoff(rq);
3477c478bd9Sstevel@tonic-gate 
348210db224Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
349210db224Sericheng 
350210db224Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	return (0);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /*
356210db224Sericheng  * DLDIOCATTR
3577c478bd9Sstevel@tonic-gate  */
3587c478bd9Sstevel@tonic-gate static void
359210db224Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
3607c478bd9Sstevel@tonic-gate {
361*ba2e4443Sseb 	dld_ioc_attr_t	*diap;
362210db224Sericheng 	dls_vlan_t	*dvp = NULL;
363210db224Sericheng 	dls_link_t	*dlp = NULL;
364210db224Sericheng 	int		err;
365210db224Sericheng 	queue_t		*q = ctls->cs_wq;
3667c478bd9Sstevel@tonic-gate 
367210db224Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
368210db224Sericheng 		goto failed;
3697c478bd9Sstevel@tonic-gate 
370210db224Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
371210db224Sericheng 	diap->dia_name[IFNAMSIZ - 1] = '\0';
372210db224Sericheng 
373210db224Sericheng 	if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) {
374210db224Sericheng 		err = ENOENT;
375210db224Sericheng 		goto failed;
376210db224Sericheng 	}
377210db224Sericheng 
378210db224Sericheng 	dlp = dvp->dv_dlp;
379*ba2e4443Sseb 	(void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev));
380210db224Sericheng 	diap->dia_vid = dvp->dv_id;
381210db224Sericheng 	diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max;
382210db224Sericheng 
383210db224Sericheng 	dls_vlan_rele(dvp);
384210db224Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
385210db224Sericheng 	return;
386210db224Sericheng 
387210db224Sericheng failed:
388210db224Sericheng 	ASSERT(err != 0);
389210db224Sericheng 	if (err == ENOENT) {
390210db224Sericheng 		char	devname[MAXNAMELEN];
391210db224Sericheng 		uint_t	instance;
392210db224Sericheng 		major_t	major;
393210db224Sericheng 
394210db224Sericheng 		/*
395210db224Sericheng 		 * Try to detect if the specified device is gldv3
396210db224Sericheng 		 * and return ENODEV if it is not.
397210db224Sericheng 		 */
398210db224Sericheng 		if (ddi_parse(diap->dia_name, devname, &instance) == 0 &&
399210db224Sericheng 		    (major = ddi_name_to_major(devname)) != (major_t)-1 &&
400210db224Sericheng 		    !GLDV3_DRV(major))
401210db224Sericheng 			err = ENODEV;
402210db224Sericheng 	}
403210db224Sericheng 	miocnak(q, mp, 0, err);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
406210db224Sericheng 
4077c478bd9Sstevel@tonic-gate /*
408210db224Sericheng  * DLDIOCVLAN
4097c478bd9Sstevel@tonic-gate  */
410210db224Sericheng typedef struct dld_ioc_vlan_state {
411210db224Sericheng 	uint_t		bytes_left;
412aae21359Skrgopi 	dld_ioc_vlan_t	*divp;
413210db224Sericheng 	dld_vlan_info_t	*vlanp;
414210db224Sericheng } dld_ioc_vlan_state_t;
415210db224Sericheng 
416210db224Sericheng static int
417210db224Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg)
418210db224Sericheng {
419210db224Sericheng 	dld_ioc_vlan_state_t	*statep = arg;
420210db224Sericheng 
421aae21359Skrgopi 	/*
422aae21359Skrgopi 	 * passed buffer space is limited to 65536 bytes. So
423aae21359Skrgopi 	 * copy only the vlans associated with the passed link.
424aae21359Skrgopi 	 */
425*ba2e4443Sseb 	if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 &&
426aae21359Skrgopi 	    dvp->dv_id != 0) {
427aae21359Skrgopi 		if (statep->bytes_left < sizeof (dld_vlan_info_t))
428aae21359Skrgopi 			return (ENOSPC);
429aae21359Skrgopi 
430aae21359Skrgopi 		(void) strlcpy(statep->vlanp->dvi_name,
431aae21359Skrgopi 		    dvp->dv_name, IFNAMSIZ);
432aae21359Skrgopi 		statep->divp->div_count++;
433aae21359Skrgopi 		statep->bytes_left -= sizeof (dld_vlan_info_t);
434aae21359Skrgopi 		statep->vlanp += 1;
435aae21359Skrgopi 	}
436210db224Sericheng 	return (0);
437210db224Sericheng }
438210db224Sericheng 
4397c478bd9Sstevel@tonic-gate static void
440210db224Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
4417c478bd9Sstevel@tonic-gate {
442210db224Sericheng 	dld_ioc_vlan_t		*divp;
443210db224Sericheng 	dld_ioc_vlan_state_t	state;
444210db224Sericheng 	int			err = EINVAL;
445210db224Sericheng 	queue_t			*q = ctls->cs_wq;
446aae21359Skrgopi 	mblk_t			*bp;
4477c478bd9Sstevel@tonic-gate 
448210db224Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0)
449210db224Sericheng 		goto failed;
4507c478bd9Sstevel@tonic-gate 
451aae21359Skrgopi 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
452aae21359Skrgopi 		goto failed;
453aae21359Skrgopi 
454aae21359Skrgopi 	freemsg(mp->b_cont);
455aae21359Skrgopi 	mp->b_cont = bp;
456aae21359Skrgopi 	divp = (dld_ioc_vlan_t *)bp->b_rptr;
457aae21359Skrgopi 	divp->div_count = 0;
458aae21359Skrgopi 	state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t);
459aae21359Skrgopi 	state.divp = divp;
460210db224Sericheng 	state.vlanp = (dld_vlan_info_t *)(divp + 1);
4617c478bd9Sstevel@tonic-gate 
462210db224Sericheng 	err = dls_vlan_walk(drv_ioc_vlan_info, &state);
463210db224Sericheng 	if (err != 0)
464210db224Sericheng 		goto failed;
465210db224Sericheng 
466210db224Sericheng 	miocack(q, mp, sizeof (dld_ioc_vlan_t) +
467aae21359Skrgopi 	    state.divp->div_count * sizeof (dld_vlan_info_t), 0);
468210db224Sericheng 	return;
469210db224Sericheng 
470210db224Sericheng failed:
471210db224Sericheng 	ASSERT(err != 0);
472210db224Sericheng 	miocnak(q, mp, 0, err);
473210db224Sericheng }
474210db224Sericheng 
475210db224Sericheng 
476210db224Sericheng /*
477210db224Sericheng  * Process an IOCTL message received by the control node.
478210db224Sericheng  */
479210db224Sericheng static void
480210db224Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
481210db224Sericheng {
482210db224Sericheng 	uint_t	cmd;
483210db224Sericheng 
484210db224Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
485210db224Sericheng 	switch (cmd) {
486210db224Sericheng 	case DLDIOCATTR:
487210db224Sericheng 		drv_ioc_attr(ctls, mp);
488210db224Sericheng 		return;
489210db224Sericheng 	case DLDIOCVLAN:
490210db224Sericheng 		drv_ioc_vlan(ctls, mp);
4917c478bd9Sstevel@tonic-gate 		return;
492210db224Sericheng 	default:
493210db224Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
494210db224Sericheng 		return;
495210db224Sericheng 	}
496210db224Sericheng }
4977c478bd9Sstevel@tonic-gate 
498210db224Sericheng /*
499210db224Sericheng  * Write side put routine of the dld control node.
500210db224Sericheng  */
501210db224Sericheng static void
502210db224Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
503210db224Sericheng {
504210db224Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
505210db224Sericheng 
506210db224Sericheng 	switch (mp->b_datap->db_type) {
507210db224Sericheng 	case M_IOCTL:
508210db224Sericheng 		drv_ioc(ctls, mp);
509210db224Sericheng 		break;
510210db224Sericheng 	default:
511210db224Sericheng 		freemsg(mp);
512210db224Sericheng 		break;
513210db224Sericheng 	}
514210db224Sericheng }
515210db224Sericheng 
516210db224Sericheng /*
517210db224Sericheng  * Write-side service procedure.
518210db224Sericheng  */
519210db224Sericheng void
520210db224Sericheng drv_uw_srv(queue_t *q)
521210db224Sericheng {
522210db224Sericheng 	mblk_t *mp;
523210db224Sericheng 
524210db224Sericheng 	while (mp = getq(q))
525210db224Sericheng 		drv_uw_put(q, mp);
5267c478bd9Sstevel@tonic-gate }
527