xref: /onnv-gate/usr/src/uts/common/io/str_conf.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 2004 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 #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/param.h>
31*0Sstevel@tonic-gate #include <sys/systm.h>
32*0Sstevel@tonic-gate #include <sys/conf.h>
33*0Sstevel@tonic-gate #include <sys/stream.h>
34*0Sstevel@tonic-gate #include <sys/strsubr.h>
35*0Sstevel@tonic-gate #include <sys/modctl.h>
36*0Sstevel@tonic-gate #include <sys/modhash.h>
37*0Sstevel@tonic-gate #include <sys/atomic.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include <sys/ddi.h>
40*0Sstevel@tonic-gate #include <sys/sunddi.h>
41*0Sstevel@tonic-gate #include <sys/t_lock.h>
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate /*
44*0Sstevel@tonic-gate  * This module provides the framework that manage STREAMS modules.
45*0Sstevel@tonic-gate  * fmodsw_alloc() is called from modconf.c as a result of a module calling
46*0Sstevel@tonic-gate  * mod_install() and fmodsw_free() is called as the result of the module
47*0Sstevel@tonic-gate  * calling mod_remove().
48*0Sstevel@tonic-gate  * fmodsw_find() will find the fmodsw_impl_t structure relating to a named
49*0Sstevel@tonic-gate  * module. There is no equivalent of driver major numbers for modules; the
50*0Sstevel@tonic-gate  * the database of fmodsw_impl_t structures is purely keyed by name and
51*0Sstevel@tonic-gate  * is hence a hash table to keep lookup cost to a minimum.
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * fmodsw_hash is the hash table that will be used to map module names to
56*0Sstevel@tonic-gate  * their fmodsw_impl_t structures. The hash function requires that the value is
57*0Sstevel@tonic-gate  * a power of 2 so this definition specifies the log of the hash table size.
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate #define	FMODSW_LOG_HASHSZ	8
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * Hash table and associated reader-writer lock
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  * NOTE: Because the lock is global data, it is initialized to zero and hence
65*0Sstevel@tonic-gate  *       a call to rw_init() is not required. Similarly all the pointers in
66*0Sstevel@tonic-gate  *       the hash table will be implicitly initialized to NULL.
67*0Sstevel@tonic-gate  */
68*0Sstevel@tonic-gate #define	FMODSW_HASHSZ		(1 << FMODSW_LOG_HASHSZ)
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate static fmodsw_impl_t	*fmodsw_hash[FMODSW_HASHSZ];
71*0Sstevel@tonic-gate static krwlock_t	fmodsw_lock;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate /*
74*0Sstevel@tonic-gate  * Debug code:
75*0Sstevel@tonic-gate  *
76*0Sstevel@tonic-gate  * This is not conditionally compiled since it may be useful to third
77*0Sstevel@tonic-gate  * parties when developing new modules.
78*0Sstevel@tonic-gate  */
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate #define	BUFSZ	512
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate #define	FMODSW_INIT		0x00000001
83*0Sstevel@tonic-gate #define	FMODSW_REGISTER		0x00000002
84*0Sstevel@tonic-gate #define	FMODSW_UNREGISTER	0x00000004
85*0Sstevel@tonic-gate #define	FMODSW_FIND		0x00000008
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate uint32_t	fmodsw_debug_flags = 0x00000000;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static void fmodsw_dprintf(uint_t flag, const char *fmt, ...) __KPRINTFLIKE(2);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /* PRINTFLIKE2 */
92*0Sstevel@tonic-gate static void
i_fmodsw_dprintf(uint_t flag,const char * fmt,...)93*0Sstevel@tonic-gate i_fmodsw_dprintf(uint_t flag, const char *fmt, ...)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate 	va_list	alist;
96*0Sstevel@tonic-gate 	char	buf[BUFSZ + 1];
97*0Sstevel@tonic-gate 	char	*ptr;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	if (fmodsw_debug_flags & flag) {
100*0Sstevel@tonic-gate 		va_start(alist, fmt);
101*0Sstevel@tonic-gate 		ptr = buf;
102*0Sstevel@tonic-gate 		(void) sprintf(ptr, "strmod debug: ");
103*0Sstevel@tonic-gate 		ptr += strlen(buf);
104*0Sstevel@tonic-gate 		(void) vsnprintf(ptr, buf + BUFSZ - ptr, fmt, alist);
105*0Sstevel@tonic-gate 		printf(buf);
106*0Sstevel@tonic-gate 		va_end(alist);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate /*
112*0Sstevel@tonic-gate  * Local functions:
113*0Sstevel@tonic-gate  */
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate #define	FMODSW_HASH(_key) \
116*0Sstevel@tonic-gate 	(uint_t)(((_key[0] << 4) | (_key[1] & 0x0f)) & (FMODSW_HASHSZ - 1))
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate #define	FMODSW_KEYCMP(_k1, _k2, _match)					\
119*0Sstevel@tonic-gate 	{								\
120*0Sstevel@tonic-gate 		char	*p1 = (char *)(_k1);				\
121*0Sstevel@tonic-gate 		char	*p2 = (char *)(_k2);				\
122*0Sstevel@tonic-gate 									\
123*0Sstevel@tonic-gate 		while (*p1 == *p2++) {					\
124*0Sstevel@tonic-gate 			if (*p1++ == '\0') {				\
125*0Sstevel@tonic-gate 				goto _match;				\
126*0Sstevel@tonic-gate 			}						\
127*0Sstevel@tonic-gate 		}							\
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static int
i_fmodsw_hash_insert(fmodsw_impl_t * fp)131*0Sstevel@tonic-gate i_fmodsw_hash_insert(fmodsw_impl_t *fp)
132*0Sstevel@tonic-gate {
133*0Sstevel@tonic-gate 	uint_t		bucket;
134*0Sstevel@tonic-gate 	fmodsw_impl_t	**pp;
135*0Sstevel@tonic-gate 	fmodsw_impl_t	*p;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	ASSERT(rw_write_held(&fmodsw_lock));
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	bucket = FMODSW_HASH(fp->f_name);
140*0Sstevel@tonic-gate 	for (pp = &(fmodsw_hash[bucket]); (p = *pp) != NULL;
141*0Sstevel@tonic-gate 	    pp = &(p->f_next))
142*0Sstevel@tonic-gate 		FMODSW_KEYCMP(p->f_name, fp->f_name, found);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	fp->f_next = p;
145*0Sstevel@tonic-gate 	*pp = fp;
146*0Sstevel@tonic-gate 	return (0);
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate found:
149*0Sstevel@tonic-gate 	return (EEXIST);
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate static int
i_fmodsw_hash_remove(const char * name,fmodsw_impl_t ** fpp)153*0Sstevel@tonic-gate i_fmodsw_hash_remove(const char *name, fmodsw_impl_t **fpp)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	uint_t		bucket;
156*0Sstevel@tonic-gate 	fmodsw_impl_t	**pp;
157*0Sstevel@tonic-gate 	fmodsw_impl_t	*p;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	ASSERT(rw_write_held(&fmodsw_lock));
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	bucket = FMODSW_HASH(name);
162*0Sstevel@tonic-gate 	for (pp = &(fmodsw_hash[bucket]); (p = *pp) != NULL;
163*0Sstevel@tonic-gate 	    pp = &(p->f_next))
164*0Sstevel@tonic-gate 		FMODSW_KEYCMP(p->f_name, name, found);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	return (ENOENT);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate found:
169*0Sstevel@tonic-gate 	if (p->f_ref > 0)
170*0Sstevel@tonic-gate 		return (EBUSY);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	*pp = p->f_next;
173*0Sstevel@tonic-gate 	*fpp = p;
174*0Sstevel@tonic-gate 	return (0);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate static int
i_fmodsw_hash_find(const char * name,fmodsw_impl_t ** fpp)178*0Sstevel@tonic-gate i_fmodsw_hash_find(const char *name, fmodsw_impl_t **fpp)
179*0Sstevel@tonic-gate {
180*0Sstevel@tonic-gate 	uint_t		bucket;
181*0Sstevel@tonic-gate 	fmodsw_impl_t	*p;
182*0Sstevel@tonic-gate 	int		rc = 0;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	ASSERT(rw_read_held(&fmodsw_lock));
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	bucket = FMODSW_HASH(name);
187*0Sstevel@tonic-gate 	for (p = fmodsw_hash[bucket]; p != NULL; p = p->f_next)
188*0Sstevel@tonic-gate 		FMODSW_KEYCMP(p->f_name, name, found);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	rc = ENOENT;
191*0Sstevel@tonic-gate found:
192*0Sstevel@tonic-gate 	*fpp = p;
193*0Sstevel@tonic-gate #ifdef	DEBUG
194*0Sstevel@tonic-gate 	if (p != NULL)
195*0Sstevel@tonic-gate 		p->f_hits++;
196*0Sstevel@tonic-gate #endif	/* DEBUG */
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	return (rc);
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate /*
203*0Sstevel@tonic-gate  * Exported functions:
204*0Sstevel@tonic-gate  */
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate int
fmodsw_register(const char * name,struct streamtab * str,int flag)207*0Sstevel@tonic-gate fmodsw_register(const char *name, struct streamtab *str, int flag)
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	fmodsw_impl_t	*fp;
210*0Sstevel@tonic-gate 	int		len;
211*0Sstevel@tonic-gate 	int		err;
212*0Sstevel@tonic-gate 	uint_t	qflag;
213*0Sstevel@tonic-gate 	uint_t	sqtype;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if ((len = strlen(name)) > FMNAMESZ)
216*0Sstevel@tonic-gate 		return (EINVAL);
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if ((fp = kmem_zalloc(sizeof (fmodsw_impl_t), KM_NOSLEEP)) == NULL)
219*0Sstevel@tonic-gate 		return (ENOMEM);
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	(void) strncpy(fp->f_name, name, len);
222*0Sstevel@tonic-gate 	fp->f_name[len] = '\0';
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0)
225*0Sstevel@tonic-gate 		goto failed;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	fp->f_str = str;
228*0Sstevel@tonic-gate 	fp->f_qflag = qflag;
229*0Sstevel@tonic-gate 	fp->f_sqtype = sqtype;
230*0Sstevel@tonic-gate 	if (qflag & (QPERMOD | QMTOUTPERIM))
231*0Sstevel@tonic-gate 		fp->f_dmp = hold_dm(str, qflag, sqtype);
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	rw_enter(&fmodsw_lock, RW_WRITER);
234*0Sstevel@tonic-gate 	if ((err = i_fmodsw_hash_insert(fp)) != 0) {
235*0Sstevel@tonic-gate 		rw_exit(&fmodsw_lock);
236*0Sstevel@tonic-gate 		goto failed;
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate 	rw_exit(&fmodsw_lock);
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	i_fmodsw_dprintf(FMODSW_REGISTER, "registered module '%s'\n", name);
241*0Sstevel@tonic-gate 	return (0);
242*0Sstevel@tonic-gate failed:
243*0Sstevel@tonic-gate 	i_fmodsw_dprintf(FMODSW_REGISTER, "failed to register module '%s'\n",
244*0Sstevel@tonic-gate 	    name);
245*0Sstevel@tonic-gate 	if (fp->f_dmp != NULL)
246*0Sstevel@tonic-gate 		rele_dm(fp->f_dmp);
247*0Sstevel@tonic-gate 	kmem_free(fp, sizeof (fmodsw_impl_t));
248*0Sstevel@tonic-gate 	return (err);
249*0Sstevel@tonic-gate }
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate int
fmodsw_unregister(const char * name)252*0Sstevel@tonic-gate fmodsw_unregister(const char *name)
253*0Sstevel@tonic-gate {
254*0Sstevel@tonic-gate 	fmodsw_impl_t	*fp;
255*0Sstevel@tonic-gate 	int		err;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	rw_enter(&fmodsw_lock, RW_WRITER);
258*0Sstevel@tonic-gate 	if ((err = i_fmodsw_hash_remove(name, &fp)) != 0) {
259*0Sstevel@tonic-gate 		rw_exit(&fmodsw_lock);
260*0Sstevel@tonic-gate 		goto failed;
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 	rw_exit(&fmodsw_lock);
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if (fp->f_dmp != NULL)
265*0Sstevel@tonic-gate 		rele_dm(fp->f_dmp);
266*0Sstevel@tonic-gate 	kmem_free(fp, sizeof (fmodsw_impl_t));
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	i_fmodsw_dprintf(FMODSW_UNREGISTER, "unregistered module '%s'\n",
269*0Sstevel@tonic-gate 	    name);
270*0Sstevel@tonic-gate 	return (0);
271*0Sstevel@tonic-gate failed:
272*0Sstevel@tonic-gate 	i_fmodsw_dprintf(FMODSW_UNREGISTER, "failed to unregister module "
273*0Sstevel@tonic-gate 	    "'%s'\n", name);
274*0Sstevel@tonic-gate 	return (err);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate fmodsw_impl_t *
fmodsw_find(const char * name,fmodsw_flags_t flags)278*0Sstevel@tonic-gate fmodsw_find(const char *name, fmodsw_flags_t flags)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	fmodsw_impl_t	*fp;
281*0Sstevel@tonic-gate 	int		id;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate try_again:
284*0Sstevel@tonic-gate 	rw_enter(&fmodsw_lock, RW_READER);
285*0Sstevel@tonic-gate 	if (i_fmodsw_hash_find(name, &fp) == 0) {
286*0Sstevel@tonic-gate 		if (flags & FMODSW_HOLD) {
287*0Sstevel@tonic-gate 			atomic_add_32(&(fp->f_ref), 1);	/* lock must be held */
288*0Sstevel@tonic-gate 			ASSERT(fp->f_ref > 0);
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 		rw_exit(&fmodsw_lock);
292*0Sstevel@tonic-gate 		return (fp);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 	rw_exit(&fmodsw_lock);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if (flags & FMODSW_LOAD) {
297*0Sstevel@tonic-gate 		if ((id = modload("strmod", (char *)name)) != -1) {
298*0Sstevel@tonic-gate 			i_fmodsw_dprintf(FMODSW_FIND,
299*0Sstevel@tonic-gate 			    "module '%s' loaded: id = %d\n", name, id);
300*0Sstevel@tonic-gate 			goto try_again;
301*0Sstevel@tonic-gate 		}
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	return (NULL);
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate void
fmodsw_rele(fmodsw_impl_t * fp)308*0Sstevel@tonic-gate fmodsw_rele(fmodsw_impl_t *fp)
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	ASSERT(fp->f_ref > 0);
311*0Sstevel@tonic-gate 	atomic_add_32(&(fp->f_ref), -1);
312*0Sstevel@tonic-gate }
313