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