xref: /titanic_44/usr/src/uts/common/io/dld/dld_drv.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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  * Data-Link Driver
31  */
32 
33 #include	<sys/types.h>
34 #include	<sys/stream.h>
35 #include	<sys/conf.h>
36 #include	<sys/stat.h>
37 #include	<sys/ddi.h>
38 #include	<sys/sunddi.h>
39 #include	<sys/dlpi.h>
40 #include	<sys/modctl.h>
41 #include	<sys/kmem.h>
42 #include	<inet/common.h>
43 
44 #include	<sys/dls.h>
45 #include	<sys/dld.h>
46 #include	<sys/dld_impl.h>
47 
48 static void	drv_init(void);
49 static int	drv_fini(void);
50 
51 static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
52 static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
53 static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
54 
55 static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
56 static int	drv_close(queue_t *);
57 
58 static void	drv_uw_put(queue_t *, mblk_t *);
59 static void	drv_uw_srv(queue_t *);
60 
61 dev_info_t	*dld_dip;		/* dev_info_t for the driver */
62 uint32_t	dld_opt;		/* Global options */
63 boolean_t	dld_open;		/* Flag to note that the control */
64 					/* node is open */
65 boolean_t	dld_aul = B_TRUE;	/* Set to B_FALSE to prevent driver */
66 					/* unloading */
67 
68 static kmutex_t	drv_lock;		/* Needs no initialization */
69 
70 static	struct	module_info	drv_info = {
71 	0,			/* mi_idnum */
72 	DLD_DRIVER_NAME,	/* mi_idname */
73 	0,			/* mi_minpsz */
74 	(64 * 1024),		/* mi_maxpsz */
75 	1,			/* mi_hiwat */
76 	0			/* mi_lowat */
77 };
78 
79 static	struct qinit		drv_ur_init = {
80 	NULL,			/* qi_putp */
81 	NULL,			/* qi_srvp */
82 	drv_open,		/* qi_qopen */
83 	drv_close,		/* qi_qclose */
84 	NULL,			/* qi_qadmin */
85 	&drv_info,		/* qi_minfo */
86 	NULL			/* qi_mstat */
87 };
88 
89 static	struct qinit		drv_uw_init = {
90 	(pfi_t)drv_uw_put,	/* qi_putp */
91 	(pfi_t)drv_uw_srv,	/* qi_srvp */
92 	NULL,			/* qi_qopen */
93 	NULL,			/* qi_qclose */
94 	NULL,			/* qi_qadmin */
95 	&drv_info,		/* qi_minfo */
96 	NULL			/* qi_mstat */
97 };
98 
99 static	struct streamtab	drv_stream = {
100 	&drv_ur_init,		/* st_rdinit */
101 	&drv_uw_init,		/* st_wrinit */
102 	NULL,			/* st_muxrinit */
103 	NULL			/* st_muxwinit */
104 };
105 
106 DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
107     nodev, drv_getinfo, D_MP | D_MTQPAIR | D_MTPUTSHARED, &drv_stream);
108 
109 /*
110  * Module linkage information for the kernel.
111  */
112 
113 extern	struct mod_ops		mod_driverops;
114 
115 static	struct modldrv		drv_modldrv = {
116 	&mod_driverops,
117 	DLD_INFO,
118 	&drv_ops
119 };
120 
121 static	struct modlinkage	drv_modlinkage = {
122 	MODREV_1,
123 	&drv_modldrv,
124 	NULL
125 };
126 
127 int
128 _init(void)
129 {
130 	int	err;
131 
132 	if ((err = mod_install(&drv_modlinkage)) != 0)
133 		return (err);
134 
135 #ifdef	DEBUG
136 	cmn_err(CE_NOTE, "!%s loaded", DLD_INFO);
137 #endif	/* DEBUG */
138 
139 	return (0);
140 }
141 
142 int
143 _fini(void)
144 {
145 	int	err;
146 
147 	if (!dld_aul)
148 		return (ENOTSUP);
149 
150 	if ((err = mod_remove(&drv_modlinkage)) != 0)
151 		return (err);
152 
153 #ifdef	DEBUG
154 	cmn_err(CE_NOTE, "!%s unloaded", DLD_INFO);
155 #endif	/* DEBUG */
156 
157 	return (err);
158 }
159 
160 int
161 _info(struct modinfo *modinfop)
162 {
163 	return (mod_info(&drv_modlinkage, modinfop));
164 }
165 
166 
167 /*
168  * Initialize compoment modules.
169  */
170 static void
171 drv_init(void)
172 {
173 	dld_minor_init();
174 	dld_node_init();
175 	dld_str_init();
176 	dld_ppa_init();
177 }
178 
179 static int
180 drv_fini(void)
181 {
182 	int	err;
183 
184 	if ((err = dld_ppa_fini()) != 0)
185 		return (err);
186 
187 	err = dld_str_fini();
188 	ASSERT(err == 0);
189 
190 	err = dld_node_fini();
191 	ASSERT(err == 0);
192 
193 	err = dld_minor_fini();
194 	ASSERT(err == 0);
195 
196 	return (0);
197 }
198 
199 /*
200  * devo_getinfo: getinfo(9e)
201  */
202 /*ARGSUSED*/
203 static int
204 drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
205 {
206 	if (dld_dip == NULL)
207 		return (DDI_FAILURE);
208 
209 	switch (cmd) {
210 	case DDI_INFO_DEVT2INSTANCE:
211 		*resp = (void *)0;
212 		break;
213 	case DDI_INFO_DEVT2DEVINFO:
214 		*resp = (void *)dld_dip;
215 		break;
216 	default:
217 		return (DDI_FAILURE);
218 	}
219 
220 	return (DDI_SUCCESS);
221 }
222 
223 /*
224  * Check properties to set options. (See dld.h for property definitions).
225  */
226 static void
227 drv_set_opt(dev_info_t *dip)
228 {
229 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
230 	    DLD_PROP_NO_STYLE1, 0) != 0) {
231 #ifdef	DEBUG
232 		cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_STYLE1);
233 #endif	/* DEBUG */
234 		dld_opt |= DLD_OPT_NO_STYLE1;
235 	}
236 
237 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
238 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
239 #ifdef	DEBUG
240 		cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_FASTPATH);
241 #endif	/* DEBUG */
242 		dld_opt |= DLD_OPT_NO_FASTPATH;
243 	}
244 
245 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
246 	    DLD_PROP_NO_POLL, 0) != 0) {
247 #ifdef	DEBUG
248 		cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_POLL);
249 #endif	/* DEBUG */
250 		dld_opt |= DLD_OPT_NO_POLL;
251 	}
252 
253 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
254 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
255 #ifdef	DEBUG
256 		cmn_err(CE_NOTE, "%s: ON", DLD_PROP_NO_ZEROCOPY);
257 #endif	/* DEBUG */
258 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
259 	}
260 }
261 
262 /*
263  * devo_attach: attach(9e)
264  */
265 static int
266 drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
267 {
268 	if (cmd != DDI_ATTACH)
269 		return (DDI_FAILURE);
270 
271 	ASSERT(ddi_get_instance(dip) == 0);
272 
273 	drv_init();
274 	drv_set_opt(dip);
275 
276 	/*
277 	 * Create control node. DLPI provider nodes will be created on demand.
278 	 */
279 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
280 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
281 		return (DDI_FAILURE);
282 
283 	dld_dip = dip;
284 
285 	/*
286 	 * Log the fact that the driver is now attached.
287 	 */
288 	ddi_report_dev(dip);
289 	return (DDI_SUCCESS);
290 }
291 
292 /*
293  * devo_detach: detach(9e)
294  */
295 static int
296 drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
297 {
298 	if (cmd != DDI_DETACH)
299 		return (DDI_FAILURE);
300 
301 	if (drv_fini() != 0)
302 		return (DDI_FAILURE);
303 
304 	ASSERT(dld_dip == dip);
305 
306 	/*
307 	 * Remove the control node.
308 	 */
309 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
310 	dld_dip = NULL;
311 
312 	return (DDI_SUCCESS);
313 }
314 
315 /*
316  * qi_qopen: open(9e)
317  */
318 /*ARGSUSED*/
319 static int
320 drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
321 {
322 	dld_str_t	*dsp;
323 	dld_node_t	*dnp;
324 	dld_ppa_t	*dpp;
325 	minor_t		minor;
326 	int		err;
327 
328 	ASSERT(sflag != MODOPEN);
329 
330 	/*
331 	 * This is a cloning driver and therefore each queue should only
332 	 * ever get opened once.
333 	 */
334 	ASSERT(rq->q_ptr == NULL);
335 	if (rq->q_ptr != NULL)
336 		return (EBUSY);
337 
338 	/*
339 	 * Grab the minor number of the dev_t that was opened. Because this
340 	 * is a cloning driver this will be distinct from the actual minor
341 	 * of the dev_t handed back.
342 	 */
343 	minor = getminor(*devp);
344 
345 	/*
346 	 * Create a new dld_str_t for the stream. This will grab a new minor
347 	 * number that will be handed back in the cloned dev_t.
348 	 */
349 	dsp = dld_str_create(rq);
350 
351 	if (minor != DLD_CONTROL_MINOR) {
352 		/*
353 		 * This is not the control node, so look up the DLPI
354 		 * provider node that is being opened.
355 		 */
356 		if ((dnp = dld_node_find(minor)) == NULL) {
357 			err = ENODEV;
358 			goto failed;
359 		}
360 
361 		dsp->ds_dnp = dnp;
362 		dsp->ds_type = DLD_DLPI;
363 
364 		ASSERT(dsp->ds_dlstate == DL_UNATTACHED);
365 		if (dnp->dn_style == DL_STYLE1) {
366 			/*
367 			 * This is a style 1 provider node so we have a
368 			 * non-ambiguous PPA.
369 			 */
370 			dpp = dld_node_ppa_find(dnp, -1);
371 
372 			if ((err = dld_str_attach(dsp, dpp)) != 0)
373 				goto failed;
374 			dsp->ds_dlstate = DL_UNBOUND;
375 		}
376 	} else {
377 		/*
378 		 * This is the control node. It is exclusive-access so
379 		 * verify that it is not already open.
380 		 */
381 		mutex_enter(&drv_lock);
382 		if (dld_open) {
383 			err = EBUSY;
384 			mutex_exit(&drv_lock);
385 			goto failed;
386 		}
387 
388 		dld_open = B_TRUE;
389 		mutex_exit(&drv_lock);
390 
391 		dsp->ds_type = DLD_CONTROL;
392 	}
393 
394 	/*
395 	 * Enable the queue srv(9e) routine.
396 	 */
397 	qprocson(rq);
398 
399 	/*
400 	 * Construct a cloned dev_t to hand back.
401 	 */
402 	*devp = makedevice(getmajor(*devp), dsp->ds_minor);
403 	return (0);
404 
405 failed:
406 	dld_str_destroy(dsp);
407 	return (err);
408 }
409 
410 /*
411  * qi_qclose: close(9e)
412  */
413 static int
414 drv_close(queue_t *rq)
415 {
416 	dld_str_t	*dsp;
417 
418 	dsp = rq->q_ptr;
419 	ASSERT(dsp != NULL);
420 
421 	/*
422 	 * Disable the queue srv(9e) routine.
423 	 */
424 	qprocsoff(rq);
425 
426 	if (dsp->ds_type != DLD_CONTROL) {
427 		/*
428 		 * This stream was open to a provider node. Check to see
429 		 * if it has been cleanly shut down.
430 		 */
431 		if (dsp->ds_dlstate != DL_UNATTACHED) {
432 			/*
433 			 * The stream is either open to a style 1 provider or
434 			 * this is not clean shutdown. Detach from the PPA.
435 			 * (This is still ok even in the style 1 case).
436 			 */
437 			dld_str_detach(dsp);
438 			dsp->ds_dlstate = DL_UNATTACHED;
439 		}
440 	} else {
441 		/*
442 		 * This stream was open to the control node. Clear the flag
443 		 * to allow another stream access.
444 		 */
445 		ASSERT(dld_open);
446 		dld_open = B_FALSE;
447 	}
448 
449 	dld_str_destroy(dsp);
450 	return (0);
451 }
452 
453 /*
454  * qi_qputp: put(9e)
455  */
456 static void
457 drv_uw_put(queue_t *wq, mblk_t *mp)
458 {
459 	dld_str_t	*dsp;
460 
461 	dsp = wq->q_ptr;
462 	ASSERT(dsp != NULL);
463 
464 	/*
465 	 * Call the put(9e) processor.
466 	 */
467 	dld_str_put(dsp, mp);
468 }
469 
470 /*
471  * qi_srvp: srv(9e)
472  */
473 static void
474 drv_uw_srv(queue_t *wq)
475 {
476 	mblk_t		*mp = NULL;
477 	mblk_t		*p;
478 	mblk_t		**pp;
479 	dld_str_t	*dsp;
480 
481 	dsp = wq->q_ptr;
482 	ASSERT(dsp != NULL);
483 
484 	/*
485 	 * Loop round and pull a chain of messages from the queue.
486 	 */
487 	for (pp = &mp; (p = getq(wq)) != NULL; pp = &(p->b_next))
488 		*pp = p;
489 
490 	/*
491 	 * If there was nothing on the queue then there's nothing to do.
492 	 */
493 	if (mp == NULL)
494 		return;
495 
496 	/*
497 	 * Call the srv(9e) processor.
498 	 */
499 	dld_str_srv(dsp, mp);
500 }
501