xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_dev.c (revision d6bb6a8465e557cb946ef49d56ed3202f6218652)
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;
58 
59 static void aggr_dev_init(void);
60 static int aggr_dev_fini(void);
61 static int aggr_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
62 static int aggr_attach(dev_info_t *, ddi_attach_cmd_t);
63 static int aggr_detach(dev_info_t *, ddi_detach_cmd_t);
64 static int aggr_open(queue_t *, dev_t *, int, int, cred_t *);
65 static int aggr_close(queue_t *);
66 static void aggr_wput(queue_t *, mblk_t *);
67 
68 /*
69  * mi_hiwat is set to 1 because of the flow control mechanism implemented
70  * in dld. refer to the comments in dld_str.c for details.
71  */
72 static struct module_info aggr_module_info = {
73 	0,
74 	AGGR_DRIVER_NAME,
75 	0,
76 	INFPSZ,
77 	1,
78 	0
79 };
80 
81 static struct qinit aggr_r_qinit = {	/* read queues */
82 	NULL,
83 	NULL,
84 	aggr_open,
85 	aggr_close,
86 	NULL,
87 	&aggr_module_info
88 };
89 
90 static struct qinit aggr_w_qinit = {	/* write queues */
91 	(pfi_t)dld_wput,
92 	(pfi_t)dld_wsrv,
93 	NULL,
94 	NULL,
95 	NULL,
96 	&aggr_module_info
97 };
98 
99 /*
100  * Entry points for aggr control node
101  */
102 static struct qinit aggr_w_ctl_qinit = {
103 	(pfi_t)aggr_wput,
104 	NULL,
105 	NULL,
106 	NULL,
107 	NULL,
108 	&aggr_module_info
109 };
110 
111 static struct streamtab aggr_streamtab = {
112 	&aggr_r_qinit,
113 	&aggr_w_qinit
114 };
115 
116 DDI_DEFINE_STREAM_OPS(aggr_dev_ops, nulldev, nulldev, aggr_attach, aggr_detach,
117     nodev, aggr_getinfo, D_MP, &aggr_streamtab);
118 
119 static struct modldrv aggr_modldrv = {
120 	&mod_driverops,		/* Type of module.  This one is a driver */
121 	AGGR_LINKINFO,		/* short description */
122 	&aggr_dev_ops		/* driver specific ops */
123 };
124 
125 static struct modlinkage modlinkage = {
126 	MODREV_1,
127 	&aggr_modldrv,
128 	NULL
129 };
130 
131 
132 int
133 _init(void)
134 {
135 	int err;
136 
137 	aggr_dev_init();
138 
139 	if ((err = mod_install(&modlinkage)) != 0) {
140 		(void) aggr_dev_fini();
141 		return (err);
142 	}
143 
144 	aggr_dip = NULL;
145 	return (0);
146 }
147 
148 int
149 _fini(void)
150 {
151 	int err;
152 
153 	if ((err = aggr_dev_fini()) != 0)
154 		return (err);
155 
156 	if ((err = mod_remove(&modlinkage)) != 0) {
157 		aggr_dev_init();
158 		return (err);
159 	}
160 
161 	return (0);
162 }
163 
164 int
165 _info(struct modinfo *modinfop)
166 {
167 	return (mod_info(&modlinkage, modinfop));
168 }
169 
170 static int
171 aggr_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
172 {
173 	if (q->q_ptr != NULL)
174 		return (EBUSY);
175 
176 	if (getminor(*devp) == AGGR_MINOR_CTL) {
177 		dld_str_t	*dsp;
178 
179 		dsp = dld_str_create(q, DLD_CONTROL, getmajor(*devp),
180 		    DL_STYLE1);
181 		if (dsp == NULL)
182 			return (ENOSR);
183 
184 		/*
185 		 * The aggr control node uses its own set of entry points.
186 		 */
187 		WR(q)->q_qinfo = &aggr_w_ctl_qinit;
188 		*devp = makedevice(getmajor(*devp), dsp->ds_minor);
189 		qprocson(q);
190 		return (0);
191 	}
192 	return (dld_open(q, devp, flag, sflag, credp));
193 }
194 
195 static int
196 aggr_close(queue_t *q)
197 {
198 	dld_str_t	*dsp = q->q_ptr;
199 
200 	if (dsp->ds_type == DLD_CONTROL) {
201 		qprocsoff(q);
202 		dld_str_destroy(dsp);
203 		return (0);
204 	}
205 	return (dld_close(q));
206 }
207 
208 static void
209 aggr_wput(queue_t *q, mblk_t *mp)
210 {
211 	if (DB_TYPE(mp) == M_IOCTL)
212 		aggr_ioctl(q, mp);
213 	else
214 		freemsg(mp);
215 }
216 
217 static void
218 aggr_dev_init(void)
219 {
220 	aggr_port_init();
221 	aggr_grp_init();
222 	aggr_lacp_init();
223 }
224 
225 static int
226 aggr_dev_fini(void)
227 {
228 	int err;
229 
230 	if ((err = aggr_grp_fini()) != 0)
231 		return (err);
232 	if ((err = aggr_port_fini()) != 0) {
233 		/*
234 		 * re-initialize the groups to keep a consistent
235 		 * state.
236 		 */
237 		aggr_grp_init();
238 	}
239 	aggr_lacp_fini();
240 
241 	return (err);
242 }
243 
244 /*ARGSUSED*/
245 static int
246 aggr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
247     void **result)
248 {
249 	switch (infocmd) {
250 	case DDI_INFO_DEVT2DEVINFO:
251 		*result = aggr_dip;
252 		return (DDI_SUCCESS);
253 	case DDI_INFO_DEVT2INSTANCE:
254 		*result = NULL;
255 		return (DDI_SUCCESS);
256 	}
257 	return (DDI_FAILURE);
258 }
259 
260 static int
261 aggr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
262 {
263 	switch (cmd) {
264 	case DDI_ATTACH:
265 		if (ddi_get_instance(dip) != 0) {
266 			/* we only allow instance 0 to attach */
267 			return (DDI_FAILURE);
268 		}
269 
270 		/* create minor node for control interface */
271 		if (ddi_create_minor_node(dip, AGGR_DEVNAME_CTL, S_IFCHR,
272 		    AGGR_MINOR_CTL, DDI_PSEUDO, 0) != DDI_SUCCESS) {
273 			return (DDI_FAILURE);
274 		}
275 
276 		aggr_dip = dip;
277 		return (DDI_SUCCESS);
278 
279 	case DDI_RESUME:
280 		return (DDI_SUCCESS);
281 
282 	default:
283 		return (DDI_FAILURE);
284 	}
285 }
286 
287 /*ARGSUSED*/
288 static int
289 aggr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
290 {
291 	switch (cmd) {
292 	case DDI_DETACH:
293 		if (aggr_grp_count() > 0)
294 			return (DDI_FAILURE);
295 
296 		aggr_dip = NULL;
297 		ddi_remove_minor_node(dip, AGGR_DEVNAME_CTL);
298 
299 		return (DDI_SUCCESS);
300 
301 	case DDI_SUSPEND:
302 		return (DDI_SUCCESS);
303 
304 	default:
305 		return (DDI_FAILURE);
306 	}
307 }
308