xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_dev.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * IEEE 802.3ad Link Aggregation.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/sysmacros.h>
34 #include <sys/conf.h>
35 #include <sys/cmn_err.h>
36 #include <sys/list.h>
37 #include <sys/ksynch.h>
38 #include <sys/kmem.h>
39 #include <sys/stream.h>
40 #include <sys/strsun.h>
41 #include <sys/modctl.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/atomic.h>
45 #include <sys/stat.h>
46 
47 #include <sys/dld_impl.h>
48 #include <sys/aggr.h>
49 #include <sys/aggr_impl.h>
50 #include <inet/common.h>
51 
52 /* module description */
53 #define	AGGR_LINKINFO	"Link Aggregation MAC"
54 #define	AGGR_DRIVER_NAME	"aggr"
55 
56 /* device info ptr, only one for instance 0 */
57 dev_info_t *aggr_dip = NULL;
58 
59 static int aggr_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
60 static int aggr_attach(dev_info_t *, ddi_attach_cmd_t);
61 static int aggr_detach(dev_info_t *, ddi_detach_cmd_t);
62 static int aggr_open(queue_t *, dev_t *, int, int, cred_t *);
63 static int aggr_close(queue_t *);
64 static void aggr_wput(queue_t *, mblk_t *);
65 
66 /*
67  * mi_hiwat is set to 1 because of the flow control mechanism implemented
68  * in dld. refer to the comments in dld_str.c for details.
69  */
70 static struct module_info aggr_module_info = {
71 	0,
72 	AGGR_DRIVER_NAME,
73 	0,
74 	INFPSZ,
75 	1,
76 	0
77 };
78 
79 static struct qinit aggr_r_qinit = {	/* read queues */
80 	NULL,
81 	NULL,
82 	aggr_open,
83 	aggr_close,
84 	NULL,
85 	&aggr_module_info
86 };
87 
88 static struct qinit aggr_w_qinit = {	/* write queues */
89 	(pfi_t)dld_wput,
90 	(pfi_t)dld_wsrv,
91 	NULL,
92 	NULL,
93 	NULL,
94 	&aggr_module_info
95 };
96 
97 /*
98  * Entry points for aggr control node
99  */
100 static struct qinit aggr_w_ctl_qinit = {
101 	(pfi_t)aggr_wput,
102 	NULL,
103 	NULL,
104 	NULL,
105 	NULL,
106 	&aggr_module_info
107 };
108 
109 static struct streamtab aggr_streamtab = {
110 	&aggr_r_qinit,
111 	&aggr_w_qinit
112 };
113 
114 DDI_DEFINE_STREAM_OPS(aggr_dev_ops, nulldev, nulldev, aggr_attach, aggr_detach,
115     nodev, aggr_getinfo, D_MP, &aggr_streamtab);
116 
117 static struct modldrv aggr_modldrv = {
118 	&mod_driverops,		/* Type of module.  This one is a driver */
119 	AGGR_LINKINFO,		/* short description */
120 	&aggr_dev_ops		/* driver specific ops */
121 };
122 
123 static struct modlinkage modlinkage = {
124 	MODREV_1,
125 	&aggr_modldrv,
126 	NULL
127 };
128 
129 
130 int
131 _init(void)
132 {
133 	return (mod_install(&modlinkage));
134 }
135 
136 int
137 _fini(void)
138 {
139 	return (mod_remove(&modlinkage));
140 }
141 
142 int
143 _info(struct modinfo *modinfop)
144 {
145 	return (mod_info(&modlinkage, modinfop));
146 }
147 
148 static int
149 aggr_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
150 {
151 	if (q->q_ptr != NULL)
152 		return (EBUSY);
153 
154 	if (getminor(*devp) == AGGR_MINOR_CTL) {
155 		dld_str_t	*dsp;
156 
157 		dsp = dld_str_create(q, DLD_CONTROL, getmajor(*devp),
158 		    DL_STYLE1);
159 		if (dsp == NULL)
160 			return (ENOSR);
161 
162 		/*
163 		 * The aggr control node uses its own set of entry points.
164 		 */
165 		WR(q)->q_qinfo = &aggr_w_ctl_qinit;
166 		*devp = makedevice(getmajor(*devp), dsp->ds_minor);
167 		qprocson(q);
168 		return (0);
169 	}
170 	return (dld_open(q, devp, flag, sflag, credp));
171 }
172 
173 static int
174 aggr_close(queue_t *q)
175 {
176 	dld_str_t	*dsp = q->q_ptr;
177 
178 	if (dsp->ds_type == DLD_CONTROL) {
179 		qprocsoff(q);
180 		dld_str_destroy(dsp);
181 		return (0);
182 	}
183 	return (dld_close(q));
184 }
185 
186 static void
187 aggr_wput(queue_t *q, mblk_t *mp)
188 {
189 	if (DB_TYPE(mp) == M_IOCTL)
190 		aggr_ioctl(q, mp);
191 	else
192 		freemsg(mp);
193 }
194 
195 /*ARGSUSED*/
196 static int
197 aggr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
198     void **result)
199 {
200 	switch (infocmd) {
201 	case DDI_INFO_DEVT2DEVINFO:
202 		*result = aggr_dip;
203 		return (DDI_SUCCESS);
204 	case DDI_INFO_DEVT2INSTANCE:
205 		*result = NULL;
206 		return (DDI_SUCCESS);
207 	}
208 	return (DDI_FAILURE);
209 }
210 
211 static int
212 aggr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
213 {
214 	switch (cmd) {
215 	case DDI_ATTACH:
216 		if (ddi_get_instance(dip) != 0) {
217 			/* we only allow instance 0 to attach */
218 			return (DDI_FAILURE);
219 		}
220 
221 		/* create minor node for control interface */
222 		if (ddi_create_minor_node(dip, AGGR_DEVNAME_CTL, S_IFCHR,
223 		    AGGR_MINOR_CTL, DDI_PSEUDO, 0) != DDI_SUCCESS) {
224 			return (DDI_FAILURE);
225 		}
226 
227 		aggr_dip = dip;
228 		aggr_port_init();
229 		aggr_grp_init();
230 		aggr_lacp_init();
231 		return (DDI_SUCCESS);
232 
233 	case DDI_RESUME:
234 		return (DDI_SUCCESS);
235 
236 	default:
237 		return (DDI_FAILURE);
238 	}
239 }
240 
241 /*ARGSUSED*/
242 static int
243 aggr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
244 {
245 	switch (cmd) {
246 	case DDI_DETACH:
247 		if (aggr_grp_count() > 0)
248 			return (DDI_FAILURE);
249 
250 		aggr_dip = NULL;
251 		ddi_remove_minor_node(dip, AGGR_DEVNAME_CTL);
252 		aggr_port_fini();
253 		aggr_grp_fini();
254 		aggr_lacp_fini();
255 		return (DDI_SUCCESS);
256 
257 	case DDI_SUSPEND:
258 		return (DDI_SUCCESS);
259 
260 	default:
261 		return (DDI_FAILURE);
262 	}
263 }
264