9348 mii: duplicate 'const' declaration specifier
[unleashed.git] / usr / src / uts / common / io / sad_conf.c
blob46a0add592a3853cd6523e7664036b160c155822
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Config dependent data structures for the Streams Administrative Driver
30 * (or "Ballad of the SAD Cafe").
32 #include <sys/types.h>
33 #include <sys/conf.h>
34 #include <sys/stream.h>
35 #include <sys/strsubr.h>
36 #include <sys/sad.h>
37 #include <sys/kmem.h>
38 #include <sys/sysmacros.h>
41 * Currently we store all the sad data in a hash table keyed by major
42 * number. This is far from ideal. It means that if a single device
43 * starts using lots of SAP_ONE entries all its entries will hash
44 * to the same bucket and we'll get very long chains for that bucket.
46 * Unfortunately, it's not possible to hash by a different key or to easily
47 * break up our one hash into seperate hashs. The reason is because
48 * the hash contains mixed data types. Ie, it has three different
49 * types of autopush nodes in it: SAP_ALL, SAP_RANGE, SAP_ONE. Not
50 * only does the hash table contain nodes of different types, but we
51 * have to be able to search the table with a node of one type that
52 * might match another node with a different type. (ie, we might search
53 * for a SAP_ONE node with a value that matches a SAP_ALL node in the
54 * hash, or vice versa.)
56 * An ideal solution would probably be an AVL tree sorted by major
57 * numbers. Each node in the AVL tree would have the following optional
58 * data associated with it:
59 * - a single SAP_ALL autopush node
60 * - an or avl tree or hash table of SAP_RANGE and SAP_ONE autopush
61 * nodes indexed by minor numbers. perhaps two separate tables,
62 * one for each type of autopush nodes.
64 * Note that regardless of how the data is stored there can't be any overlap
65 * stored between autopush nodes. For example, if there is a SAP_ALL node
66 * for a given major number then there can't be any SAP_RANGE or SAP_ONE
67 * nodes for that same major number.
71 * Private Internal Interfaces
73 /*ARGSUSED*/
74 static uint_t
75 sad_hash_alg(void *hash_data, mod_hash_key_t key)
77 struct apcommon *apc = (struct apcommon *)key;
79 ASSERT(sad_apc_verify(apc) == 0);
80 return (apc->apc_major);
84 * Compare hash keys based off of major, minor, lastminor, and type.
86 static int
87 sad_hash_keycmp(mod_hash_key_t key1, mod_hash_key_t key2)
89 struct apcommon *apc1 = (struct apcommon *)key1;
90 struct apcommon *apc2 = (struct apcommon *)key2;
92 ASSERT(sad_apc_verify(apc1) == 0);
93 ASSERT(sad_apc_verify(apc2) == 0);
95 /* Filter out cases where the major number doesn't match. */
96 if (apc1->apc_major != apc2->apc_major)
97 return (1);
99 /* If either type is SAP_ALL then we're done. */
100 if ((apc1->apc_cmd == SAP_ALL) || (apc2->apc_cmd == SAP_ALL))
101 return (0);
103 /* Deal with the case where both types are SAP_ONE. */
104 if ((apc1->apc_cmd == SAP_ONE) && (apc2->apc_cmd == SAP_ONE)) {
105 /* Check if the minor numbers match. */
106 return (apc1->apc_minor != apc2->apc_minor);
109 /* Deal with the case where both types are SAP_RANGE. */
110 if ((apc1->apc_cmd == SAP_RANGE) && (apc2->apc_cmd == SAP_RANGE)) {
111 /* Check for overlapping ranges. */
112 if ((apc1->apc_lastminor < apc2->apc_minor) ||
113 (apc1->apc_minor > apc2->apc_lastminor))
114 return (1);
115 return (0);
119 * We know that one type is SAP_ONE and the other is SAP_RANGE.
120 * So now let's do range matching.
122 if (apc1->apc_cmd == SAP_RANGE) {
123 ASSERT(apc2->apc_cmd == SAP_ONE);
124 if ((apc1->apc_lastminor < apc2->apc_minor) ||
125 (apc1->apc_minor > apc2->apc_minor))
126 return (1);
127 } else {
128 ASSERT(apc1->apc_cmd == SAP_ONE);
129 ASSERT(apc2->apc_cmd == SAP_RANGE);
130 if ((apc1->apc_minor < apc2->apc_minor) ||
131 (apc1->apc_minor > apc2->apc_lastminor))
132 return (1);
134 return (0);
137 /*ARGSUSED*/
138 static uint_t
139 sad_hash_free_value(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
141 struct autopush *ap = (struct autopush *)val;
143 ASSERT(ap->ap_cnt > 0);
144 if (--(ap->ap_cnt) == 0)
145 kmem_free(ap, sizeof (struct autopush));
147 return (MH_WALK_CONTINUE);
151 * External Interfaces
154 sad_apc_verify(struct apcommon *apc)
156 /* sanity check the number of modules to push */
157 if ((apc->apc_npush == 0) || (apc->apc_npush > MAXAPUSH) ||
158 (apc->apc_npush > nstrpush))
159 return (EINVAL);
161 /* Check for NODEV major vaule */
162 if (apc->apc_major == -1)
163 return (EINVAL);
165 switch (apc->apc_cmd) {
166 case SAP_ALL:
167 case SAP_ONE:
169 * Really, we'd like to be strict here and make sure that
170 * apc_lastminor is 0 (since setting apc_lastminor for
171 * SAP_ALL and SAP_ONE commands doesn't make any sense),
172 * but we can't since historically apc_lastminor has been
173 * silently ignored for non-SAP_RANGE commands.
175 break;
176 case SAP_RANGE:
177 if (apc->apc_lastminor <= apc->apc_minor)
178 return (ERANGE);
179 break;
180 default:
181 return (EINVAL);
183 return (0);
187 sad_ap_verify(struct autopush *ap)
189 int ret, i;
191 if ((ret = sad_apc_verify(&ap->ap_common)) != 0)
192 return (ret);
195 * Validate that the specified list of modules exist. Note that
196 * ap_npush has already been sanity checked by sad_apc_verify().
198 for (i = 0; i < ap->ap_npush; i++) {
199 ap->ap_list[i][FMNAMESZ] = '\0';
200 if (fmodsw_find(ap->ap_list[i], FMODSW_LOAD) == NULL)
201 return (EINVAL);
203 return (0);
206 struct autopush *
207 sad_ap_alloc(void)
209 struct autopush *ap_new;
211 ap_new = kmem_zalloc(sizeof (struct autopush), KM_SLEEP);
212 ap_new->ap_cnt = 1;
213 return (ap_new);
216 void
217 sad_ap_rele(struct autopush *ap, str_stack_t *ss)
219 mutex_enter(&ss->ss_sad_lock);
220 ASSERT(ap->ap_cnt > 0);
221 if (--(ap->ap_cnt) == 0) {
222 mutex_exit(&ss->ss_sad_lock);
223 kmem_free(ap, sizeof (struct autopush));
224 } else {
225 mutex_exit(&ss->ss_sad_lock);
229 void
230 sad_ap_insert(struct autopush *ap, str_stack_t *ss)
232 ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
233 ASSERT(sad_apc_verify(&ap->ap_common) == 0);
234 ASSERT(sad_ap_find(&ap->ap_common, ss) == NULL);
235 (void) mod_hash_insert(ss->ss_sad_hash, &ap->ap_common, ap);
238 void
239 sad_ap_remove(struct autopush *ap, str_stack_t *ss)
241 struct autopush *ap_removed = NULL;
243 ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
244 (void) mod_hash_remove(ss->ss_sad_hash, &ap->ap_common,
245 (mod_hash_val_t *)&ap_removed);
246 ASSERT(ap == ap_removed);
249 struct autopush *
250 sad_ap_find(struct apcommon *apc, str_stack_t *ss)
252 struct autopush *ap_result = NULL;
254 ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
255 ASSERT(sad_apc_verify(apc) == 0);
257 (void) mod_hash_find(ss->ss_sad_hash, apc,
258 (mod_hash_val_t *)&ap_result);
259 if (ap_result != NULL)
260 ap_result->ap_cnt++;
261 return (ap_result);
264 struct autopush *
265 sad_ap_find_by_dev(dev_t dev, str_stack_t *ss)
267 struct apcommon apc;
268 struct autopush *ap_result;
270 ASSERT(MUTEX_NOT_HELD(&ss->ss_sad_lock));
272 /* prepare an apcommon structure to search with */
273 apc.apc_cmd = SAP_ONE;
274 apc.apc_major = getmajor(dev);
275 apc.apc_minor = getminor(dev);
278 * the following values must be set but initialized to have a
279 * valid apcommon struct, but since we're only using this
280 * structure to do a query the values are never actually used.
282 apc.apc_npush = 1;
283 apc.apc_lastminor = 0;
285 mutex_enter(&ss->ss_sad_lock);
286 ap_result = sad_ap_find(&apc, ss);
287 mutex_exit(&ss->ss_sad_lock);
288 return (ap_result);
291 void
292 sad_initspace(str_stack_t *ss)
294 mutex_init(&ss->ss_sad_lock, NULL, MUTEX_DEFAULT, NULL);
295 ss->ss_sad_hash_nchains = 127;
296 ss->ss_sadcnt = 16;
298 ss->ss_saddev = kmem_zalloc(ss->ss_sadcnt * sizeof (struct saddev),
299 KM_SLEEP);
300 ss->ss_sad_hash = mod_hash_create_extended("sad_hash",
301 ss->ss_sad_hash_nchains, mod_hash_null_keydtor,
302 mod_hash_null_valdtor,
303 sad_hash_alg, NULL, sad_hash_keycmp, KM_SLEEP);
306 void
307 sad_freespace(str_stack_t *ss)
309 kmem_free(ss->ss_saddev, ss->ss_sadcnt * sizeof (struct saddev));
310 ss->ss_saddev = NULL;
312 mutex_enter(&ss->ss_sad_lock);
313 mod_hash_walk(ss->ss_sad_hash, sad_hash_free_value, NULL);
314 mod_hash_destroy_hash(ss->ss_sad_hash);
315 ss->ss_sad_hash = NULL;
316 mutex_exit(&ss->ss_sad_lock);
318 mutex_destroy(&ss->ss_sad_lock);