Home | History | Annotate | Line # | Download | only in kern
ddi.c revision 1.6
      1  1.1  haad 
      2  1.1  haad /*
      3  1.1  haad  * CDDL HEADER START
      4  1.1  haad  *
      5  1.1  haad  * The contents of this file are subject to the terms of the
      6  1.1  haad  * Common Development and Distribution License, Version 1.0 only
      7  1.1  haad  * (the "License").  You may not use this file except in compliance
      8  1.1  haad  * with the License.
      9  1.1  haad  *
     10  1.1  haad  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11  1.1  haad  * or http://www.opensolaris.org/os/licensing.
     12  1.1  haad  * See the License for the specific language governing permissions
     13  1.1  haad  * and limitations under the License.
     14  1.1  haad  *
     15  1.1  haad  * When distributing Covered Code, include this CDDL HEADER in each
     16  1.1  haad  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17  1.1  haad  * If applicable, add the following below this CDDL HEADER, with the
     18  1.1  haad  * fields enclosed by brackets "[]" replaced with your own identifying
     19  1.1  haad  * information: Portions Copyright [yyyy] [name of copyright owner]
     20  1.1  haad  *
     21  1.1  haad  * CDDL HEADER END
     22  1.1  haad  */
     23  1.1  haad /*
     24  1.1  haad  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     25  1.1  haad  * Use is subject to license terms.
     26  1.1  haad  */
     27  1.1  haad 
     28  1.1  haad /*	Copyright (c) 1988 AT&T	*/
     29  1.1  haad /*	All Rights Reserved */
     30  1.1  haad 
     31  1.6   chs /*-
     32  1.6   chs  * Copyright (c) 2010 Pawel Jakub Dawidek <pjd (at) FreeBSD.org>
     33  1.6   chs  * All rights reserved.
     34  1.6   chs  *
     35  1.6   chs  * Redistribution and use in source and binary forms, with or without
     36  1.6   chs  * modification, are permitted provided that the following conditions
     37  1.6   chs  * are met:
     38  1.6   chs  * 1. Redistributions of source code must retain the above copyright
     39  1.6   chs  *    notice, this list of conditions and the following disclaimer.
     40  1.6   chs  * 2. Redistributions in binary form must reproduce the above copyright
     41  1.6   chs  *    notice, this list of conditions and the following disclaimer in the
     42  1.6   chs  *    documentation and/or other materials provided with the distribution.
     43  1.6   chs  *
     44  1.6   chs  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
     45  1.6   chs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     46  1.6   chs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     47  1.6   chs  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
     48  1.6   chs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     49  1.6   chs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     50  1.6   chs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     51  1.6   chs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     52  1.6   chs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     53  1.6   chs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     54  1.6   chs  * SUCH DAMAGE.
     55  1.6   chs  */
     56  1.1  haad 
     57  1.1  haad #include <sys/types.h>
     58  1.6   chs #include <sys/sunddi.h>
     59  1.4  haad #include <sys/debug.h>
     60  1.1  haad #include <sys/errno.h>
     61  1.1  haad #include <sys/param.h>
     62  1.5   riz #include <sys/lwp.h>
     63  1.3  haad #include <sys/kernel.h>
     64  1.1  haad #include <sys/kmem.h>
     65  1.1  haad #include <sys/cmn_err.h>
     66  1.1  haad #include <sys/namei.h>
     67  1.1  haad #include <sys/stat.h>
     68  1.1  haad #include <sys/vfs_syscalls.h>
     69  1.1  haad 
     70  1.1  haad __strong_alias(ddi_strtol,ddi_strtoul)
     71  1.1  haad 
     72  1.1  haad /*
     73  1.1  haad  * String to integer conversion routines.
     74  1.1  haad  *
     75  1.1  haad  * This file is derived from usr/src/common/util/strtol.c
     76  1.1  haad  *
     77  1.1  haad  * We cannot use the user land versions as there is no errno to report
     78  1.1  haad  * error in kernel.  So the return value is used to return an error,
     79  1.1  haad  * and the result is stored in an extra parameter passed by reference.
     80  1.1  haad  * Otherwise, the following functions are identical to the user land
     81  1.1  haad  * versions.
     82  1.1  haad  */
     83  1.1  haad 
     84  1.1  haad /*
     85  1.1  haad  * We should have a kernel version of ctype.h.
     86  1.1  haad  */
     87  1.1  haad #define	isalnum(ch)	(isalpha(ch) || isdigit(ch))
     88  1.1  haad #define	isalpha(ch)	(isupper(ch) || islower(ch))
     89  1.1  haad #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
     90  1.1  haad #define	islower(ch)	((ch) >= 'a' && (ch) <= 'z')
     91  1.1  haad #define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
     92  1.1  haad 			((ch) == '\t') || ((ch) == '\f'))
     93  1.1  haad #define	isupper(ch)	((ch) >= 'A' && (ch) <= 'Z')
     94  1.1  haad #define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
     95  1.1  haad 			((ch) >= 'A' && (ch) <= 'F'))
     96  1.1  haad 
     97  1.1  haad #define	DIGIT(x)	\
     98  1.1  haad 	(isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
     99  1.1  haad 
    100  1.1  haad #define	MBASE	('z' - 'a' + 1 + 10)
    101  1.1  haad 
    102  1.1  haad /*
    103  1.1  haad  * The following macro is a local version of isalnum() which limits
    104  1.1  haad  * alphabetic characters to the ranges a-z and A-Z; locale dependent
    105  1.1  haad  * characters will not return 1. The members of a-z and A-Z are
    106  1.1  haad  * assumed to be in ascending order and contiguous
    107  1.1  haad  */
    108  1.1  haad #define	lisalnum(x)	\
    109  1.1  haad 	(isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
    110  1.1  haad 
    111  1.1  haad static int
    112  1.1  haad do_mkdirp(const char *path)
    113  1.1  haad {
    114  1.1  haad 	struct lwp *l = curlwp;
    115  1.1  haad 	int mode;
    116  1.1  haad 	int error;
    117  1.1  haad 	register_t ret;
    118  1.1  haad 
    119  1.1  haad 	const char *s, *e;
    120  1.1  haad 	char *here;
    121  1.1  haad 
    122  1.1  haad 	error = 0;
    123  1.1  haad 	mode = 493;
    124  1.1  haad 
    125  1.1  haad 	if (*path != '/')
    126  1.1  haad 		panic("Not an absolute path");
    127  1.1  haad 
    128  1.1  haad 	here = PNBUF_GET();
    129  1.1  haad 	for (s = path;; s = e) {
    130  1.1  haad 		e = strchr(s + 1, '/');
    131  1.1  haad 		if (e == NULL)
    132  1.1  haad 			break;
    133  1.1  haad 
    134  1.1  haad 		strlcpy(here, path, e - path + 1);
    135  1.2  haad 		error = do_sys_mkdir((const char *)here, mode, UIO_SYSSPACE);
    136  1.1  haad 	}
    137  1.1  haad 	PNBUF_PUT(here);
    138  1.1  haad 
    139  1.1  haad 	if (error == EEXIST)
    140  1.1  haad 		error = 0;
    141  1.1  haad 
    142  1.1  haad 	return error;
    143  1.1  haad }
    144  1.1  haad 
    145  1.1  haad int
    146  1.1  haad ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
    147  1.1  haad {
    148  1.1  haad 	unsigned long val;
    149  1.1  haad 	int c;
    150  1.1  haad 	int xx;
    151  1.1  haad 	unsigned long	multmax;
    152  1.1  haad 	int neg = 0;
    153  1.1  haad 	const char **ptr = (const char **)nptr;
    154  1.1  haad 	const unsigned char	*ustr = (const unsigned char *)str;
    155  1.1  haad 
    156  1.1  haad 	if (ptr != (const char **)0)
    157  1.1  haad 		*ptr = (char *)ustr; /* in case no number is formed */
    158  1.1  haad 	if (base < 0 || base > MBASE || base == 1) {
    159  1.1  haad 		/* base is invalid -- should be a fatal error */
    160  1.1  haad 		return (EINVAL);
    161  1.1  haad 	}
    162  1.1  haad 	if (!isalnum(c = *ustr)) {
    163  1.1  haad 		while (isspace(c))
    164  1.1  haad 			c = *++ustr;
    165  1.1  haad 		switch (c) {
    166  1.1  haad 		case '-':
    167  1.1  haad 			neg++;
    168  1.1  haad 			/* FALLTHROUGH */
    169  1.1  haad 		case '+':
    170  1.1  haad 			c = *++ustr;
    171  1.1  haad 		}
    172  1.1  haad 	}
    173  1.1  haad 	if (base == 0)
    174  1.1  haad 		if (c != '0')
    175  1.1  haad 			base = 10;
    176  1.1  haad 		else if (ustr[1] == 'x' || ustr[1] == 'X')
    177  1.1  haad 			base = 16;
    178  1.1  haad 		else
    179  1.1  haad 			base = 8;
    180  1.1  haad 	/*
    181  1.1  haad 	 * for any base > 10, the digits incrementally following
    182  1.1  haad 	 *	9 are assumed to be "abc...z" or "ABC...Z"
    183  1.1  haad 	 */
    184  1.1  haad 	if (!lisalnum(c) || (xx = DIGIT(c)) >= base)
    185  1.1  haad 		return (EINVAL); /* no number formed */
    186  1.1  haad 	if (base == 16 && c == '0' && (ustr[1] == 'x' || ustr[1] == 'X') &&
    187  1.1  haad 	    isxdigit(ustr[2]))
    188  1.1  haad 		c = *(ustr += 2); /* skip over leading "0x" or "0X" */
    189  1.1  haad 
    190  1.1  haad 	multmax = ULONG_MAX / (unsigned long)base;
    191  1.1  haad 	val = DIGIT(c);
    192  1.1  haad 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; ) {
    193  1.1  haad 		if (val > multmax)
    194  1.1  haad 			goto overflow;
    195  1.1  haad 		val *= base;
    196  1.1  haad 		if (ULONG_MAX - val < xx)
    197  1.1  haad 			goto overflow;
    198  1.1  haad 		val += xx;
    199  1.1  haad 		c = *++ustr;
    200  1.1  haad 	}
    201  1.1  haad 	if (ptr != (const char **)0)
    202  1.1  haad 		*ptr = (char *)ustr;
    203  1.1  haad 	*result = neg ? -val : val;
    204  1.1  haad 	return (0);
    205  1.1  haad 
    206  1.1  haad overflow:
    207  1.1  haad 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; (c = *++ustr))
    208  1.1  haad 		;
    209  1.1  haad 	if (ptr != (const char **)0)
    210  1.1  haad 		*ptr = (char *)ustr;
    211  1.1  haad 	return (ERANGE);
    212  1.1  haad }
    213  1.1  haad 
    214  1.6   chs int
    215  1.6   chs ddi_strtoull(const char *str, char **nptr, int base, unsigned long long *result)
    216  1.6   chs {
    217  1.6   chs 
    218  1.6   chs 	*result = (unsigned long long)strtoull(str, nptr, base);
    219  1.6   chs 	if (*result == 0)
    220  1.6   chs 		return (EINVAL);
    221  1.6   chs 	else if (*result == ULLONG_MAX)
    222  1.6   chs 		return (ERANGE);
    223  1.6   chs 	return (0);
    224  1.6   chs }
    225  1.6   chs 
    226  1.1  haad /*
    227  1.1  haad  * Find first bit set in a mask (returned counting from 1 up)
    228  1.1  haad  */
    229  1.1  haad 
    230  1.1  haad int
    231  1.1  haad ddi_ffs(long mask)
    232  1.1  haad {
    233  1.1  haad 	return (ffs(mask));
    234  1.1  haad }
    235  1.1  haad 
    236  1.1  haad /*
    237  1.1  haad  * Find last bit set. Take mask and clear
    238  1.1  haad  * all but the most significant bit, and
    239  1.1  haad  * then let ffs do the rest of the work.
    240  1.1  haad  *
    241  1.1  haad  * Algorithm courtesy of Steve Chessin.
    242  1.1  haad  */
    243  1.1  haad 
    244  1.1  haad int
    245  1.1  haad ddi_fls(long mask)
    246  1.1  haad {
    247  1.1  haad 	while (mask) {
    248  1.1  haad 		long nx;
    249  1.1  haad 
    250  1.1  haad 		if ((nx = (mask & (mask - 1))) == 0)
    251  1.1  haad 			break;
    252  1.1  haad 		mask = nx;
    253  1.1  haad 	}
    254  1.1  haad 	return (ffs(mask));
    255  1.1  haad }
    256  1.1  haad 
    257  1.1  haad /*
    258  1.1  haad  * The next five routines comprise generic storage management utilities
    259  1.1  haad  * for driver soft state structures (in "the old days," this was done
    260  1.1  haad  * with a statically sized array - big systems and dynamic loading
    261  1.1  haad  * and unloading make heap allocation more attractive)
    262  1.1  haad  */
    263  1.1  haad 
    264  1.1  haad /*
    265  1.1  haad  * Allocate a set of pointers to 'n_items' objects of size 'size'
    266  1.1  haad  * bytes.  Each pointer is initialized to nil.
    267  1.1  haad  *
    268  1.1  haad  * The 'size' and 'n_items' values are stashed in the opaque
    269  1.1  haad  * handle returned to the caller.
    270  1.1  haad  *
    271  1.1  haad  * This implementation interprets 'set of pointers' to mean 'array
    272  1.1  haad  * of pointers' but note that nothing in the interface definition
    273  1.1  haad  * precludes an implementation that uses, for example, a linked list.
    274  1.1  haad  * However there should be a small efficiency gain from using an array
    275  1.1  haad  * at lookup time.
    276  1.1  haad  *
    277  1.1  haad  * NOTE	As an optimization, we make our growable array allocations in
    278  1.1  haad  *	powers of two (bytes), since that's how much kmem_alloc (currently)
    279  1.1  haad  *	gives us anyway.  It should save us some free/realloc's ..
    280  1.1  haad  *
    281  1.1  haad  *	As a further optimization, we make the growable array start out
    282  1.1  haad  *	with MIN_N_ITEMS in it.
    283  1.1  haad  */
    284  1.1  haad 
    285  1.1  haad /*
    286  1.1  haad  * This data structure is entirely private to the soft state allocator.
    287  1.1  haad  */
    288  1.1  haad struct i_ddi_soft_state {
    289  1.1  haad 	void		**array;	/* the array of pointers */
    290  1.1  haad 	kmutex_t	lock;	/* serialize access to this struct */
    291  1.1  haad 	size_t		size;	/* how many bytes per state struct */
    292  1.1  haad 	size_t		n_items;	/* how many structs herein */
    293  1.1  haad 	struct i_ddi_soft_state *next;	/* 'dirty' elements */
    294  1.1  haad };
    295  1.1  haad 
    296  1.1  haad #define	MIN_N_ITEMS	8	/* 8 void *'s == 32 bytes */
    297  1.1  haad 
    298  1.1  haad int
    299  1.1  haad ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
    300  1.1  haad {
    301  1.1  haad 	struct i_ddi_soft_state *ss;
    302  1.1  haad 
    303  1.1  haad 	if (state_p == NULL || *state_p != NULL || size == 0)
    304  1.1  haad 		return (EINVAL);
    305  1.1  haad 
    306  1.1  haad 	ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
    307  1.1  haad 	mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
    308  1.1  haad 	ss->size = size;
    309  1.1  haad 
    310  1.1  haad 	if (n_items < MIN_N_ITEMS)
    311  1.1  haad 		ss->n_items = MIN_N_ITEMS;
    312  1.1  haad 	else {
    313  1.1  haad 		int bitlog;
    314  1.1  haad 
    315  1.1  haad 		if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
    316  1.1  haad 			bitlog--;
    317  1.1  haad 		ss->n_items = 1 << bitlog;
    318  1.1  haad 	}
    319  1.1  haad 
    320  1.1  haad 	ASSERT(ss->n_items >= n_items);
    321  1.1  haad 
    322  1.1  haad 	ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
    323  1.1  haad 
    324  1.1  haad 	*state_p = ss;
    325  1.1  haad 
    326  1.1  haad 	return (0);
    327  1.1  haad }
    328  1.1  haad 
    329  1.1  haad 
    330  1.1  haad /*
    331  1.1  haad  * Allocate a state structure of size 'size' to be associated
    332  1.1  haad  * with item 'item'.
    333  1.1  haad  *
    334  1.1  haad  * In this implementation, the array is extended to
    335  1.1  haad  * allow the requested offset, if needed.
    336  1.1  haad  */
    337  1.1  haad int
    338  1.1  haad ddi_soft_state_zalloc(void *state, int item)
    339  1.1  haad {
    340  1.1  haad 	struct i_ddi_soft_state *ss;
    341  1.1  haad 	void **array;
    342  1.1  haad 	void *new_element;
    343  1.1  haad 
    344  1.1  haad 	if ((ss = state) == NULL || item < 0)
    345  1.1  haad 		return (DDI_FAILURE);
    346  1.1  haad 
    347  1.1  haad 	mutex_enter(&ss->lock);
    348  1.1  haad 	if (ss->size == 0) {
    349  1.1  haad 		mutex_exit(&ss->lock);
    350  1.1  haad 		cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle");
    351  1.1  haad 		return (DDI_FAILURE);
    352  1.1  haad 	}
    353  1.1  haad 
    354  1.1  haad 	array = ss->array;	/* NULL if ss->n_items == 0 */
    355  1.1  haad 	ASSERT(ss->n_items != 0 && array != NULL);
    356  1.1  haad 
    357  1.1  haad 	/*
    358  1.1  haad 	 * refuse to tread on an existing element
    359  1.1  haad 	 */
    360  1.1  haad 	if (item < ss->n_items && array[item] != NULL) {
    361  1.1  haad 		mutex_exit(&ss->lock);
    362  1.1  haad 		return (DDI_FAILURE);
    363  1.1  haad 	}
    364  1.1  haad 
    365  1.1  haad 	/*
    366  1.1  haad 	 * Allocate a new element to plug in
    367  1.1  haad 	 */
    368  1.1  haad 	new_element = kmem_zalloc(ss->size, KM_SLEEP);
    369  1.1  haad 
    370  1.1  haad 	/*
    371  1.1  haad 	 * Check if the array is big enough, if not, grow it.
    372  1.1  haad 	 */
    373  1.1  haad 	if (item >= ss->n_items) {
    374  1.1  haad 		void	**new_array;
    375  1.1  haad 		size_t	new_n_items;
    376  1.1  haad 		struct i_ddi_soft_state *dirty;
    377  1.1  haad 
    378  1.1  haad 		/*
    379  1.1  haad 		 * Allocate a new array of the right length, copy
    380  1.1  haad 		 * all the old pointers to the new array, then
    381  1.1  haad 		 * if it exists at all, put the old array on the
    382  1.1  haad 		 * dirty list.
    383  1.1  haad 		 *
    384  1.1  haad 		 * Note that we can't kmem_free() the old array.
    385  1.1  haad 		 *
    386  1.1  haad 		 * Why -- well the 'get' operation is 'mutex-free', so we
    387  1.1  haad 		 * can't easily catch a suspended thread that is just about
    388  1.1  haad 		 * to dereference the array we just grew out of.  So we
    389  1.1  haad 		 * cons up a header and put it on a list of 'dirty'
    390  1.1  haad 		 * pointer arrays.  (Dirty in the sense that there may
    391  1.1  haad 		 * be suspended threads somewhere that are in the middle
    392  1.1  haad 		 * of referencing them).  Fortunately, we -can- garbage
    393  1.1  haad 		 * collect it all at ddi_soft_state_fini time.
    394  1.1  haad 		 */
    395  1.1  haad 		new_n_items = ss->n_items;
    396  1.1  haad 		while (new_n_items < (1 + item))
    397  1.1  haad 			new_n_items <<= 1;	/* double array size .. */
    398  1.1  haad 
    399  1.1  haad 		ASSERT(new_n_items >= (1 + item));	/* sanity check! */
    400  1.1  haad 
    401  1.1  haad 		new_array = kmem_zalloc(new_n_items * sizeof (void *),
    402  1.1  haad 		    KM_SLEEP);
    403  1.1  haad 		/*
    404  1.1  haad 		 * Copy the pointers into the new array
    405  1.1  haad 		 */
    406  1.1  haad 		bcopy(array, new_array, ss->n_items * sizeof (void *));
    407  1.1  haad 
    408  1.1  haad 		/*
    409  1.1  haad 		 * Save the old array on the dirty list
    410  1.1  haad 		 */
    411  1.1  haad 		dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
    412  1.1  haad 		dirty->array = ss->array;
    413  1.1  haad 		dirty->n_items = ss->n_items;
    414  1.1  haad 		dirty->next = ss->next;
    415  1.1  haad 		ss->next = dirty;
    416  1.1  haad 
    417  1.1  haad 		ss->array = (array = new_array);
    418  1.1  haad 		ss->n_items = new_n_items;
    419  1.1  haad 	}
    420  1.1  haad 
    421  1.1  haad 	ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
    422  1.1  haad 
    423  1.1  haad 	array[item] = new_element;
    424  1.1  haad 
    425  1.1  haad 	mutex_exit(&ss->lock);
    426  1.1  haad 	return (DDI_SUCCESS);
    427  1.1  haad }
    428  1.1  haad 
    429  1.1  haad 
    430  1.1  haad /*
    431  1.1  haad  * Fetch a pointer to the allocated soft state structure.
    432  1.1  haad  *
    433  1.1  haad  * This is designed to be cheap.
    434  1.1  haad  *
    435  1.1  haad  * There's an argument that there should be more checking for
    436  1.1  haad  * nil pointers and out of bounds on the array.. but we do a lot
    437  1.1  haad  * of that in the alloc/free routines.
    438  1.1  haad  *
    439  1.1  haad  * An array has the convenience that we don't need to lock read-access
    440  1.1  haad  * to it c.f. a linked list.  However our "expanding array" strategy
    441  1.1  haad  * means that we should hold a readers lock on the i_ddi_soft_state
    442  1.1  haad  * structure.
    443  1.1  haad  *
    444  1.1  haad  * However, from a performance viewpoint, we need to do it without
    445  1.1  haad  * any locks at all -- this also makes it a leaf routine.  The algorithm
    446  1.1  haad  * is 'lock-free' because we only discard the pointer arrays at
    447  1.1  haad  * ddi_soft_state_fini() time.
    448  1.1  haad  */
    449  1.1  haad void *
    450  1.1  haad ddi_get_soft_state(void *state, int item)
    451  1.1  haad {
    452  1.1  haad 	struct i_ddi_soft_state *ss = state;
    453  1.1  haad 
    454  1.1  haad 	ASSERT(ss != NULL && item >= 0);
    455  1.1  haad 
    456  1.1  haad 	if (item < ss->n_items && ss->array != NULL)
    457  1.1  haad 		return (ss->array[item]);
    458  1.1  haad 	return (NULL);
    459  1.1  haad }
    460  1.1  haad 
    461  1.1  haad /*
    462  1.1  haad  * Free the state structure corresponding to 'item.'   Freeing an
    463  1.1  haad  * element that has either gone or was never allocated is not
    464  1.1  haad  * considered an error.  Note that we free the state structure, but
    465  1.1  haad  * we don't shrink our pointer array, or discard 'dirty' arrays,
    466  1.1  haad  * since even a few pointers don't really waste too much memory.
    467  1.1  haad  *
    468  1.1  haad  * Passing an item number that is out of bounds, or a null pointer will
    469  1.1  haad  * provoke an error message.
    470  1.1  haad  */
    471  1.1  haad void
    472  1.1  haad ddi_soft_state_free(void *state, int item)
    473  1.1  haad {
    474  1.1  haad 	struct i_ddi_soft_state *ss;
    475  1.1  haad 	void **array;
    476  1.1  haad 	void *element;
    477  1.1  haad 	static char msg[] = "ddi_soft_state_free:";
    478  1.1  haad 
    479  1.1  haad 	if ((ss = state) == NULL) {
    480  1.1  haad 		cmn_err(CE_WARN, "%s null handle",
    481  1.1  haad 		    msg);
    482  1.1  haad 		return;
    483  1.1  haad 	}
    484  1.1  haad 
    485  1.1  haad 	element = NULL;
    486  1.1  haad 
    487  1.1  haad 	mutex_enter(&ss->lock);
    488  1.1  haad 
    489  1.1  haad 	if ((array = ss->array) == NULL || ss->size == 0) {
    490  1.1  haad 		cmn_err(CE_WARN, "%s bad handle",
    491  1.1  haad 		    msg);
    492  1.1  haad 	} else if (item < 0 || item >= ss->n_items) {
    493  1.1  haad 		cmn_err(CE_WARN, "%s item %d not in range [0..%lu]",
    494  1.1  haad 		    msg, item, ss->n_items - 1);
    495  1.1  haad 	} else if (array[item] != NULL) {
    496  1.1  haad 		element = array[item];
    497  1.1  haad 		array[item] = NULL;
    498  1.1  haad 	}
    499  1.1  haad 
    500  1.1  haad 	mutex_exit(&ss->lock);
    501  1.1  haad 
    502  1.1  haad 	if (element)
    503  1.1  haad 		kmem_free(element, ss->size);
    504  1.1  haad }
    505  1.1  haad 
    506  1.1  haad 
    507  1.1  haad /*
    508  1.1  haad  * Free the entire set of pointers, and any
    509  1.1  haad  * soft state structures contained therein.
    510  1.1  haad  *
    511  1.1  haad  * Note that we don't grab the ss->lock mutex, even though
    512  1.1  haad  * we're inspecting the various fields of the data structure.
    513  1.1  haad  *
    514  1.1  haad  * There is an implicit assumption that this routine will
    515  1.1  haad  * never run concurrently with any of the above on this
    516  1.1  haad  * particular state structure i.e. by the time the driver
    517  1.1  haad  * calls this routine, there should be no other threads
    518  1.1  haad  * running in the driver.
    519  1.1  haad  */
    520  1.1  haad void
    521  1.1  haad ddi_soft_state_fini(void **state_p)
    522  1.1  haad {
    523  1.1  haad 	struct i_ddi_soft_state *ss, *dirty;
    524  1.1  haad 	int item;
    525  1.1  haad 	static char msg[] = "ddi_soft_state_fini:";
    526  1.1  haad 
    527  1.1  haad 	if (state_p == NULL || (ss = *state_p) == NULL) {
    528  1.1  haad 		cmn_err(CE_WARN, "%s null handle",
    529  1.1  haad 		    msg);
    530  1.1  haad 		return;
    531  1.1  haad 	}
    532  1.1  haad 
    533  1.1  haad 	if (ss->size == 0) {
    534  1.1  haad 		cmn_err(CE_WARN, "%s bad handle",
    535  1.1  haad 		    msg);
    536  1.1  haad 		return;
    537  1.1  haad 	}
    538  1.1  haad 
    539  1.1  haad 	if (ss->n_items > 0) {
    540  1.1  haad 		for (item = 0; item < ss->n_items; item++)
    541  1.1  haad 			ddi_soft_state_free(ss, item);
    542  1.1  haad 		kmem_free(ss->array, ss->n_items * sizeof (void *));
    543  1.1  haad 	}
    544  1.1  haad 
    545  1.1  haad 	/*
    546  1.1  haad 	 * Now delete any dirty arrays from previous 'grow' operations
    547  1.1  haad 	 */
    548  1.1  haad 	for (dirty = ss->next; dirty; dirty = ss->next) {
    549  1.1  haad 		ss->next = dirty->next;
    550  1.1  haad 		kmem_free(dirty->array, dirty->n_items * sizeof (void *));
    551  1.1  haad 		kmem_free(dirty, sizeof (*dirty));
    552  1.1  haad 	}
    553  1.1  haad 
    554  1.1  haad 	mutex_destroy(&ss->lock);
    555  1.1  haad 	kmem_free(ss, sizeof (*ss));
    556  1.1  haad 
    557  1.1  haad 	*state_p = NULL;
    558  1.1  haad }
    559  1.1  haad 
    560  1.1  haad int
    561  1.1  haad ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
    562  1.1  haad     minor_t minor_num, char *node_type, int flag)
    563  1.1  haad {
    564  1.1  haad 	struct lwp *l = curlwp;
    565  1.1  haad 	char *pn;
    566  1.1  haad 	dev_t dev;
    567  1.1  haad 	int error;
    568  1.1  haad 	register_t ret;
    569  1.1  haad 
    570  1.1  haad 	printf("ddi_create_minor_node: name %s\n", name);
    571  1.1  haad 
    572  1.1  haad 	dev = makedev(flag, minor_num);
    573  1.1  haad 
    574  1.1  haad 	pn = PNBUF_GET();
    575  1.1  haad 	if (spec_type == S_IFCHR)
    576  1.1  haad 		snprintf(pn, MAXPATHLEN, "/dev/zvol/rdsk/%s", name);
    577  1.1  haad 	else
    578  1.1  haad 		snprintf(pn, MAXPATHLEN, "/dev/zvol/dsk/%s", name);
    579  1.1  haad 
    580  1.1  haad 	if ((error = do_mkdirp(pn)) != 0)
    581  1.1  haad 		goto exit;
    582  1.1  haad 
    583  1.1  haad 	error = do_sys_mknod(l, (const char *)pn, spec_type, dev, &ret, UIO_SYSSPACE);
    584  1.1  haad 
    585  1.1  haad exit:
    586  1.1  haad 	PNBUF_PUT(pn);
    587  1.1  haad 
    588  1.1  haad 	return error;
    589  1.1  haad }
    590  1.1  haad 
    591  1.1  haad void
    592  1.1  haad ddi_remove_minor_node(dev_info_t *dip, char *name)
    593  1.1  haad {
    594  1.1  haad 	char *pn;
    595  1.1  haad 	int error;
    596  1.1  haad 
    597  1.1  haad 	pn = PNBUF_GET();
    598  1.1  haad 	snprintf(pn, MAXPATHLEN, "/dev/zvol/dsk/%s", name);
    599  1.1  haad 	(void)do_sys_unlink(pn, UIO_SYSSPACE);
    600  1.1  haad 	PNBUF_PUT(pn);
    601  1.1  haad 
    602  1.1  haad 	/* We need to remove raw and block device nodes */
    603  1.1  haad 	pn = PNBUF_GET();
    604  1.1  haad 	snprintf(pn, MAXPATHLEN, "/dev/zvol/rdsk/%s", name);
    605  1.1  haad 	(void)do_sys_unlink(pn, UIO_SYSSPACE);
    606  1.1  haad 	PNBUF_PUT(pn);
    607  1.1  haad }
    608  1.3  haad 
    609  1.6   chs #if 0
    610  1.3  haad clock_t
    611  1.3  haad ddi_get_lbolt()
    612  1.3  haad {
    613  1.3  haad 
    614  1.3  haad 	return hardclock_ticks;
    615  1.3  haad }
    616  1.3  haad 
    617  1.3  haad int64_t
    618  1.3  haad ddi_get_lbolt64()
    619  1.3  haad {
    620  1.3  haad 
    621  1.3  haad 	return hardclock_ticks;
    622  1.3  haad }
    623  1.6   chs #endif
    624