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