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