xref: /illumos-gate/usr/src/uts/common/io/dld/dld_drv.c (revision 210db2243d3b5ca39c96a4c34c6d9453ddfbeaa9)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Data-Link Driver
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include	<sys/conf.h>
34*210db224Sericheng #include	<sys/mkdev.h>
357c478bd9Sstevel@tonic-gate #include	<sys/modctl.h>
36*210db224Sericheng #include	<sys/stat.h>
37*210db224Sericheng #include	<sys/strsun.h>
387c478bd9Sstevel@tonic-gate #include	<sys/dld.h>
397c478bd9Sstevel@tonic-gate #include	<sys/dld_impl.h>
40*210db224Sericheng #include	<sys/dls_impl.h>
41*210db224Sericheng #include	<inet/common.h>
42*210db224Sericheng 
43*210db224Sericheng /*
44*210db224Sericheng  * dld control node state, one per open control node session.
45*210db224Sericheng  */
46*210db224Sericheng typedef struct dld_ctl_str_s {
47*210db224Sericheng 	minor_t cs_minor;
48*210db224Sericheng 	queue_t *cs_wq;
49*210db224Sericheng } dld_ctl_str_t;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static void	drv_init(void);
527c478bd9Sstevel@tonic-gate static int	drv_fini(void);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
557c478bd9Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
567c478bd9Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
577c478bd9Sstevel@tonic-gate 
58*210db224Sericheng /*
59*210db224Sericheng  * The following entry points are private to dld and are used for control
60*210db224Sericheng  * operations only. The entry points exported to mac drivers are defined
61*210db224Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
62*210db224Sericheng  */
637c478bd9Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
647c478bd9Sstevel@tonic-gate static int	drv_close(queue_t *);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
677c478bd9Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
70*210db224Sericheng uint32_t	dld_opt = 0;		/* Global options */
71*210db224Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static	struct	module_info	drv_info = {
747c478bd9Sstevel@tonic-gate 	0,			/* mi_idnum */
757c478bd9Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
767c478bd9Sstevel@tonic-gate 	0,			/* mi_minpsz */
777c478bd9Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
787c478bd9Sstevel@tonic-gate 	1,			/* mi_hiwat */
797c478bd9Sstevel@tonic-gate 	0			/* mi_lowat */
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
837c478bd9Sstevel@tonic-gate 	NULL,			/* qi_putp */
847c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
857c478bd9Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
867c478bd9Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
877c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
887c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
897c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
907c478bd9Sstevel@tonic-gate };
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
937c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
947c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
957c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
967c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
977c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
987c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
997c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1037c478bd9Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1047c478bd9Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1057c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1067c478bd9Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
110*210db224Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1197c478bd9Sstevel@tonic-gate 	&mod_driverops,
1207c478bd9Sstevel@tonic-gate 	DLD_INFO,
1217c478bd9Sstevel@tonic-gate 	&drv_ops
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1257c478bd9Sstevel@tonic-gate 	MODREV_1,
1267c478bd9Sstevel@tonic-gate 	&drv_modldrv,
1277c478bd9Sstevel@tonic-gate 	NULL
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate int
1317c478bd9Sstevel@tonic-gate _init(void)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	int	err;
1347c478bd9Sstevel@tonic-gate 
135*210db224Sericheng 	drv_init();
136*210db224Sericheng 
1377c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1387c478bd9Sstevel@tonic-gate 		return (err);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	return (0);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate int
1447c478bd9Sstevel@tonic-gate _fini(void)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	int	err;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1497c478bd9Sstevel@tonic-gate 		return (err);
1507c478bd9Sstevel@tonic-gate 
151*210db224Sericheng 	if (drv_fini() != 0) {
152*210db224Sericheng 		(void) mod_install(&drv_modlinkage);
153*210db224Sericheng 		return (DDI_FAILURE);
154*210db224Sericheng 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	return (err);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate int
1607c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
167*210db224Sericheng  * Initialize component modules.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate static void
1707c478bd9Sstevel@tonic-gate drv_init(void)
1717c478bd9Sstevel@tonic-gate {
172*210db224Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
173*210db224Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1747c478bd9Sstevel@tonic-gate 	dld_str_init();
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static int
1787c478bd9Sstevel@tonic-gate drv_fini(void)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	int	err;
1817c478bd9Sstevel@tonic-gate 
182*210db224Sericheng 	if ((err = dld_str_fini()) != 0)
1837c478bd9Sstevel@tonic-gate 		return (err);
1847c478bd9Sstevel@tonic-gate 
185*210db224Sericheng 	vmem_destroy(dld_ctl_vmem);
1867c478bd9Sstevel@tonic-gate 	return (0);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1937c478bd9Sstevel@tonic-gate static int
1947c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	if (dld_dip == NULL)
1977c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	switch (cmd) {
2007c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2017c478bd9Sstevel@tonic-gate 		*resp = (void *)0;
2027c478bd9Sstevel@tonic-gate 		break;
2037c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2047c478bd9Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2057c478bd9Sstevel@tonic-gate 		break;
2067c478bd9Sstevel@tonic-gate 	default:
2077c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate static void
2177c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2207c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2217c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2257c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2267c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2307c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2317c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * devo_attach: attach(9e)
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate static int
2397c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2427c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	drv_set_opt(dip);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/*
2497c478bd9Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2507c478bd9Sstevel@tonic-gate 	 */
2517c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2527c478bd9Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	dld_dip = dip;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2597c478bd9Sstevel@tonic-gate 	 */
2607c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
2617c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * devo_detach: detach(9e)
2667c478bd9Sstevel@tonic-gate  */
2677c478bd9Sstevel@tonic-gate static int
2687c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2717c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/*
2767c478bd9Sstevel@tonic-gate 	 * Remove the control node.
2777c478bd9Sstevel@tonic-gate 	 */
2787c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2797c478bd9Sstevel@tonic-gate 	dld_dip = NULL;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
285*210db224Sericheng  * dld control node open procedure.
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2887c478bd9Sstevel@tonic-gate static int
2897c478bd9Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2907c478bd9Sstevel@tonic-gate {
291*210db224Sericheng 	dld_ctl_str_t	*ctls;
2927c478bd9Sstevel@tonic-gate 	minor_t		minor;
293*210db224Sericheng 	queue_t *oq =	OTHERQ(rq);
2947c478bd9Sstevel@tonic-gate 
295*210db224Sericheng 	if (sflag == MODOPEN)
296*210db224Sericheng 		return (ENOTSUP);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
3007c478bd9Sstevel@tonic-gate 	 * ever get opened once.
3017c478bd9Sstevel@tonic-gate 	 */
3027c478bd9Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3037c478bd9Sstevel@tonic-gate 		return (EBUSY);
3047c478bd9Sstevel@tonic-gate 
305*210db224Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
306*210db224Sericheng 	if (minor == 0)
307*210db224Sericheng 		return (ENOMEM);
3087c478bd9Sstevel@tonic-gate 
309*210db224Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
310*210db224Sericheng 	if (ctls == NULL) {
311*210db224Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
312*210db224Sericheng 		return (ENOMEM);
313*210db224Sericheng 	}
3147c478bd9Sstevel@tonic-gate 
315*210db224Sericheng 	ctls->cs_minor = minor;
316*210db224Sericheng 	ctls->cs_wq = WR(rq);
3177c478bd9Sstevel@tonic-gate 
318*210db224Sericheng 	rq->q_ptr = ctls;
319*210db224Sericheng 	oq->q_ptr = ctls;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/*
3227c478bd9Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	qprocson(rq);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/*
3277c478bd9Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3287c478bd9Sstevel@tonic-gate 	 */
329*210db224Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3307c478bd9Sstevel@tonic-gate 	return (0);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate /*
334*210db224Sericheng  * dld control node close procedure.
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate static int
3377c478bd9Sstevel@tonic-gate drv_close(queue_t *rq)
3387c478bd9Sstevel@tonic-gate {
339*210db224Sericheng 	dld_ctl_str_t	*ctls;
3407c478bd9Sstevel@tonic-gate 
341*210db224Sericheng 	ctls = rq->q_ptr;
342*210db224Sericheng 	ASSERT(ctls != NULL);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/*
3457c478bd9Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3467c478bd9Sstevel@tonic-gate 	 */
3477c478bd9Sstevel@tonic-gate 	qprocsoff(rq);
3487c478bd9Sstevel@tonic-gate 
349*210db224Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
350*210db224Sericheng 
351*210db224Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	return (0);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
357*210db224Sericheng  * DLDIOCATTR
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate static void
360*210db224Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
3617c478bd9Sstevel@tonic-gate {
362*210db224Sericheng 	dld_ioc_attr_t *diap;
363*210db224Sericheng 	dls_vlan_t	*dvp = NULL;
364*210db224Sericheng 	dls_link_t	*dlp = NULL;
365*210db224Sericheng 	int		err;
366*210db224Sericheng 	queue_t		*q = ctls->cs_wq;
3677c478bd9Sstevel@tonic-gate 
368*210db224Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
369*210db224Sericheng 		goto failed;
3707c478bd9Sstevel@tonic-gate 
371*210db224Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
372*210db224Sericheng 	diap->dia_name[IFNAMSIZ - 1] = '\0';
373*210db224Sericheng 
374*210db224Sericheng 	if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) {
375*210db224Sericheng 		err = ENOENT;
376*210db224Sericheng 		goto failed;
377*210db224Sericheng 	}
378*210db224Sericheng 
379*210db224Sericheng 	dlp = dvp->dv_dlp;
380*210db224Sericheng 	(void) strlcpy(diap->dia_dev, dlp->dl_dev, MAXNAMELEN);
381*210db224Sericheng 	diap->dia_port = dlp->dl_port;
382*210db224Sericheng 	diap->dia_vid = dvp->dv_id;
383*210db224Sericheng 	diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max;
384*210db224Sericheng 
385*210db224Sericheng 	dls_vlan_rele(dvp);
386*210db224Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
387*210db224Sericheng 	return;
388*210db224Sericheng 
389*210db224Sericheng failed:
390*210db224Sericheng 	ASSERT(err != 0);
391*210db224Sericheng 	if (err == ENOENT) {
392*210db224Sericheng 		char	devname[MAXNAMELEN];
393*210db224Sericheng 		uint_t	instance;
394*210db224Sericheng 		major_t	major;
395*210db224Sericheng 
396*210db224Sericheng 		/*
397*210db224Sericheng 		 * Try to detect if the specified device is gldv3
398*210db224Sericheng 		 * and return ENODEV if it is not.
399*210db224Sericheng 		 */
400*210db224Sericheng 		if (ddi_parse(diap->dia_name, devname, &instance) == 0 &&
401*210db224Sericheng 		    (major = ddi_name_to_major(devname)) != (major_t)-1 &&
402*210db224Sericheng 		    !GLDV3_DRV(major))
403*210db224Sericheng 			err = ENODEV;
404*210db224Sericheng 	}
405*210db224Sericheng 	miocnak(q, mp, 0, err);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
408*210db224Sericheng 
4097c478bd9Sstevel@tonic-gate /*
410*210db224Sericheng  * DLDIOCVLAN
4117c478bd9Sstevel@tonic-gate  */
412*210db224Sericheng typedef struct dld_ioc_vlan_state {
413*210db224Sericheng 	uint_t		bytes_left;
414*210db224Sericheng 	uint_t		count;
415*210db224Sericheng 	dld_vlan_info_t	*vlanp;
416*210db224Sericheng } dld_ioc_vlan_state_t;
417*210db224Sericheng 
418*210db224Sericheng static int
419*210db224Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg)
420*210db224Sericheng {
421*210db224Sericheng 	dld_ioc_vlan_state_t	*statep = arg;
422*210db224Sericheng 
423*210db224Sericheng 	if (statep->bytes_left < sizeof (dld_vlan_info_t))
424*210db224Sericheng 		return (ENOSPC);
425*210db224Sericheng 
426*210db224Sericheng 	(void) strlcpy(statep->vlanp->dvi_name, dvp->dv_name, IFNAMSIZ);
427*210db224Sericheng 	statep->vlanp->dvi_vid = dvp->dv_id;
428*210db224Sericheng 
429*210db224Sericheng 	statep->count++;
430*210db224Sericheng 	statep->bytes_left -= sizeof (dld_vlan_info_t);
431*210db224Sericheng 	statep->vlanp += 1;
432*210db224Sericheng 	return (0);
433*210db224Sericheng }
434*210db224Sericheng 
4357c478bd9Sstevel@tonic-gate static void
436*210db224Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
4377c478bd9Sstevel@tonic-gate {
438*210db224Sericheng 	dld_ioc_vlan_t		*divp;
439*210db224Sericheng 	dld_ioc_vlan_state_t	state;
440*210db224Sericheng 	int			err = EINVAL;
441*210db224Sericheng 	queue_t			*q = ctls->cs_wq;
4427c478bd9Sstevel@tonic-gate 
443*210db224Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0)
444*210db224Sericheng 		goto failed;
4457c478bd9Sstevel@tonic-gate 
446*210db224Sericheng 	divp = (dld_ioc_vlan_t *)mp->b_cont->b_rptr;
447*210db224Sericheng 	state.bytes_left = MBLKL(mp->b_cont) - sizeof (dld_ioc_vlan_t);
448*210db224Sericheng 	state.count = 0;
449*210db224Sericheng 	state.vlanp = (dld_vlan_info_t *)(divp + 1);
4507c478bd9Sstevel@tonic-gate 
451*210db224Sericheng 	err = dls_vlan_walk(drv_ioc_vlan_info, &state);
452*210db224Sericheng 	if (err != 0)
453*210db224Sericheng 		goto failed;
454*210db224Sericheng 
455*210db224Sericheng 	divp->div_count = state.count;
456*210db224Sericheng 	miocack(q, mp, sizeof (dld_ioc_vlan_t) +
457*210db224Sericheng 	    state.count * sizeof (dld_vlan_info_t), 0);
458*210db224Sericheng 	return;
459*210db224Sericheng 
460*210db224Sericheng failed:
461*210db224Sericheng 	ASSERT(err != 0);
462*210db224Sericheng 	miocnak(q, mp, 0, err);
463*210db224Sericheng }
464*210db224Sericheng 
465*210db224Sericheng 
466*210db224Sericheng /*
467*210db224Sericheng  * Process an IOCTL message received by the control node.
468*210db224Sericheng  */
469*210db224Sericheng static void
470*210db224Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
471*210db224Sericheng {
472*210db224Sericheng 	uint_t	cmd;
473*210db224Sericheng 
474*210db224Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
475*210db224Sericheng 	switch (cmd) {
476*210db224Sericheng 	case DLDIOCATTR:
477*210db224Sericheng 		drv_ioc_attr(ctls, mp);
478*210db224Sericheng 		return;
479*210db224Sericheng 	case DLDIOCVLAN:
480*210db224Sericheng 		drv_ioc_vlan(ctls, mp);
4817c478bd9Sstevel@tonic-gate 		return;
482*210db224Sericheng 	default:
483*210db224Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
484*210db224Sericheng 		return;
485*210db224Sericheng 	}
486*210db224Sericheng }
4877c478bd9Sstevel@tonic-gate 
488*210db224Sericheng /*
489*210db224Sericheng  * Write side put routine of the dld control node.
490*210db224Sericheng  */
491*210db224Sericheng static void
492*210db224Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
493*210db224Sericheng {
494*210db224Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
495*210db224Sericheng 
496*210db224Sericheng 	switch (mp->b_datap->db_type) {
497*210db224Sericheng 	case M_IOCTL:
498*210db224Sericheng 		drv_ioc(ctls, mp);
499*210db224Sericheng 		break;
500*210db224Sericheng 	default:
501*210db224Sericheng 		freemsg(mp);
502*210db224Sericheng 		break;
503*210db224Sericheng 	}
504*210db224Sericheng }
505*210db224Sericheng 
506*210db224Sericheng /*
507*210db224Sericheng  * Write-side service procedure.
508*210db224Sericheng  */
509*210db224Sericheng void
510*210db224Sericheng drv_uw_srv(queue_t *q)
511*210db224Sericheng {
512*210db224Sericheng 	mblk_t *mp;
513*210db224Sericheng 
514*210db224Sericheng 	while (mp = getq(q))
515*210db224Sericheng 		drv_uw_put(q, mp);
5167c478bd9Sstevel@tonic-gate }
517