5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License, Version 1.0 only
7 * (the "License"). You may not use this file except in compliance
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1988 AT&T */
29 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <sys/param.h>
38 #include <sys/cmn_err.h>
39 #include <sys/namei.h>
41 #include <sys/vfs_syscalls.h>
43 __strong_alias(ddi_strtol
,ddi_strtoul
)
46 * String to integer conversion routines.
48 * This file is derived from usr/src/common/util/strtol.c
50 * We cannot use the user land versions as there is no errno to report
51 * error in kernel. So the return value is used to return an error,
52 * and the result is stored in an extra parameter passed by reference.
53 * Otherwise, the following functions are identical to the user land
58 * We should have a kernel version of ctype.h.
60 #define isalnum(ch) (isalpha(ch) || isdigit(ch))
61 #define isalpha(ch) (isupper(ch) || islower(ch))
62 #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
63 #define islower(ch) ((ch) >= 'a' && (ch) <= 'z')
64 #define isspace(ch) (((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
65 ((ch) == '\t') || ((ch) == '\f'))
66 #define isupper(ch) ((ch) >= 'A' && (ch) <= 'Z')
67 #define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
68 ((ch) >= 'A' && (ch) <= 'F'))
71 (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
73 #define MBASE ('z' - 'a' + 1 + 10)
76 * The following macro is a local version of isalnum() which limits
77 * alphabetic characters to the ranges a-z and A-Z; locale dependent
78 * characters will not return 1. The members of a-z and A-Z are
79 * assumed to be in ascending order and contiguous
82 (isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
85 do_mkdirp(const char *path
)
87 struct lwp
*l
= curlwp
;
99 panic("Not an absolute path");
102 for (s
= path
;; s
= e
) {
103 e
= strchr(s
+ 1, '/');
107 strlcpy(here
, path
, e
- path
+ 1);
108 error
= do_sys_mkdir((const char *)here
, mode
, UIO_SYSSPACE
);
119 ddi_strtoul(const char *str
, char **nptr
, int base
, unsigned long *result
)
124 unsigned long multmax
;
126 const char **ptr
= (const char **)nptr
;
127 const unsigned char *ustr
= (const unsigned char *)str
;
129 if (ptr
!= (const char **)0)
130 *ptr
= (char *)ustr
; /* in case no number is formed */
131 if (base
< 0 || base
> MBASE
|| base
== 1) {
132 /* base is invalid -- should be a fatal error */
135 if (!isalnum(c
= *ustr
)) {
149 else if (ustr
[1] == 'x' || ustr
[1] == 'X')
154 * for any base > 10, the digits incrementally following
155 * 9 are assumed to be "abc...z" or "ABC...Z"
157 if (!lisalnum(c
) || (xx
= DIGIT(c
)) >= base
)
158 return (EINVAL
); /* no number formed */
159 if (base
== 16 && c
== '0' && (ustr
[1] == 'x' || ustr
[1] == 'X') &&
161 c
= *(ustr
+= 2); /* skip over leading "0x" or "0X" */
163 multmax
= ULONG_MAX
/ (unsigned long)base
;
165 for (c
= *++ustr
; lisalnum(c
) && (xx
= DIGIT(c
)) < base
; ) {
169 if (ULONG_MAX
- val
< xx
)
174 if (ptr
!= (const char **)0)
176 *result
= neg
? -val
: val
;
180 for (c
= *++ustr
; lisalnum(c
) && (xx
= DIGIT(c
)) < base
; (c
= *++ustr
))
182 if (ptr
!= (const char **)0)
188 * Find first bit set in a mask (returned counting from 1 up)
198 * Find last bit set. Take mask and clear
199 * all but the most significant bit, and
200 * then let ffs do the rest of the work.
202 * Algorithm courtesy of Steve Chessin.
211 if ((nx
= (mask
& (mask
- 1))) == 0)
219 * The next five routines comprise generic storage management utilities
220 * for driver soft state structures (in "the old days," this was done
221 * with a statically sized array - big systems and dynamic loading
222 * and unloading make heap allocation more attractive)
226 * Allocate a set of pointers to 'n_items' objects of size 'size'
227 * bytes. Each pointer is initialized to nil.
229 * The 'size' and 'n_items' values are stashed in the opaque
230 * handle returned to the caller.
232 * This implementation interprets 'set of pointers' to mean 'array
233 * of pointers' but note that nothing in the interface definition
234 * precludes an implementation that uses, for example, a linked list.
235 * However there should be a small efficiency gain from using an array
238 * NOTE As an optimization, we make our growable array allocations in
239 * powers of two (bytes), since that's how much kmem_alloc (currently)
240 * gives us anyway. It should save us some free/realloc's ..
242 * As a further optimization, we make the growable array start out
243 * with MIN_N_ITEMS in it.
247 * This data structure is entirely private to the soft state allocator.
249 struct i_ddi_soft_state
{
250 void **array
; /* the array of pointers */
251 kmutex_t lock
; /* serialize access to this struct */
252 size_t size
; /* how many bytes per state struct */
253 size_t n_items
; /* how many structs herein */
254 struct i_ddi_soft_state
*next
; /* 'dirty' elements */
257 #define MIN_N_ITEMS 8 /* 8 void *'s == 32 bytes */
260 ddi_soft_state_init(void **state_p
, size_t size
, size_t n_items
)
262 struct i_ddi_soft_state
*ss
;
264 if (state_p
== NULL
|| *state_p
!= NULL
|| size
== 0)
267 ss
= kmem_zalloc(sizeof (*ss
), KM_SLEEP
);
268 mutex_init(&ss
->lock
, NULL
, MUTEX_DRIVER
, NULL
);
271 if (n_items
< MIN_N_ITEMS
)
272 ss
->n_items
= MIN_N_ITEMS
;
276 if ((bitlog
= ddi_fls(n_items
)) == ddi_ffs(n_items
))
278 ss
->n_items
= 1 << bitlog
;
281 ASSERT(ss
->n_items
>= n_items
);
283 ss
->array
= kmem_zalloc(ss
->n_items
* sizeof (void *), KM_SLEEP
);
292 * Allocate a state structure of size 'size' to be associated
295 * In this implementation, the array is extended to
296 * allow the requested offset, if needed.
299 ddi_soft_state_zalloc(void *state
, int item
)
301 struct i_ddi_soft_state
*ss
;
305 if ((ss
= state
) == NULL
|| item
< 0)
306 return (DDI_FAILURE
);
308 mutex_enter(&ss
->lock
);
310 mutex_exit(&ss
->lock
);
311 cmn_err(CE_WARN
, "ddi_soft_state_zalloc: bad handle");
312 return (DDI_FAILURE
);
315 array
= ss
->array
; /* NULL if ss->n_items == 0 */
316 ASSERT(ss
->n_items
!= 0 && array
!= NULL
);
319 * refuse to tread on an existing element
321 if (item
< ss
->n_items
&& array
[item
] != NULL
) {
322 mutex_exit(&ss
->lock
);
323 return (DDI_FAILURE
);
327 * Allocate a new element to plug in
329 new_element
= kmem_zalloc(ss
->size
, KM_SLEEP
);
332 * Check if the array is big enough, if not, grow it.
334 if (item
>= ss
->n_items
) {
337 struct i_ddi_soft_state
*dirty
;
340 * Allocate a new array of the right length, copy
341 * all the old pointers to the new array, then
342 * if it exists at all, put the old array on the
345 * Note that we can't kmem_free() the old array.
347 * Why -- well the 'get' operation is 'mutex-free', so we
348 * can't easily catch a suspended thread that is just about
349 * to dereference the array we just grew out of. So we
350 * cons up a header and put it on a list of 'dirty'
351 * pointer arrays. (Dirty in the sense that there may
352 * be suspended threads somewhere that are in the middle
353 * of referencing them). Fortunately, we -can- garbage
354 * collect it all at ddi_soft_state_fini time.
356 new_n_items
= ss
->n_items
;
357 while (new_n_items
< (1 + item
))
358 new_n_items
<<= 1; /* double array size .. */
360 ASSERT(new_n_items
>= (1 + item
)); /* sanity check! */
362 new_array
= kmem_zalloc(new_n_items
* sizeof (void *),
365 * Copy the pointers into the new array
367 bcopy(array
, new_array
, ss
->n_items
* sizeof (void *));
370 * Save the old array on the dirty list
372 dirty
= kmem_zalloc(sizeof (*dirty
), KM_SLEEP
);
373 dirty
->array
= ss
->array
;
374 dirty
->n_items
= ss
->n_items
;
375 dirty
->next
= ss
->next
;
378 ss
->array
= (array
= new_array
);
379 ss
->n_items
= new_n_items
;
382 ASSERT(array
!= NULL
&& item
< ss
->n_items
&& array
[item
] == NULL
);
384 array
[item
] = new_element
;
386 mutex_exit(&ss
->lock
);
387 return (DDI_SUCCESS
);
392 * Fetch a pointer to the allocated soft state structure.
394 * This is designed to be cheap.
396 * There's an argument that there should be more checking for
397 * nil pointers and out of bounds on the array.. but we do a lot
398 * of that in the alloc/free routines.
400 * An array has the convenience that we don't need to lock read-access
401 * to it c.f. a linked list. However our "expanding array" strategy
402 * means that we should hold a readers lock on the i_ddi_soft_state
405 * However, from a performance viewpoint, we need to do it without
406 * any locks at all -- this also makes it a leaf routine. The algorithm
407 * is 'lock-free' because we only discard the pointer arrays at
408 * ddi_soft_state_fini() time.
411 ddi_get_soft_state(void *state
, int item
)
413 struct i_ddi_soft_state
*ss
= state
;
415 ASSERT(ss
!= NULL
&& item
>= 0);
417 if (item
< ss
->n_items
&& ss
->array
!= NULL
)
418 return (ss
->array
[item
]);
423 * Free the state structure corresponding to 'item.' Freeing an
424 * element that has either gone or was never allocated is not
425 * considered an error. Note that we free the state structure, but
426 * we don't shrink our pointer array, or discard 'dirty' arrays,
427 * since even a few pointers don't really waste too much memory.
429 * Passing an item number that is out of bounds, or a null pointer will
430 * provoke an error message.
433 ddi_soft_state_free(void *state
, int item
)
435 struct i_ddi_soft_state
*ss
;
438 static char msg
[] = "ddi_soft_state_free:";
440 if ((ss
= state
) == NULL
) {
441 cmn_err(CE_WARN
, "%s null handle",
448 mutex_enter(&ss
->lock
);
450 if ((array
= ss
->array
) == NULL
|| ss
->size
== 0) {
451 cmn_err(CE_WARN
, "%s bad handle",
453 } else if (item
< 0 || item
>= ss
->n_items
) {
454 cmn_err(CE_WARN
, "%s item %d not in range [0..%lu]",
455 msg
, item
, ss
->n_items
- 1);
456 } else if (array
[item
] != NULL
) {
457 element
= array
[item
];
461 mutex_exit(&ss
->lock
);
464 kmem_free(element
, ss
->size
);
469 * Free the entire set of pointers, and any
470 * soft state structures contained therein.
472 * Note that we don't grab the ss->lock mutex, even though
473 * we're inspecting the various fields of the data structure.
475 * There is an implicit assumption that this routine will
476 * never run concurrently with any of the above on this
477 * particular state structure i.e. by the time the driver
478 * calls this routine, there should be no other threads
479 * running in the driver.
482 ddi_soft_state_fini(void **state_p
)
484 struct i_ddi_soft_state
*ss
, *dirty
;
486 static char msg
[] = "ddi_soft_state_fini:";
488 if (state_p
== NULL
|| (ss
= *state_p
) == NULL
) {
489 cmn_err(CE_WARN
, "%s null handle",
495 cmn_err(CE_WARN
, "%s bad handle",
500 if (ss
->n_items
> 0) {
501 for (item
= 0; item
< ss
->n_items
; item
++)
502 ddi_soft_state_free(ss
, item
);
503 kmem_free(ss
->array
, ss
->n_items
* sizeof (void *));
507 * Now delete any dirty arrays from previous 'grow' operations
509 for (dirty
= ss
->next
; dirty
; dirty
= ss
->next
) {
510 ss
->next
= dirty
->next
;
511 kmem_free(dirty
->array
, dirty
->n_items
* sizeof (void *));
512 kmem_free(dirty
, sizeof (*dirty
));
515 mutex_destroy(&ss
->lock
);
516 kmem_free(ss
, sizeof (*ss
));
522 ddi_create_minor_node(dev_info_t
*dip
, char *name
, int spec_type
,
523 minor_t minor_num
, char *node_type
, int flag
)
525 struct lwp
*l
= curlwp
;
531 printf("ddi_create_minor_node: name %s\n", name
);
533 dev
= makedev(flag
, minor_num
);
536 if (spec_type
== S_IFCHR
)
537 snprintf(pn
, MAXPATHLEN
, "/dev/zvol/rdsk/%s", name
);
539 snprintf(pn
, MAXPATHLEN
, "/dev/zvol/dsk/%s", name
);
541 if ((error
= do_mkdirp(pn
)) != 0)
544 error
= do_sys_mknod(l
, (const char *)pn
, spec_type
, dev
, &ret
, UIO_SYSSPACE
);
553 ddi_remove_minor_node(dev_info_t
*dip
, char *name
)
559 snprintf(pn
, MAXPATHLEN
, "/dev/zvol/dsk/%s", name
);
560 (void)do_sys_unlink(pn
, UIO_SYSSPACE
);
563 /* We need to remove raw and block device nodes */
565 snprintf(pn
, MAXPATHLEN
, "/dev/zvol/rdsk/%s", name
);
566 (void)do_sys_unlink(pn
, UIO_SYSSPACE
);