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