xref: /onnv-gate/usr/src/uts/common/avs/ns/nsctl/nsc_dev.c (revision 9093:cd587b0bd19c)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/debug.h>
287836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
297836SJohn.Forte@Sun.COM #include <sys/kmem.h>
307836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
317836SJohn.Forte@Sun.COM #include <sys/errno.h>
327836SJohn.Forte@Sun.COM #include <sys/ddi.h>
337836SJohn.Forte@Sun.COM 
347836SJohn.Forte@Sun.COM #include <sys/ncall/ncall.h>
357836SJohn.Forte@Sun.COM 
367836SJohn.Forte@Sun.COM #define	__NSC_GEN__
377836SJohn.Forte@Sun.COM #include "nsc_dev.h"
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM #ifdef DS_DDICT
407836SJohn.Forte@Sun.COM #include "../contract.h"
417836SJohn.Forte@Sun.COM #endif
427836SJohn.Forte@Sun.COM 
437836SJohn.Forte@Sun.COM #include "../nsctl.h"
447836SJohn.Forte@Sun.COM 
457836SJohn.Forte@Sun.COM #define	NSC_DEVMIN	"DevMin"
467836SJohn.Forte@Sun.COM #define	NSC_DEVMAJ	"DevMaj"
477836SJohn.Forte@Sun.COM 
487836SJohn.Forte@Sun.COM #define	_I(x)	(((long)(&((nsc_io_t *)0)->x))/sizeof (long))
497836SJohn.Forte@Sun.COM #define	_F(x)	(((long)(&((nsc_fd_t *)0)->x))/sizeof (long))
507836SJohn.Forte@Sun.COM 
517836SJohn.Forte@Sun.COM 
527836SJohn.Forte@Sun.COM nsc_def_t _nsc_io_def[] = {
537836SJohn.Forte@Sun.COM 	"Open",		(uintptr_t)nsc_null,	_I(open),
547836SJohn.Forte@Sun.COM 	"Close",	(uintptr_t)nsc_null,	_I(close),
557836SJohn.Forte@Sun.COM 	"Attach",	(uintptr_t)nsc_null,	_I(attach),
567836SJohn.Forte@Sun.COM 	"Detach",	(uintptr_t)nsc_null,	_I(detach),
577836SJohn.Forte@Sun.COM 	"Flush",	(uintptr_t)nsc_null,	_I(flush),
587836SJohn.Forte@Sun.COM 	"Provide",	0,		_I(provide),
597836SJohn.Forte@Sun.COM 	0,		0,		0
607836SJohn.Forte@Sun.COM };
617836SJohn.Forte@Sun.COM 
627836SJohn.Forte@Sun.COM nsc_def_t _nsc_fd_def[] = {
637836SJohn.Forte@Sun.COM 	"Pinned",	(uintptr_t)nsc_null,	_F(sf_pinned),
647836SJohn.Forte@Sun.COM 	"Unpinned",	(uintptr_t)nsc_null,	_F(sf_unpinned),
657836SJohn.Forte@Sun.COM 	"Attach",	(uintptr_t)nsc_null,	_F(sf_attach),
667836SJohn.Forte@Sun.COM 	"Detach",	(uintptr_t)nsc_null,	_F(sf_detach),
677836SJohn.Forte@Sun.COM 	"Flush",	(uintptr_t)nsc_null,	_F(sf_flush),
687836SJohn.Forte@Sun.COM 	0,		0,		0
697836SJohn.Forte@Sun.COM };
707836SJohn.Forte@Sun.COM 
717836SJohn.Forte@Sun.COM kmutex_t _nsc_io_lock;
727836SJohn.Forte@Sun.COM kmutex_t _nsc_devval_lock;
737836SJohn.Forte@Sun.COM 
747836SJohn.Forte@Sun.COM nsc_io_t *_nsc_io_top = NULL;
757836SJohn.Forte@Sun.COM nsc_io_t *_nsc_null_io = NULL;
767836SJohn.Forte@Sun.COM nsc_dev_t *_nsc_dev_top = NULL;
777836SJohn.Forte@Sun.COM nsc_dev_t *_nsc_dev_pend = NULL;
787836SJohn.Forte@Sun.COM nsc_path_t *_nsc_path_top = NULL;
797836SJohn.Forte@Sun.COM nsc_devval_t *_nsc_devval_top = NULL;
807836SJohn.Forte@Sun.COM 
817836SJohn.Forte@Sun.COM extern nsc_def_t _nsc_disk_def[];
827836SJohn.Forte@Sun.COM extern nsc_def_t _nsc_cache_def[];
837836SJohn.Forte@Sun.COM 
847836SJohn.Forte@Sun.COM extern nsc_mem_t *_nsc_local_mem;
857836SJohn.Forte@Sun.COM extern nsc_rmmap_t *_nsc_global_map;
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM static clock_t _nsc_io_lbolt;
887836SJohn.Forte@Sun.COM 
897836SJohn.Forte@Sun.COM static nsc_io_t *_nsc_find_io(char *, int, int *);
907836SJohn.Forte@Sun.COM nsc_io_t *_nsc_reserve_io(char *, int);
917836SJohn.Forte@Sun.COM static nsc_io_t *_nsc_alloc_io(int, char *, int);
927836SJohn.Forte@Sun.COM 
937836SJohn.Forte@Sun.COM static int _nsc_open_fn(nsc_fd_t *, int);
947836SJohn.Forte@Sun.COM static int _nsc_close_fn(nsc_fd_t *);
957836SJohn.Forte@Sun.COM static int _nsc_alloc_fd(char *, int, int, nsc_fd_t **);
967836SJohn.Forte@Sun.COM static int _nsc_alloc_iodev(nsc_dev_t *, int, nsc_iodev_t **);
977836SJohn.Forte@Sun.COM static int _nsc_alloc_dev(char *, nsc_dev_t **);
987836SJohn.Forte@Sun.COM static int _nsc_reopen_io(char *, int);
997836SJohn.Forte@Sun.COM static int _nsc_reopen_dev(nsc_dev_t *, int);
1007836SJohn.Forte@Sun.COM static int _nsc_relock_dev(nsc_dev_t *, nsc_fd_t *, nsc_iodev_t *);
1017836SJohn.Forte@Sun.COM static int _nsc_reopen_fd(nsc_fd_t *, int);
1027836SJohn.Forte@Sun.COM static int _nsc_decode_io(nsc_def_t *, nsc_io_t *);
1037836SJohn.Forte@Sun.COM 
1047836SJohn.Forte@Sun.COM void _nsc_release_io(nsc_io_t *);
1057836SJohn.Forte@Sun.COM static void _nsc_free_fd(nsc_fd_t *);
1067836SJohn.Forte@Sun.COM static void _nsc_free_iodev(nsc_iodev_t *);
1077836SJohn.Forte@Sun.COM static void _nsc_free_dev(nsc_dev_t *);
1087836SJohn.Forte@Sun.COM static void _nsc_free_io(nsc_io_t *);
1097836SJohn.Forte@Sun.COM static void _nsc_relink_fd(nsc_fd_t *, nsc_fd_t **, nsc_fd_t **, nsc_iodev_t *);
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM static int _nsc_setval(nsc_dev_t *, char *, char *, int, int);
1127836SJohn.Forte@Sun.COM static void r_nsc_setval(ncall_t *, int *);
1137836SJohn.Forte@Sun.COM static void r_nsc_setval_all(ncall_t *, int *);
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM extern void _nsc_add_disk(nsc_io_t *);
1167836SJohn.Forte@Sun.COM extern void _nsc_add_cache(nsc_io_t *);
1177836SJohn.Forte@Sun.COM 
1187836SJohn.Forte@Sun.COM 
1197836SJohn.Forte@Sun.COM /*
1207836SJohn.Forte@Sun.COM  * void
1217836SJohn.Forte@Sun.COM  * _nsc_init_dev (void)
1227836SJohn.Forte@Sun.COM  *	Initialise device subsystem.
1237836SJohn.Forte@Sun.COM  *
1247836SJohn.Forte@Sun.COM  * Calling/Exit State:
1257836SJohn.Forte@Sun.COM  *	Called at driver initialisation time to allocate necessary
1267836SJohn.Forte@Sun.COM  *	data structures.
1277836SJohn.Forte@Sun.COM  */
1287836SJohn.Forte@Sun.COM void
_nsc_init_dev()1297836SJohn.Forte@Sun.COM _nsc_init_dev()
1307836SJohn.Forte@Sun.COM {
1317836SJohn.Forte@Sun.COM 	mutex_init(&_nsc_io_lock, NULL, MUTEX_DRIVER, NULL);
1327836SJohn.Forte@Sun.COM 	mutex_init(&_nsc_devval_lock, NULL, MUTEX_DRIVER, NULL);
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM 	_nsc_null_io = nsc_register_io("null", NSC_NULL, (nsc_def_t *)0);
1357836SJohn.Forte@Sun.COM 
1367836SJohn.Forte@Sun.COM 	if (!_nsc_null_io)
1377836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "nsctl: nsc_init_dev");
1387836SJohn.Forte@Sun.COM 
1397836SJohn.Forte@Sun.COM 	ncall_register_svc(NSC_SETVAL_ALL, r_nsc_setval_all);
1407836SJohn.Forte@Sun.COM 	ncall_register_svc(NSC_SETVAL, r_nsc_setval);
1417836SJohn.Forte@Sun.COM }
1427836SJohn.Forte@Sun.COM 
1437836SJohn.Forte@Sun.COM 
1447836SJohn.Forte@Sun.COM void
_nsc_deinit_dev()1457836SJohn.Forte@Sun.COM _nsc_deinit_dev()
1467836SJohn.Forte@Sun.COM {
1477836SJohn.Forte@Sun.COM 	nsc_devval_t *dv;
1487836SJohn.Forte@Sun.COM 	nsc_val_t *vp;
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_devval_lock);
1517836SJohn.Forte@Sun.COM 
1527836SJohn.Forte@Sun.COM 	while ((dv = _nsc_devval_top) != NULL) {
1537836SJohn.Forte@Sun.COM 		while ((vp = dv->dv_values) != NULL) {
1547836SJohn.Forte@Sun.COM 			dv->dv_values = vp->sv_next;
1557836SJohn.Forte@Sun.COM 			nsc_kmem_free(vp, sizeof (*vp));
1567836SJohn.Forte@Sun.COM 		}
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM 		_nsc_devval_top = dv->dv_next;
1597836SJohn.Forte@Sun.COM 		nsc_kmem_free(dv, sizeof (*dv));
1607836SJohn.Forte@Sun.COM 	}
1617836SJohn.Forte@Sun.COM 
1627836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_devval_lock);
1637836SJohn.Forte@Sun.COM 
1647836SJohn.Forte@Sun.COM 	ncall_unregister_svc(NSC_SETVAL_ALL);
1657836SJohn.Forte@Sun.COM 	ncall_unregister_svc(NSC_SETVAL);
1667836SJohn.Forte@Sun.COM 
1677836SJohn.Forte@Sun.COM 	mutex_destroy(&_nsc_devval_lock);
1687836SJohn.Forte@Sun.COM 	mutex_destroy(&_nsc_io_lock);
1697836SJohn.Forte@Sun.COM }
1707836SJohn.Forte@Sun.COM 
1717836SJohn.Forte@Sun.COM 
1727836SJohn.Forte@Sun.COM /*
1737836SJohn.Forte@Sun.COM  * nsc_io_t *
1747836SJohn.Forte@Sun.COM  * nsc_register_io (char *name, int type, nsc_def_t *def)
1757836SJohn.Forte@Sun.COM  *	Register an I/O module.
1767836SJohn.Forte@Sun.COM  *
1777836SJohn.Forte@Sun.COM  * Calling/Exit State:
1787836SJohn.Forte@Sun.COM  *	Returns a token for use in future calls to nsc_unregister_io.
1797836SJohn.Forte@Sun.COM  *	The ID and flags for the module are specified by 'type' and
1807836SJohn.Forte@Sun.COM  *	the appropriate entry points are defined using 'def'. If
1817836SJohn.Forte@Sun.COM  *	registration fails NULL is returned.
1827836SJohn.Forte@Sun.COM  *
1837836SJohn.Forte@Sun.COM  * Description:
1847836SJohn.Forte@Sun.COM  *	Registers an I/O module for use by subsequent calls to
1857836SJohn.Forte@Sun.COM  *	nsc_open.
1867836SJohn.Forte@Sun.COM  */
1877836SJohn.Forte@Sun.COM nsc_io_t *
nsc_register_io(name,type,def)1887836SJohn.Forte@Sun.COM nsc_register_io(name, type, def)
1897836SJohn.Forte@Sun.COM char *name;
1907836SJohn.Forte@Sun.COM int type;
1917836SJohn.Forte@Sun.COM nsc_def_t *def;
1927836SJohn.Forte@Sun.COM {
1937836SJohn.Forte@Sun.COM 	nsc_io_t *io, *tp;
1947836SJohn.Forte@Sun.COM 	int rc, id, flag;
1957836SJohn.Forte@Sun.COM 	nsc_io_t **iop;
1967836SJohn.Forte@Sun.COM 
1977836SJohn.Forte@Sun.COM 	id = (type & NSC_TYPES);
1987836SJohn.Forte@Sun.COM 	flag = (type & ~NSC_TYPES);
1997836SJohn.Forte@Sun.COM 
2007836SJohn.Forte@Sun.COM 	if ((!(id & NSC_ID) || (id & ~NSC_IDS)) &&
2017836SJohn.Forte@Sun.COM 			(id != NSC_NULL || _nsc_null_io))
2027836SJohn.Forte@Sun.COM 		return (NULL);
2037836SJohn.Forte@Sun.COM 
2047836SJohn.Forte@Sun.COM 	if (!(io = _nsc_alloc_io(id, name, flag)))
2057836SJohn.Forte@Sun.COM 		return (NULL);
2067836SJohn.Forte@Sun.COM 
2077836SJohn.Forte@Sun.COM 	rc = _nsc_decode_io(def, io);
2087836SJohn.Forte@Sun.COM 
2097836SJohn.Forte@Sun.COM 	if (!rc && id != NSC_NULL) {
2107836SJohn.Forte@Sun.COM 		_nsc_free_io(io);
2117836SJohn.Forte@Sun.COM 		return (NULL);
2127836SJohn.Forte@Sun.COM 	}
2137836SJohn.Forte@Sun.COM 
2147836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
2157836SJohn.Forte@Sun.COM 
2167836SJohn.Forte@Sun.COM 	for (tp = _nsc_io_top; tp; tp = tp->next) {
2177836SJohn.Forte@Sun.COM 		if (strcmp(tp->name, name) == 0 || tp->id == id) {
2187836SJohn.Forte@Sun.COM 			mutex_exit(&_nsc_io_lock);
2197836SJohn.Forte@Sun.COM 			_nsc_free_io(io);
2207836SJohn.Forte@Sun.COM 			return (NULL);
2217836SJohn.Forte@Sun.COM 		}
2227836SJohn.Forte@Sun.COM 	}
2237836SJohn.Forte@Sun.COM 
2247836SJohn.Forte@Sun.COM 	for (iop = &_nsc_io_top; *iop; iop = &(*iop)->next)
2257836SJohn.Forte@Sun.COM 		if (id >= (*iop)->id)
2267836SJohn.Forte@Sun.COM 			break;
2277836SJohn.Forte@Sun.COM 
2287836SJohn.Forte@Sun.COM 	io->next = (*iop);
2297836SJohn.Forte@Sun.COM 	(*iop) = io;
2307836SJohn.Forte@Sun.COM 
2317836SJohn.Forte@Sun.COM 	_nsc_io_lbolt = nsc_lbolt();
2327836SJohn.Forte@Sun.COM 
2337836SJohn.Forte@Sun.COM 	while ((rc = _nsc_reopen_io(NULL, 0)) != 0)
2347836SJohn.Forte@Sun.COM 		if (rc != ERESTART)
2357836SJohn.Forte@Sun.COM 			break;
2367836SJohn.Forte@Sun.COM 
2377836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
2387836SJohn.Forte@Sun.COM 	return (io);
2397836SJohn.Forte@Sun.COM }
2407836SJohn.Forte@Sun.COM 
2417836SJohn.Forte@Sun.COM 
2427836SJohn.Forte@Sun.COM /*
2437836SJohn.Forte@Sun.COM  * static int
2447836SJohn.Forte@Sun.COM  * _nsc_decode_io (nsc_def_t *def, nsc_io_t *io)
2457836SJohn.Forte@Sun.COM  *	Decode I/O module definition.
2467836SJohn.Forte@Sun.COM  *
2477836SJohn.Forte@Sun.COM  * Calling/Exit State:
2487836SJohn.Forte@Sun.COM  *	Returns TRUE if the definition contains an adequate
2497836SJohn.Forte@Sun.COM  *	description of an I/O module.
2507836SJohn.Forte@Sun.COM  *
2517836SJohn.Forte@Sun.COM  * Description:
2527836SJohn.Forte@Sun.COM  *	Decode the definition of an I/O module and supply
2537836SJohn.Forte@Sun.COM  *	translation routines where possible for operations
2547836SJohn.Forte@Sun.COM  *	that are not defined.
2557836SJohn.Forte@Sun.COM  */
2567836SJohn.Forte@Sun.COM static int
_nsc_decode_io(def,io)2577836SJohn.Forte@Sun.COM _nsc_decode_io(def, io)
2587836SJohn.Forte@Sun.COM nsc_def_t *def;
2597836SJohn.Forte@Sun.COM nsc_io_t *io;
2607836SJohn.Forte@Sun.COM {
2617836SJohn.Forte@Sun.COM 	nsc_decode_param(def, _nsc_io_def, (long *)io);
2627836SJohn.Forte@Sun.COM 	nsc_decode_param(def, _nsc_disk_def, (long *)io);
2637836SJohn.Forte@Sun.COM 	nsc_decode_param(def, _nsc_cache_def, (long *)io);
2647836SJohn.Forte@Sun.COM 
2657836SJohn.Forte@Sun.COM 	_nsc_add_disk(io);
2667836SJohn.Forte@Sun.COM 	_nsc_add_cache(io);
2677836SJohn.Forte@Sun.COM 
2687836SJohn.Forte@Sun.COM 	return (1);
2697836SJohn.Forte@Sun.COM }
2707836SJohn.Forte@Sun.COM 
2717836SJohn.Forte@Sun.COM 
2727836SJohn.Forte@Sun.COM /*
2737836SJohn.Forte@Sun.COM  * int
2747836SJohn.Forte@Sun.COM  * nsc_unregister_io (nsc_io_t *io, int flag)
2757836SJohn.Forte@Sun.COM  *	Un-register an I/O module.
2767836SJohn.Forte@Sun.COM  *
2777836SJohn.Forte@Sun.COM  * Calling/Exit State:
2787836SJohn.Forte@Sun.COM  *	Returns 0 on success, otherwise returns an error code.
2797836SJohn.Forte@Sun.COM  *
2807836SJohn.Forte@Sun.COM  * Description:
2817836SJohn.Forte@Sun.COM  *	The specified I/O module is un-registered if possible.
2827836SJohn.Forte@Sun.COM  *	All open file descriptors using the module will be closed
2837836SJohn.Forte@Sun.COM  *	in preparation for a subsequent re-open.
2847836SJohn.Forte@Sun.COM  *
2857836SJohn.Forte@Sun.COM  *	If NSC_PCATCH is specified and a signal is received,
2867836SJohn.Forte@Sun.COM  *	the unregister will be terminated and EINTR returned.
2877836SJohn.Forte@Sun.COM  */
2887836SJohn.Forte@Sun.COM int
nsc_unregister_io(nsc_io_t * io,int flag)2897836SJohn.Forte@Sun.COM nsc_unregister_io(nsc_io_t *io, int flag)
2907836SJohn.Forte@Sun.COM {
2917836SJohn.Forte@Sun.COM 	nsc_path_t *sp;
2927836SJohn.Forte@Sun.COM 	nsc_io_t *xio;
2937836SJohn.Forte@Sun.COM 	int rc = 0;
2947836SJohn.Forte@Sun.COM 
2957836SJohn.Forte@Sun.COM 	if (io == _nsc_null_io)
2967836SJohn.Forte@Sun.COM 		return (EINVAL);
2977836SJohn.Forte@Sun.COM 
2987836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
2997836SJohn.Forte@Sun.COM 
3007836SJohn.Forte@Sun.COM 	for (xio = _nsc_io_top; xio; xio = xio->next)
3017836SJohn.Forte@Sun.COM 		if (xio == io)
3027836SJohn.Forte@Sun.COM 			break;
3037836SJohn.Forte@Sun.COM 
3047836SJohn.Forte@Sun.COM 	if (!xio || io->pend) {
3057836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_io_lock);
3067836SJohn.Forte@Sun.COM 		return (xio ? EALREADY : 0);
3077836SJohn.Forte@Sun.COM 	}
3087836SJohn.Forte@Sun.COM 
3097836SJohn.Forte@Sun.COM 	io->pend = 1;
3107836SJohn.Forte@Sun.COM lp:
3117836SJohn.Forte@Sun.COM 	for (sp = _nsc_path_top; sp; sp = sp->sp_next)
3127836SJohn.Forte@Sun.COM 		if (sp->sp_io == io) {
3137836SJohn.Forte@Sun.COM 			mutex_exit(&_nsc_io_lock);
3147836SJohn.Forte@Sun.COM 
3157836SJohn.Forte@Sun.COM 			if ((rc = nsc_unregister_path(sp, flag)) != 0) {
3167836SJohn.Forte@Sun.COM 				io->pend = 0;
3177836SJohn.Forte@Sun.COM 				return (rc);
3187836SJohn.Forte@Sun.COM 			}
3197836SJohn.Forte@Sun.COM 
3207836SJohn.Forte@Sun.COM 			mutex_enter(&_nsc_io_lock);
3217836SJohn.Forte@Sun.COM 			goto lp;
3227836SJohn.Forte@Sun.COM 		}
3237836SJohn.Forte@Sun.COM 
3247836SJohn.Forte@Sun.COM 	_nsc_io_lbolt = nsc_lbolt();
3257836SJohn.Forte@Sun.COM 
3267836SJohn.Forte@Sun.COM 	while (io->refcnt && !rc) {
3277836SJohn.Forte@Sun.COM 		while ((rc = _nsc_reopen_io(NULL, flag)) != 0)
3287836SJohn.Forte@Sun.COM 			if (rc != ERESTART)
3297836SJohn.Forte@Sun.COM 				break;
3307836SJohn.Forte@Sun.COM 
3317836SJohn.Forte@Sun.COM 		if (rc || !io->refcnt)
3327836SJohn.Forte@Sun.COM 			break;
3337836SJohn.Forte@Sun.COM 
3347836SJohn.Forte@Sun.COM 		if (!cv_wait_sig(&io->cv, &_nsc_io_lock))
3357836SJohn.Forte@Sun.COM 			rc = EINTR;
3367836SJohn.Forte@Sun.COM 	}
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM 	/*
3397836SJohn.Forte@Sun.COM 	 * We have tried to get rid of all the IO provider's clients.
3407836SJohn.Forte@Sun.COM 	 * If there are still anonymous buffers outstanding, then fail
3417836SJohn.Forte@Sun.COM 	 * the unregister.
3427836SJohn.Forte@Sun.COM 	 */
3437836SJohn.Forte@Sun.COM 
3447836SJohn.Forte@Sun.COM 	if (!rc && io->abufcnt > 0)
3457836SJohn.Forte@Sun.COM 		rc = EUSERS;
3467836SJohn.Forte@Sun.COM 
3477836SJohn.Forte@Sun.COM 	if (rc)
3487836SJohn.Forte@Sun.COM 		io->pend = 0;
3497836SJohn.Forte@Sun.COM 
3507836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
3517836SJohn.Forte@Sun.COM 
3527836SJohn.Forte@Sun.COM 	if (!rc)
3537836SJohn.Forte@Sun.COM 		_nsc_free_io(io);
3547836SJohn.Forte@Sun.COM 
3557836SJohn.Forte@Sun.COM 	return (rc);
3567836SJohn.Forte@Sun.COM }
3577836SJohn.Forte@Sun.COM 
3587836SJohn.Forte@Sun.COM 
3597836SJohn.Forte@Sun.COM /*
3607836SJohn.Forte@Sun.COM  * nsc_path_t *
3617836SJohn.Forte@Sun.COM  * nsc_register_path (char *path, int type, nsc_io_t *io)
3627836SJohn.Forte@Sun.COM  *	Register interest in pathname.
3637836SJohn.Forte@Sun.COM  *
3647836SJohn.Forte@Sun.COM  * Calling/Exit State:
3657836SJohn.Forte@Sun.COM  *	Returns a token for use in future calls to
3667836SJohn.Forte@Sun.COM  *	nsc_unregister_path. The 'path' argument can contain
3677836SJohn.Forte@Sun.COM  *	wild characters. If registration fails NULL is returned.
3687836SJohn.Forte@Sun.COM  *	May not be called for io providers that support NSC_ANON.
3697836SJohn.Forte@Sun.COM  *
3707836SJohn.Forte@Sun.COM  * Description:
3717836SJohn.Forte@Sun.COM  *	Registers an interest in any pathnames matching 'path'
3727836SJohn.Forte@Sun.COM  *	which are opened with the specified type.
3737836SJohn.Forte@Sun.COM  */
3747836SJohn.Forte@Sun.COM nsc_path_t *
nsc_register_path(char * path,int type,nsc_io_t * io)3757836SJohn.Forte@Sun.COM nsc_register_path(char *path, int type, nsc_io_t *io)
3767836SJohn.Forte@Sun.COM {
3777836SJohn.Forte@Sun.COM 	nsc_path_t *sp, **spp;
3787836SJohn.Forte@Sun.COM 	int rc;
3797836SJohn.Forte@Sun.COM 
3807836SJohn.Forte@Sun.COM 	if ((type & NSC_IDS) || !io || (io->provide & NSC_ANON) ||
3817836SJohn.Forte@Sun.COM 	    !(sp = nsc_kmem_zalloc(sizeof (*sp), KM_SLEEP, _nsc_local_mem)))
3827836SJohn.Forte@Sun.COM 		return (NULL);
3837836SJohn.Forte@Sun.COM 
3847836SJohn.Forte@Sun.COM 	sp->sp_path = nsc_strdup(path);
3857836SJohn.Forte@Sun.COM 	sp->sp_type = type;
3867836SJohn.Forte@Sun.COM 	sp->sp_io = io;
3877836SJohn.Forte@Sun.COM 
3887836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
3897836SJohn.Forte@Sun.COM 
3907836SJohn.Forte@Sun.COM 	for (spp = &_nsc_path_top; *spp; spp = &(*spp)->sp_next)
3917836SJohn.Forte@Sun.COM 		if (io->id >= (*spp)->sp_io->id)
3927836SJohn.Forte@Sun.COM 			break;
3937836SJohn.Forte@Sun.COM 
3947836SJohn.Forte@Sun.COM 	sp->sp_next = (*spp);
3957836SJohn.Forte@Sun.COM 	(*spp) = sp;
3967836SJohn.Forte@Sun.COM 
3977836SJohn.Forte@Sun.COM 	_nsc_io_lbolt = nsc_lbolt();
3987836SJohn.Forte@Sun.COM 
3997836SJohn.Forte@Sun.COM 	while ((rc = _nsc_reopen_io(path, 0)) != 0)
4007836SJohn.Forte@Sun.COM 		if (rc != ERESTART)
4017836SJohn.Forte@Sun.COM 			break;
4027836SJohn.Forte@Sun.COM 
4037836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
4047836SJohn.Forte@Sun.COM 	return (sp);
4057836SJohn.Forte@Sun.COM }
4067836SJohn.Forte@Sun.COM 
4077836SJohn.Forte@Sun.COM 
4087836SJohn.Forte@Sun.COM /*
4097836SJohn.Forte@Sun.COM  * int
4107836SJohn.Forte@Sun.COM  * nsc_unregister_path (nsc_path_t *sp, int flag)
4117836SJohn.Forte@Sun.COM  *	Un-register interest in pathname.
4127836SJohn.Forte@Sun.COM  *
4137836SJohn.Forte@Sun.COM  * Calling/Exit State:
4147836SJohn.Forte@Sun.COM  *	Returns 0 on success, otherwise returns an error code.
4157836SJohn.Forte@Sun.COM  *
4167836SJohn.Forte@Sun.COM  * Description:
4177836SJohn.Forte@Sun.COM  *	Interest in the specified pathname is un-registered
4187836SJohn.Forte@Sun.COM  *	if possible. All appropriate file descriptors will be
4197836SJohn.Forte@Sun.COM  *	closed in preparation for a subsequent re-open.
4207836SJohn.Forte@Sun.COM  *
4217836SJohn.Forte@Sun.COM  *	If NSC_PCATCH is specified and a signal is received,
4227836SJohn.Forte@Sun.COM  *	the unregister will be terminated and EINTR returned.
4237836SJohn.Forte@Sun.COM  */
4247836SJohn.Forte@Sun.COM int
nsc_unregister_path(sp,flag)4257836SJohn.Forte@Sun.COM nsc_unregister_path(sp, flag)
4267836SJohn.Forte@Sun.COM nsc_path_t *sp;
4277836SJohn.Forte@Sun.COM int flag;
4287836SJohn.Forte@Sun.COM {
4297836SJohn.Forte@Sun.COM 	nsc_path_t *xsp, **spp;
4307836SJohn.Forte@Sun.COM 	int rc;
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
4337836SJohn.Forte@Sun.COM 
4347836SJohn.Forte@Sun.COM 	for (xsp = _nsc_path_top; xsp; xsp = xsp->sp_next)
4357836SJohn.Forte@Sun.COM 		if (xsp == sp)
4367836SJohn.Forte@Sun.COM 			break;
4377836SJohn.Forte@Sun.COM 
4387836SJohn.Forte@Sun.COM 	if (!xsp || sp->sp_pend) {
4397836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_io_lock);
4407836SJohn.Forte@Sun.COM 		return (xsp ? EALREADY : 0);
4417836SJohn.Forte@Sun.COM 	}
4427836SJohn.Forte@Sun.COM 
4437836SJohn.Forte@Sun.COM 	sp->sp_pend = 1;
4447836SJohn.Forte@Sun.COM 	_nsc_io_lbolt = nsc_lbolt();
4457836SJohn.Forte@Sun.COM 
4467836SJohn.Forte@Sun.COM 	while ((rc = _nsc_reopen_io(sp->sp_path, flag)) != 0)
4477836SJohn.Forte@Sun.COM 		if (rc != ERESTART) {
4487836SJohn.Forte@Sun.COM 			sp->sp_pend = 0;
4497836SJohn.Forte@Sun.COM 			mutex_exit(&_nsc_io_lock);
4507836SJohn.Forte@Sun.COM 			return (rc);
4517836SJohn.Forte@Sun.COM 		}
4527836SJohn.Forte@Sun.COM 
4537836SJohn.Forte@Sun.COM 	for (spp = &_nsc_path_top; *spp; spp = &(*spp)->sp_next)
4547836SJohn.Forte@Sun.COM 		if (*spp == sp)
4557836SJohn.Forte@Sun.COM 			break;
4567836SJohn.Forte@Sun.COM 
4577836SJohn.Forte@Sun.COM 	if (*spp)
4587836SJohn.Forte@Sun.COM 		(*spp) = sp->sp_next;
4597836SJohn.Forte@Sun.COM 
4607836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
4617836SJohn.Forte@Sun.COM 
4627836SJohn.Forte@Sun.COM 	nsc_strfree(sp->sp_path);
4637836SJohn.Forte@Sun.COM 	nsc_kmem_free(sp, sizeof (*sp));
4647836SJohn.Forte@Sun.COM 	return (0);
4657836SJohn.Forte@Sun.COM }
4667836SJohn.Forte@Sun.COM 
4677836SJohn.Forte@Sun.COM 
4687836SJohn.Forte@Sun.COM /*
4697836SJohn.Forte@Sun.COM  * static int
4707836SJohn.Forte@Sun.COM  * _nsc_reopen_io (char *path, int flag)
4717836SJohn.Forte@Sun.COM  *	Force re-open of all file descriptors.
4727836SJohn.Forte@Sun.COM  *
4737836SJohn.Forte@Sun.COM  * Calling/Exit State:
4747836SJohn.Forte@Sun.COM  *	The _nsc_io_lock must be held across calls to
4757836SJohn.Forte@Sun.COM  *	this function.
4767836SJohn.Forte@Sun.COM  *
4777836SJohn.Forte@Sun.COM  *	Returns 0 if the force succeeds without releasing
4787836SJohn.Forte@Sun.COM  *	_nsc_io_lock, otherwise returns an error code.
4797836SJohn.Forte@Sun.COM  *
4807836SJohn.Forte@Sun.COM  * Description:
4817836SJohn.Forte@Sun.COM  *	A re-open is forced for all file descriptors as
4827836SJohn.Forte@Sun.COM  *	appropriate. For performance reasons available
4837836SJohn.Forte@Sun.COM  *	devices are re-opened before those that would block.
4847836SJohn.Forte@Sun.COM  */
4857836SJohn.Forte@Sun.COM static int
_nsc_reopen_io(path,flag)4867836SJohn.Forte@Sun.COM _nsc_reopen_io(path, flag)
4877836SJohn.Forte@Sun.COM char *path;
4887836SJohn.Forte@Sun.COM int flag;
4897836SJohn.Forte@Sun.COM {
4907836SJohn.Forte@Sun.COM 	nsc_dev_t *dp, *dev;
4917836SJohn.Forte@Sun.COM 	int rc, errno = 0;
4927836SJohn.Forte@Sun.COM 	int try, run;
4937836SJohn.Forte@Sun.COM 
4947836SJohn.Forte@Sun.COM 	for (run = 1, try = (NSC_TRY | NSC_DEFER); run--; try = 0) {
4957836SJohn.Forte@Sun.COM 		for (dev = _nsc_dev_top; dev; dev = dev->nsc_next) {
4967836SJohn.Forte@Sun.COM 			if (path && !nsc_strmatch(dev->nsc_path, path))
4977836SJohn.Forte@Sun.COM 				continue;
4987836SJohn.Forte@Sun.COM 
4997836SJohn.Forte@Sun.COM 			if (!(rc = _nsc_reopen_dev(dev, flag | try)))
5007836SJohn.Forte@Sun.COM 				continue;
5017836SJohn.Forte@Sun.COM 
5027836SJohn.Forte@Sun.COM 			for (dp = _nsc_dev_top; dp; dp = dp->nsc_next)
5037836SJohn.Forte@Sun.COM 				if (dp == dev)
5047836SJohn.Forte@Sun.COM 					break;
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 			if (!dp)
5077836SJohn.Forte@Sun.COM 				return (ERESTART);
5087836SJohn.Forte@Sun.COM 
5097836SJohn.Forte@Sun.COM 			if (try && !(flag & NSC_TRY))
5107836SJohn.Forte@Sun.COM 				run = 1;
5117836SJohn.Forte@Sun.COM 			if (!run && errno != ERESTART)
5127836SJohn.Forte@Sun.COM 				errno = rc;
5137836SJohn.Forte@Sun.COM 		}
5147836SJohn.Forte@Sun.COM 	}
5157836SJohn.Forte@Sun.COM 
5167836SJohn.Forte@Sun.COM 	return (errno);
5177836SJohn.Forte@Sun.COM }
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM 
5207836SJohn.Forte@Sun.COM /*
5217836SJohn.Forte@Sun.COM  * static int
5227836SJohn.Forte@Sun.COM  * _nsc_reopen_dev (nsc_dev_t *dev, int flag)
5237836SJohn.Forte@Sun.COM  *	Force re-open of entire device.
5247836SJohn.Forte@Sun.COM  *
5257836SJohn.Forte@Sun.COM  * Calling/Exit State:
5267836SJohn.Forte@Sun.COM  *	The _nsc_io_lock must be held across calls to
5277836SJohn.Forte@Sun.COM  *	this function.
5287836SJohn.Forte@Sun.COM  *
5297836SJohn.Forte@Sun.COM  *	Returns 0 if the force succeeds without releasing
5307836SJohn.Forte@Sun.COM  *	_nsc_io_lock, otherwise returns an error code.
5317836SJohn.Forte@Sun.COM  *
5327836SJohn.Forte@Sun.COM  * Description:
5337836SJohn.Forte@Sun.COM  *	A re-open is forced for all file descriptors for the
5347836SJohn.Forte@Sun.COM  *	device as appropriate.
5357836SJohn.Forte@Sun.COM  */
5367836SJohn.Forte@Sun.COM static int
_nsc_reopen_dev(dev,flag)5377836SJohn.Forte@Sun.COM _nsc_reopen_dev(dev, flag)
5387836SJohn.Forte@Sun.COM nsc_dev_t *dev;
5397836SJohn.Forte@Sun.COM int flag;
5407836SJohn.Forte@Sun.COM {
5417836SJohn.Forte@Sun.COM 	int rc, errno = 0;
5427836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev;
5437836SJohn.Forte@Sun.COM 	int try, run;
5447836SJohn.Forte@Sun.COM 	nsc_fd_t *fd;
5457836SJohn.Forte@Sun.COM 
5467836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
5477836SJohn.Forte@Sun.COM 
5487836SJohn.Forte@Sun.COM 	for (run = 1, try = (NSC_TRY | NSC_DEFER); run--; try = 0)
5497836SJohn.Forte@Sun.COM 		for (iodev = dev->nsc_list; iodev; iodev = iodev->si_next) {
5507836SJohn.Forte@Sun.COM 			for (fd = iodev->si_open; fd; fd = fd->sf_next) {
5517836SJohn.Forte@Sun.COM 				if (!(rc = _nsc_reopen_fd(fd, flag | try)))
5527836SJohn.Forte@Sun.COM 					continue;
5537836SJohn.Forte@Sun.COM 
5547836SJohn.Forte@Sun.COM 				if (rc == -ERESTART)
5557836SJohn.Forte@Sun.COM 					return (ERESTART);
5567836SJohn.Forte@Sun.COM 
5577836SJohn.Forte@Sun.COM 				if (!_nsc_relock_dev(dev, fd, iodev))
5587836SJohn.Forte@Sun.COM 					return (ERESTART);
5597836SJohn.Forte@Sun.COM 
5607836SJohn.Forte@Sun.COM 				if (try && !(flag & NSC_TRY))
5617836SJohn.Forte@Sun.COM 					run = 1;
5627836SJohn.Forte@Sun.COM 				if (!run && errno != ERESTART)
5637836SJohn.Forte@Sun.COM 					errno = rc;
5647836SJohn.Forte@Sun.COM 			}
5657836SJohn.Forte@Sun.COM 		}
5667836SJohn.Forte@Sun.COM 
5677836SJohn.Forte@Sun.COM 	for (run = 1, try = (NSC_TRY | NSC_DEFER); run--; try = 0)
5687836SJohn.Forte@Sun.COM 		for (fd = dev->nsc_close; fd; fd = fd->sf_next) {
5697836SJohn.Forte@Sun.COM 			if (!(rc = _nsc_reopen_fd(fd, flag | try)))
5707836SJohn.Forte@Sun.COM 				continue;
5717836SJohn.Forte@Sun.COM 
5727836SJohn.Forte@Sun.COM 			if (rc == -ERESTART)
5737836SJohn.Forte@Sun.COM 				return (ERESTART);
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM 			if (!_nsc_relock_dev(dev, fd, NULL))
5767836SJohn.Forte@Sun.COM 				return (ERESTART);
5777836SJohn.Forte@Sun.COM 
5787836SJohn.Forte@Sun.COM 			if (try && !(flag & NSC_TRY))
5797836SJohn.Forte@Sun.COM 				run = 1;
5807836SJohn.Forte@Sun.COM 			if (!run && errno != ERESTART)
5817836SJohn.Forte@Sun.COM 				errno = rc;
5827836SJohn.Forte@Sun.COM 		}
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
5857836SJohn.Forte@Sun.COM 	return (errno);
5867836SJohn.Forte@Sun.COM }
5877836SJohn.Forte@Sun.COM 
5887836SJohn.Forte@Sun.COM 
5897836SJohn.Forte@Sun.COM /*
5907836SJohn.Forte@Sun.COM  * static int
5917836SJohn.Forte@Sun.COM  * _nsc_relock_dev (nsc_dev_t *dev, nsc_fd_t *fd, nsc_iodev_t *iodev)
5927836SJohn.Forte@Sun.COM  *	Relock device structure if possible.
5937836SJohn.Forte@Sun.COM  *
5947836SJohn.Forte@Sun.COM  * Calling/Exit State:
5957836SJohn.Forte@Sun.COM  *	The _nsc_io_lock must be held across calls to
5967836SJohn.Forte@Sun.COM  *	this function.
5977836SJohn.Forte@Sun.COM  *
5987836SJohn.Forte@Sun.COM  *	Checks whether the file descriptor is still part
5997836SJohn.Forte@Sun.COM  *	of the specified device and I/O device. If so the
6007836SJohn.Forte@Sun.COM  *	device lock is taken. Otherwise FALSE is returned.
6017836SJohn.Forte@Sun.COM  */
6027836SJohn.Forte@Sun.COM static int
_nsc_relock_dev(nsc_dev_t * dev,nsc_fd_t * fd,nsc_iodev_t * iodev)6037836SJohn.Forte@Sun.COM _nsc_relock_dev(nsc_dev_t *dev, nsc_fd_t *fd, nsc_iodev_t *iodev)
6047836SJohn.Forte@Sun.COM {
6057836SJohn.Forte@Sun.COM 	nsc_fd_t *fp = NULL;
6067836SJohn.Forte@Sun.COM 	nsc_iodev_t *iop;
6077836SJohn.Forte@Sun.COM 	nsc_dev_t *dp;
6087836SJohn.Forte@Sun.COM 
6097836SJohn.Forte@Sun.COM 	for (dp = _nsc_dev_top; dp; dp = dp->nsc_next)
6107836SJohn.Forte@Sun.COM 		if (dp == dev)
6117836SJohn.Forte@Sun.COM 			break;
6127836SJohn.Forte@Sun.COM 
6137836SJohn.Forte@Sun.COM 	if (!dp)
6147836SJohn.Forte@Sun.COM 		return (0);
6157836SJohn.Forte@Sun.COM 
6167836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM 	if (iodev)
6197836SJohn.Forte@Sun.COM 		for (iop = dev->nsc_list; iop; iop = iop->si_next)
6207836SJohn.Forte@Sun.COM 			if (iop == iodev)
6217836SJohn.Forte@Sun.COM 				break;
6227836SJohn.Forte@Sun.COM 
6237836SJohn.Forte@Sun.COM 	if (!iodev || iop) {
6247836SJohn.Forte@Sun.COM 		fp = (iodev) ? iodev->si_open : dev->nsc_close;
6257836SJohn.Forte@Sun.COM 
6267836SJohn.Forte@Sun.COM 		for (; fp; fp = fp->sf_next)
6277836SJohn.Forte@Sun.COM 			if (fp == fd)
6287836SJohn.Forte@Sun.COM 				break;
6297836SJohn.Forte@Sun.COM 	}
6307836SJohn.Forte@Sun.COM 
6317836SJohn.Forte@Sun.COM 	if (!fp) {
6327836SJohn.Forte@Sun.COM 		mutex_exit(&dev->nsc_lock);
6337836SJohn.Forte@Sun.COM 		return (0);
6347836SJohn.Forte@Sun.COM 	}
6357836SJohn.Forte@Sun.COM 
6367836SJohn.Forte@Sun.COM 	return (1);
6377836SJohn.Forte@Sun.COM }
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 
6407836SJohn.Forte@Sun.COM /*
6417836SJohn.Forte@Sun.COM  * static int
6427836SJohn.Forte@Sun.COM  * _nsc_reopen_fd (nsc_fd_t *dev, int flag)
6437836SJohn.Forte@Sun.COM  *	Force re-open of file descriptor.
6447836SJohn.Forte@Sun.COM  *
6457836SJohn.Forte@Sun.COM  * Calling/Exit State:
6467836SJohn.Forte@Sun.COM  *	Both _nsc_io_lock and the device lock must be held
6477836SJohn.Forte@Sun.COM  *	across calls to this function.
6487836SJohn.Forte@Sun.COM  *
6497836SJohn.Forte@Sun.COM  *	Returns 0 if the force succeeds without releasing
6507836SJohn.Forte@Sun.COM  *	any locks, otherwise returns an error code. If an
6517836SJohn.Forte@Sun.COM  *	error code is returned the device lock is released.
6527836SJohn.Forte@Sun.COM  *
6537836SJohn.Forte@Sun.COM  * Description:
6547836SJohn.Forte@Sun.COM  *	If appropriate the file descriptor is closed in order
6557836SJohn.Forte@Sun.COM  *	to force a subsequent open using the currently available
6567836SJohn.Forte@Sun.COM  *	resources.
6577836SJohn.Forte@Sun.COM  */
6587836SJohn.Forte@Sun.COM static int
_nsc_reopen_fd(fd,flag)6597836SJohn.Forte@Sun.COM _nsc_reopen_fd(fd, flag)
6607836SJohn.Forte@Sun.COM nsc_fd_t *fd;
6617836SJohn.Forte@Sun.COM int flag;
6627836SJohn.Forte@Sun.COM {
6637836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
6647836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev = fd->sf_iodev;
6657836SJohn.Forte@Sun.COM 	int changed = 0;
6667836SJohn.Forte@Sun.COM 	int rc;
6677836SJohn.Forte@Sun.COM 
6687836SJohn.Forte@Sun.COM 	if (!fd->sf_pend && !iodev)
6697836SJohn.Forte@Sun.COM 		return (0);
6707836SJohn.Forte@Sun.COM 
6717836SJohn.Forte@Sun.COM 	if (fd->sf_pend == _NSC_OPEN)
6727836SJohn.Forte@Sun.COM 		if (fd->sf_lbolt - _nsc_io_lbolt > 0)
6737836SJohn.Forte@Sun.COM 			return (0);
6747836SJohn.Forte@Sun.COM 
6757836SJohn.Forte@Sun.COM 	if (iodev &&
6767836SJohn.Forte@Sun.COM 	    (iodev->si_io ==
6777836SJohn.Forte@Sun.COM 		_nsc_find_io(dev->nsc_path, fd->sf_type, &changed)) &&
6787836SJohn.Forte@Sun.COM 	    !changed)
6797836SJohn.Forte@Sun.COM 		return (0);
6807836SJohn.Forte@Sun.COM 
6817836SJohn.Forte@Sun.COM 	if (iodev)
6827836SJohn.Forte@Sun.COM 		fd->sf_reopen = 1;
6837836SJohn.Forte@Sun.COM 
6847836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
6857836SJohn.Forte@Sun.COM 
6867836SJohn.Forte@Sun.COM 	dev->nsc_reopen = 1;
6877836SJohn.Forte@Sun.COM 
6887836SJohn.Forte@Sun.COM 	rc = _nsc_close_fd(fd, flag);
6897836SJohn.Forte@Sun.COM 
6907836SJohn.Forte@Sun.COM 	dev->nsc_reopen = 0;
6917836SJohn.Forte@Sun.COM 
6927836SJohn.Forte@Sun.COM 	if (rc == EAGAIN && (flag & NSC_DEFER) && fd->sf_reopen)
6937836SJohn.Forte@Sun.COM 		dev->nsc_drop = 1;
6947836SJohn.Forte@Sun.COM 
6957836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
6967836SJohn.Forte@Sun.COM 
6977836SJohn.Forte@Sun.COM 	if (rc == -ERESTART)
6987836SJohn.Forte@Sun.COM 		delay(2);	/* allow other threads cpu time */
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
7017836SJohn.Forte@Sun.COM 	return (rc ? rc : ERESTART);
7027836SJohn.Forte@Sun.COM }
7037836SJohn.Forte@Sun.COM 
7047836SJohn.Forte@Sun.COM 
7057836SJohn.Forte@Sun.COM /*
7067836SJohn.Forte@Sun.COM  * nsc_fd_t *
7077836SJohn.Forte@Sun.COM  * nsc_open (char *path, int type, nsc_def_t *def, blind_t arg, int *sts)
7087836SJohn.Forte@Sun.COM  *	Open file descriptor for pathname.
7097836SJohn.Forte@Sun.COM  *
7107836SJohn.Forte@Sun.COM  * Calling/Exit State:
7117836SJohn.Forte@Sun.COM  *	Returns file descriptor if open succeeds, otherwise
7127836SJohn.Forte@Sun.COM  *	returns 0 and puts error code in the location pointed
7137836SJohn.Forte@Sun.COM  *	to by sts.
7147836SJohn.Forte@Sun.COM  *
7157836SJohn.Forte@Sun.COM  * Description:
7167836SJohn.Forte@Sun.COM  *	Open the specified pathname using an appropriate access
7177836SJohn.Forte@Sun.COM  *	method.
7187836SJohn.Forte@Sun.COM  */
7197836SJohn.Forte@Sun.COM nsc_fd_t *
nsc_open(path,type,def,arg,sts)7207836SJohn.Forte@Sun.COM nsc_open(path, type, def, arg, sts)
7217836SJohn.Forte@Sun.COM char *path;
7227836SJohn.Forte@Sun.COM int type;
7237836SJohn.Forte@Sun.COM nsc_def_t *def;
7247836SJohn.Forte@Sun.COM blind_t arg;
7257836SJohn.Forte@Sun.COM int *sts;
7267836SJohn.Forte@Sun.COM {
7277836SJohn.Forte@Sun.COM 	int flag, rc;
7287836SJohn.Forte@Sun.COM 	nsc_fd_t *fd;
7297836SJohn.Forte@Sun.COM 
7307836SJohn.Forte@Sun.COM 	flag = (type & ~NSC_TYPES);
7317836SJohn.Forte@Sun.COM 	type &= NSC_TYPES;
7327836SJohn.Forte@Sun.COM 
7337836SJohn.Forte@Sun.COM 	if ((flag & NSC_READ) == 0)
7347836SJohn.Forte@Sun.COM 		flag |= NSC_RDWR;
7357836SJohn.Forte@Sun.COM 
7367836SJohn.Forte@Sun.COM 	if ((rc = _nsc_alloc_fd(path, type, flag, &fd)) != 0) {
7377836SJohn.Forte@Sun.COM 		if (sts)
7387836SJohn.Forte@Sun.COM 			*sts = rc;
7397836SJohn.Forte@Sun.COM 		return (NULL);
7407836SJohn.Forte@Sun.COM 	}
7417836SJohn.Forte@Sun.COM 
7427836SJohn.Forte@Sun.COM 	fd->sf_arg = arg;
7437836SJohn.Forte@Sun.COM 	fd->sf_aio = _nsc_null_io;
7447836SJohn.Forte@Sun.COM 
7457836SJohn.Forte@Sun.COM 	nsc_decode_param(def, _nsc_fd_def, (long *)fd);
7467836SJohn.Forte@Sun.COM 
7477836SJohn.Forte@Sun.COM 	mutex_enter(&fd->sf_dev->nsc_lock);
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 	while ((rc = _nsc_open_fd(fd, flag)) != 0)
7507836SJohn.Forte@Sun.COM 		if (rc != ERESTART)
7517836SJohn.Forte@Sun.COM 			break;
7527836SJohn.Forte@Sun.COM 
7537836SJohn.Forte@Sun.COM 	mutex_exit(&fd->sf_dev->nsc_lock);
7547836SJohn.Forte@Sun.COM 
7557836SJohn.Forte@Sun.COM 	if (rc) {
7567836SJohn.Forte@Sun.COM 		_nsc_free_fd(fd);
7577836SJohn.Forte@Sun.COM 		if (sts)
7587836SJohn.Forte@Sun.COM 			*sts = rc;
7597836SJohn.Forte@Sun.COM 		return (NULL);
7607836SJohn.Forte@Sun.COM 	}
7617836SJohn.Forte@Sun.COM 
7627836SJohn.Forte@Sun.COM 	return (fd);
7637836SJohn.Forte@Sun.COM }
7647836SJohn.Forte@Sun.COM 
7657836SJohn.Forte@Sun.COM 
7667836SJohn.Forte@Sun.COM /*
7677836SJohn.Forte@Sun.COM  * int
7687836SJohn.Forte@Sun.COM  * _nsc_open_fd (nsc_fd_t *fd, int flag)
7697836SJohn.Forte@Sun.COM  *	Open file descriptor.
7707836SJohn.Forte@Sun.COM  *
7717836SJohn.Forte@Sun.COM  * Calling/Exit State:
7727836SJohn.Forte@Sun.COM  *	The device lock must be held across calls to
7737836SJohn.Forte@Sun.COM  *	this function.
7747836SJohn.Forte@Sun.COM  *
7757836SJohn.Forte@Sun.COM  *	Returns 0 if the open succeeds, otherwise
7767836SJohn.Forte@Sun.COM  *	returns an error code.
7777836SJohn.Forte@Sun.COM  *
7787836SJohn.Forte@Sun.COM  * Description:
7797836SJohn.Forte@Sun.COM  *	Open the specified file descriptor.
7807836SJohn.Forte@Sun.COM  */
7817836SJohn.Forte@Sun.COM int
_nsc_open_fd(fd,flag)7827836SJohn.Forte@Sun.COM _nsc_open_fd(fd, flag)
7837836SJohn.Forte@Sun.COM nsc_fd_t *fd;
7847836SJohn.Forte@Sun.COM int flag;
7857836SJohn.Forte@Sun.COM {
7867836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
7877836SJohn.Forte@Sun.COM 	int rc;
7887836SJohn.Forte@Sun.COM 
7897836SJohn.Forte@Sun.COM 	if (fd->sf_pend)
7907836SJohn.Forte@Sun.COM 		return (_nsc_wait_dev(dev, flag));
7917836SJohn.Forte@Sun.COM 
7927836SJohn.Forte@Sun.COM 	if (fd->sf_iodev)
7937836SJohn.Forte@Sun.COM 		return (0);
7947836SJohn.Forte@Sun.COM 	if (flag & NSC_NOBLOCK)
7957836SJohn.Forte@Sun.COM 		return (EAGAIN);
7967836SJohn.Forte@Sun.COM 
7977836SJohn.Forte@Sun.COM 	fd->sf_pend = _NSC_OPEN;
7987836SJohn.Forte@Sun.COM 	fd->sf_lbolt = nsc_lbolt();
7997836SJohn.Forte@Sun.COM 
8007836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	rc = _nsc_open_fn(fd, flag);
8037836SJohn.Forte@Sun.COM 
8047836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
8057836SJohn.Forte@Sun.COM 	fd->sf_pend = 0;
8067836SJohn.Forte@Sun.COM 
8077836SJohn.Forte@Sun.COM 	if (!rc)
8087836SJohn.Forte@Sun.COM 		fd->sf_iodev->si_pend = 0;
8097836SJohn.Forte@Sun.COM 
8107836SJohn.Forte@Sun.COM 	if (dev->nsc_wait || dev->nsc_refcnt <= 0)
8117836SJohn.Forte@Sun.COM 		cv_broadcast(&dev->nsc_cv);
8127836SJohn.Forte@Sun.COM 
8137836SJohn.Forte@Sun.COM 	return (rc ? rc : ERESTART);
8147836SJohn.Forte@Sun.COM }
8157836SJohn.Forte@Sun.COM 
8167836SJohn.Forte@Sun.COM 
8177836SJohn.Forte@Sun.COM /*
8187836SJohn.Forte@Sun.COM  * static int
8197836SJohn.Forte@Sun.COM  * _nsc_open_fn (nsc_fd_t *fd, int flag)
8207836SJohn.Forte@Sun.COM  *	Allocate I/O device and open file descriptor.
8217836SJohn.Forte@Sun.COM  *
8227836SJohn.Forte@Sun.COM  * Calling/Exit State:
8237836SJohn.Forte@Sun.COM  *	No locks may be held across this function.
8247836SJohn.Forte@Sun.COM  *
8257836SJohn.Forte@Sun.COM  *	If the open succeeds an I/O device will be
8267836SJohn.Forte@Sun.COM  *	attached to the file descriptor, marked as
8277836SJohn.Forte@Sun.COM  *	pending and 0 returned. Otherwise, returns
8287836SJohn.Forte@Sun.COM  *	an error code.
8297836SJohn.Forte@Sun.COM  *
8307836SJohn.Forte@Sun.COM  * Description:
8317836SJohn.Forte@Sun.COM  *	Allocate an I/O device and open the specified
8327836SJohn.Forte@Sun.COM  *	file descriptor.
8337836SJohn.Forte@Sun.COM  */
8347836SJohn.Forte@Sun.COM static int
_nsc_open_fn(fd,flag)8357836SJohn.Forte@Sun.COM _nsc_open_fn(fd, flag)
8367836SJohn.Forte@Sun.COM nsc_fd_t *fd;
8377836SJohn.Forte@Sun.COM int flag;
8387836SJohn.Forte@Sun.COM {
8397836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
8407836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev;
8417836SJohn.Forte@Sun.COM 	int rc;
8427836SJohn.Forte@Sun.COM 
8437836SJohn.Forte@Sun.COM 	if ((rc = _nsc_alloc_iodev(dev, fd->sf_type, &iodev)) != 0)
8447836SJohn.Forte@Sun.COM 		return (rc);
8457836SJohn.Forte@Sun.COM 
8467836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
8477836SJohn.Forte@Sun.COM 
8487836SJohn.Forte@Sun.COM 	if (iodev->si_pend) {
8497836SJohn.Forte@Sun.COM 		rc = _nsc_wait_dev(dev, flag);
8507836SJohn.Forte@Sun.COM 		mutex_exit(&dev->nsc_lock);
8517836SJohn.Forte@Sun.COM 		_nsc_free_iodev(iodev);
8527836SJohn.Forte@Sun.COM 		return (rc);
8537836SJohn.Forte@Sun.COM 	}
8547836SJohn.Forte@Sun.COM 
8557836SJohn.Forte@Sun.COM 	iodev->si_pend = _NSC_OPEN;
8567836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
8577836SJohn.Forte@Sun.COM 
8587836SJohn.Forte@Sun.COM 	rc = (*iodev->si_io->open)(dev->nsc_path,
8597836SJohn.Forte@Sun.COM 			(fd->sf_flag & ~NSC_RDWR), &fd->sf_cd, iodev);
8607836SJohn.Forte@Sun.COM 
8617836SJohn.Forte@Sun.COM 	if (rc) {
8627836SJohn.Forte@Sun.COM 		iodev->si_pend = 0;
8637836SJohn.Forte@Sun.COM 		_nsc_free_iodev(iodev);
8647836SJohn.Forte@Sun.COM 		return (rc);
8657836SJohn.Forte@Sun.COM 	}
8667836SJohn.Forte@Sun.COM 
8677836SJohn.Forte@Sun.COM 	/* save away the DevMaj and DevMin values */
8687836SJohn.Forte@Sun.COM 	if (iodev->si_io->id == NSC_RAW_ID) {
8697836SJohn.Forte@Sun.COM 		rc = _nsc_setval(dev, NULL, NSC_DEVMAJ,
8707836SJohn.Forte@Sun.COM 		    (int)getmajor((dev_t)fd->sf_cd), FALSE);
8717836SJohn.Forte@Sun.COM #ifdef DEBUG
8727836SJohn.Forte@Sun.COM 		if (rc != 1) {
873*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_NOTE, "!nsctl: could not set DevMaj (%s:%x)",
8747836SJohn.Forte@Sun.COM 			    dev->nsc_path, (int)getmajor((dev_t)fd->sf_cd));
8757836SJohn.Forte@Sun.COM 		}
8767836SJohn.Forte@Sun.COM #endif
8777836SJohn.Forte@Sun.COM 
8787836SJohn.Forte@Sun.COM 		rc = _nsc_setval(dev, NULL, NSC_DEVMIN,
8797836SJohn.Forte@Sun.COM 		    (int)getminor((dev_t)fd->sf_cd), FALSE);
8807836SJohn.Forte@Sun.COM #ifdef DEBUG
8817836SJohn.Forte@Sun.COM 		if (rc != 1) {
882*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_NOTE, "!nsctl: could not set DevMin (%s:%x)",
8837836SJohn.Forte@Sun.COM 			    dev->nsc_path, (int)getminor((dev_t)fd->sf_cd));
8847836SJohn.Forte@Sun.COM 		}
8857836SJohn.Forte@Sun.COM #endif
8867836SJohn.Forte@Sun.COM 	}
8877836SJohn.Forte@Sun.COM 
8887836SJohn.Forte@Sun.COM 	fd->sf_iodev = iodev;
8897836SJohn.Forte@Sun.COM 	_nsc_relink_fd(fd, &dev->nsc_close, &iodev->si_open, iodev);
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM 	return (0);
8927836SJohn.Forte@Sun.COM }
8937836SJohn.Forte@Sun.COM 
8947836SJohn.Forte@Sun.COM 
8957836SJohn.Forte@Sun.COM /*
8967836SJohn.Forte@Sun.COM  * int
8977836SJohn.Forte@Sun.COM  * nsc_close (nsc_fd_t *fd)
8987836SJohn.Forte@Sun.COM  *	Close file descriptor for pathname.
8997836SJohn.Forte@Sun.COM  *
9007836SJohn.Forte@Sun.COM  * Calling/Exit State:
9017836SJohn.Forte@Sun.COM  *	Returns 0 if close succeeds, otherwise returns error
9027836SJohn.Forte@Sun.COM  *	code.
9037836SJohn.Forte@Sun.COM  *
9047836SJohn.Forte@Sun.COM  * Description:
9057836SJohn.Forte@Sun.COM  *	Close the specified file descriptor. It is assumed
9067836SJohn.Forte@Sun.COM  *	that all other users of this file descriptor have
9077836SJohn.Forte@Sun.COM  *	finished. Any reserve will be discarded before the
9087836SJohn.Forte@Sun.COM  *	close is performed.
9097836SJohn.Forte@Sun.COM  */
9107836SJohn.Forte@Sun.COM int
nsc_close(fd)9117836SJohn.Forte@Sun.COM nsc_close(fd)
9127836SJohn.Forte@Sun.COM nsc_fd_t *fd;
9137836SJohn.Forte@Sun.COM {
9147836SJohn.Forte@Sun.COM 	int rc;
9157836SJohn.Forte@Sun.COM 
9167836SJohn.Forte@Sun.COM 	if (!fd)
9177836SJohn.Forte@Sun.COM 		return (0);
9187836SJohn.Forte@Sun.COM 
9197836SJohn.Forte@Sun.COM 	while (fd->sf_reserve)
9207836SJohn.Forte@Sun.COM 		nsc_release(fd);
9217836SJohn.Forte@Sun.COM 
9227836SJohn.Forte@Sun.COM 	mutex_enter(&fd->sf_dev->nsc_lock);
9237836SJohn.Forte@Sun.COM 
9247836SJohn.Forte@Sun.COM 	fd->sf_owner = NULL;
9257836SJohn.Forte@Sun.COM 
9267836SJohn.Forte@Sun.COM 	while ((rc = _nsc_close_fd(fd, 0)) != 0)
9277836SJohn.Forte@Sun.COM 		if (rc != ERESTART)
9287836SJohn.Forte@Sun.COM 			break;
9297836SJohn.Forte@Sun.COM 
9307836SJohn.Forte@Sun.COM 	nsc_decode_param(_nsc_fd_def, _nsc_fd_def, (long *)fd);
9317836SJohn.Forte@Sun.COM 
9327836SJohn.Forte@Sun.COM 	mutex_exit(&fd->sf_dev->nsc_lock);
9337836SJohn.Forte@Sun.COM 
9347836SJohn.Forte@Sun.COM 	if (!rc)
9357836SJohn.Forte@Sun.COM 		_nsc_free_fd(fd);
9367836SJohn.Forte@Sun.COM 	return (rc);
9377836SJohn.Forte@Sun.COM }
9387836SJohn.Forte@Sun.COM 
9397836SJohn.Forte@Sun.COM 
9407836SJohn.Forte@Sun.COM /*
9417836SJohn.Forte@Sun.COM  * int
9427836SJohn.Forte@Sun.COM  * _nsc_close_fd (nsc_fd_t *fd, int flag)
9437836SJohn.Forte@Sun.COM  *	Close file descriptor.
9447836SJohn.Forte@Sun.COM  *
9457836SJohn.Forte@Sun.COM  * Calling/Exit State:
9467836SJohn.Forte@Sun.COM  *	The device lock must be held across calls to
9477836SJohn.Forte@Sun.COM  *	this function.
9487836SJohn.Forte@Sun.COM  *
9497836SJohn.Forte@Sun.COM  *	Returns 0 if the close succeeds, otherwise
9507836SJohn.Forte@Sun.COM  *	returns an error code.
9517836SJohn.Forte@Sun.COM  *
9527836SJohn.Forte@Sun.COM  * Description:
9537836SJohn.Forte@Sun.COM  *	Close the specified file descriptor.
9547836SJohn.Forte@Sun.COM  */
9557836SJohn.Forte@Sun.COM int
_nsc_close_fd(fd,flag)9567836SJohn.Forte@Sun.COM _nsc_close_fd(fd, flag)
9577836SJohn.Forte@Sun.COM nsc_fd_t *fd;
9587836SJohn.Forte@Sun.COM int flag;
9597836SJohn.Forte@Sun.COM {
9607836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
9617836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev;
9627836SJohn.Forte@Sun.COM 	int rc;
9637836SJohn.Forte@Sun.COM 
9647836SJohn.Forte@Sun.COM 	if (fd->sf_pend) {
9657836SJohn.Forte@Sun.COM 		if (fd->sf_pend == _NSC_CLOSE && dev->nsc_reopen != 0)
9667836SJohn.Forte@Sun.COM 			return (-ERESTART);
9677836SJohn.Forte@Sun.COM 
9687836SJohn.Forte@Sun.COM 		return (_nsc_wait_dev(dev, flag));
9697836SJohn.Forte@Sun.COM 	}
9707836SJohn.Forte@Sun.COM 
9717836SJohn.Forte@Sun.COM 	flag |= NSC_RDWR;
9727836SJohn.Forte@Sun.COM 	iodev = fd->sf_iodev;
9737836SJohn.Forte@Sun.COM 
9747836SJohn.Forte@Sun.COM 	if (!iodev)
9757836SJohn.Forte@Sun.COM 		return (0);
9767836SJohn.Forte@Sun.COM 
9777836SJohn.Forte@Sun.COM 	if ((rc = _nsc_detach_fd(fd, flag)) != 0)
9787836SJohn.Forte@Sun.COM 		return (rc);
9797836SJohn.Forte@Sun.COM 
9807836SJohn.Forte@Sun.COM 	if (iodev->si_pend)
9817836SJohn.Forte@Sun.COM 		return (_nsc_wait_dev(dev, flag));
9827836SJohn.Forte@Sun.COM 
9837836SJohn.Forte@Sun.COM 	if (iodev->si_open == fd && !fd->sf_next) {
9847836SJohn.Forte@Sun.COM 		if ((rc = _nsc_detach_iodev(iodev, NULL, flag)) != 0)
9857836SJohn.Forte@Sun.COM 			return (rc);
9867836SJohn.Forte@Sun.COM 
9877836SJohn.Forte@Sun.COM 		if (dev->nsc_list == iodev && !iodev->si_next)
9887836SJohn.Forte@Sun.COM 			if ((rc = _nsc_detach_dev(dev, NULL, flag)) != 0)
9897836SJohn.Forte@Sun.COM 				return (rc);
9907836SJohn.Forte@Sun.COM 	}
9917836SJohn.Forte@Sun.COM 
9927836SJohn.Forte@Sun.COM 	if (flag & NSC_NOBLOCK)
9937836SJohn.Forte@Sun.COM 		return (EAGAIN);
9947836SJohn.Forte@Sun.COM 
9957836SJohn.Forte@Sun.COM 	fd->sf_pend = _NSC_CLOSE;
9967836SJohn.Forte@Sun.COM 	iodev->si_pend = _NSC_CLOSE;
9977836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
9987836SJohn.Forte@Sun.COM 
9997836SJohn.Forte@Sun.COM 	rc = _nsc_close_fn(fd);
10007836SJohn.Forte@Sun.COM 
10017836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
10027836SJohn.Forte@Sun.COM 	fd->sf_pend = 0;
10037836SJohn.Forte@Sun.COM 
10047836SJohn.Forte@Sun.COM 	fd->sf_reopen = 0;
10057836SJohn.Forte@Sun.COM 	if (rc)
10067836SJohn.Forte@Sun.COM 		iodev->si_pend = 0;
10077836SJohn.Forte@Sun.COM 
10087836SJohn.Forte@Sun.COM 	if (dev->nsc_wait || dev->nsc_refcnt <= 0)
10097836SJohn.Forte@Sun.COM 		cv_broadcast(&dev->nsc_cv);
10107836SJohn.Forte@Sun.COM 
10117836SJohn.Forte@Sun.COM 	return (rc ? rc : ERESTART);
10127836SJohn.Forte@Sun.COM }
10137836SJohn.Forte@Sun.COM 
10147836SJohn.Forte@Sun.COM 
10157836SJohn.Forte@Sun.COM /*
10167836SJohn.Forte@Sun.COM  * static int
10177836SJohn.Forte@Sun.COM  * _nsc_close_fn (nsc_fd_t *fd)
10187836SJohn.Forte@Sun.COM  *	Close file descriptor and free I/O device.
10197836SJohn.Forte@Sun.COM  *
10207836SJohn.Forte@Sun.COM  * Calling/Exit State:
10217836SJohn.Forte@Sun.COM  *	No locks may be held across this function.
10227836SJohn.Forte@Sun.COM  *
10237836SJohn.Forte@Sun.COM  *	Returns 0 if the close succeeds, otherwise
10247836SJohn.Forte@Sun.COM  *	returns an error code.
10257836SJohn.Forte@Sun.COM  *
10267836SJohn.Forte@Sun.COM  *	If the close succeeds the I/O device will be
10277836SJohn.Forte@Sun.COM  *	detached from the file descriptor, released
10287836SJohn.Forte@Sun.COM  *	and 0 returned. Otherwise, returns an error
10297836SJohn.Forte@Sun.COM  *	code.
10307836SJohn.Forte@Sun.COM  *
10317836SJohn.Forte@Sun.COM  * Description:
10327836SJohn.Forte@Sun.COM  *	Close the specified file descriptor and free
10337836SJohn.Forte@Sun.COM  *	the I/O device.
10347836SJohn.Forte@Sun.COM  */
10357836SJohn.Forte@Sun.COM static int
_nsc_close_fn(fd)10367836SJohn.Forte@Sun.COM _nsc_close_fn(fd)
10377836SJohn.Forte@Sun.COM nsc_fd_t *fd;
10387836SJohn.Forte@Sun.COM {
10397836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev = fd->sf_iodev;
10407836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
10417836SJohn.Forte@Sun.COM 	int last, rc;
10427836SJohn.Forte@Sun.COM 
10437836SJohn.Forte@Sun.COM 	last = (iodev->si_open == fd && !fd->sf_next);
10447836SJohn.Forte@Sun.COM 
10457836SJohn.Forte@Sun.COM 	if (last || (iodev->si_io->flag & NSC_REFCNT))
10467836SJohn.Forte@Sun.COM 		if ((rc = (*iodev->si_io->close)(fd->sf_cd)) != 0)
10477836SJohn.Forte@Sun.COM 			return (rc);
10487836SJohn.Forte@Sun.COM 
10497836SJohn.Forte@Sun.COM 	fd->sf_iodev = NULL;
10507836SJohn.Forte@Sun.COM 	_nsc_relink_fd(fd, &iodev->si_open, &dev->nsc_close, iodev);
10517836SJohn.Forte@Sun.COM 
10527836SJohn.Forte@Sun.COM 	iodev->si_pend = 0;
10537836SJohn.Forte@Sun.COM 	_nsc_free_iodev(iodev);
10547836SJohn.Forte@Sun.COM 
10557836SJohn.Forte@Sun.COM 	return (0);
10567836SJohn.Forte@Sun.COM }
10577836SJohn.Forte@Sun.COM 
10587836SJohn.Forte@Sun.COM 
10597836SJohn.Forte@Sun.COM /*
10607836SJohn.Forte@Sun.COM  * void
10617836SJohn.Forte@Sun.COM  * nsc_set_owner (nsc_fd_t *fd, nsc_iodev_t *iodev)
10627836SJohn.Forte@Sun.COM  *	Set owner associated with file descriptor.
10637836SJohn.Forte@Sun.COM  *
10647836SJohn.Forte@Sun.COM  * Calling/Exit State:
10657836SJohn.Forte@Sun.COM  *	Sets the owner field in the file descriptor.
10667836SJohn.Forte@Sun.COM  */
10677836SJohn.Forte@Sun.COM void
nsc_set_owner(nsc_fd_t * fd,nsc_iodev_t * iodev)10687836SJohn.Forte@Sun.COM nsc_set_owner(nsc_fd_t *fd, nsc_iodev_t *iodev)
10697836SJohn.Forte@Sun.COM {
10707836SJohn.Forte@Sun.COM 	if (fd) {
10717836SJohn.Forte@Sun.COM 		mutex_enter(&fd->sf_dev->nsc_lock);
10727836SJohn.Forte@Sun.COM 		fd->sf_owner = iodev;
10737836SJohn.Forte@Sun.COM 		mutex_exit(&fd->sf_dev->nsc_lock);
10747836SJohn.Forte@Sun.COM 	}
10757836SJohn.Forte@Sun.COM }
10767836SJohn.Forte@Sun.COM 
10777836SJohn.Forte@Sun.COM 
10787836SJohn.Forte@Sun.COM /*
10797836SJohn.Forte@Sun.COM  * char *
10807836SJohn.Forte@Sun.COM  * nsc_pathname (nsc_fd_t *fd)
10817836SJohn.Forte@Sun.COM  *	Pathname associated with file descriptor.
10827836SJohn.Forte@Sun.COM  *
10837836SJohn.Forte@Sun.COM  * Calling/Exit State:
10847836SJohn.Forte@Sun.COM  *	Returns a pointer to the pathname associated
10857836SJohn.Forte@Sun.COM  *	with the given file descriptor.
10867836SJohn.Forte@Sun.COM  */
10877836SJohn.Forte@Sun.COM char *
nsc_pathname(fd)10887836SJohn.Forte@Sun.COM nsc_pathname(fd)
10897836SJohn.Forte@Sun.COM nsc_fd_t *fd;
10907836SJohn.Forte@Sun.COM {
10917836SJohn.Forte@Sun.COM 	return ((fd) ? (fd->sf_dev->nsc_path) : 0);
10927836SJohn.Forte@Sun.COM }
10937836SJohn.Forte@Sun.COM 
10947836SJohn.Forte@Sun.COM 
10957836SJohn.Forte@Sun.COM /*
10967836SJohn.Forte@Sun.COM  * int
10977836SJohn.Forte@Sun.COM  * nsc_fdpathcmp(nsc_fd_t *fd, uint64_t phash, char *path)
10987836SJohn.Forte@Sun.COM  *	Compare fd to pathname and hash
10997836SJohn.Forte@Sun.COM  *
11007836SJohn.Forte@Sun.COM  * Calling/Exit State:
11017836SJohn.Forte@Sun.COM  *	Returns comparison value like strcmp(3C).
11027836SJohn.Forte@Sun.COM  *
11037836SJohn.Forte@Sun.COM  * Description:
11047836SJohn.Forte@Sun.COM  *	Does an optimised comparison of the pathname and associated hash
11057836SJohn.Forte@Sun.COM  *	value (as returned from nsc_strhash()) against the pathname of
11067836SJohn.Forte@Sun.COM  *	the filedescriptor, fd.
11077836SJohn.Forte@Sun.COM  */
11087836SJohn.Forte@Sun.COM int
nsc_fdpathcmp(nsc_fd_t * fd,uint64_t phash,char * path)11097836SJohn.Forte@Sun.COM nsc_fdpathcmp(nsc_fd_t *fd, uint64_t phash, char *path)
11107836SJohn.Forte@Sun.COM {
11117836SJohn.Forte@Sun.COM 	int rc = -1;
11127836SJohn.Forte@Sun.COM 
11137836SJohn.Forte@Sun.COM 	if (fd != NULL && fd->sf_dev->nsc_phash == phash)
11147836SJohn.Forte@Sun.COM 		rc = strcmp(fd->sf_dev->nsc_path, path);
11157836SJohn.Forte@Sun.COM 
11167836SJohn.Forte@Sun.COM 	return (rc);
11177836SJohn.Forte@Sun.COM }
11187836SJohn.Forte@Sun.COM 
11197836SJohn.Forte@Sun.COM 
11207836SJohn.Forte@Sun.COM static int
_nsc_setval(nsc_dev_t * dev,char * path,char * name,int val,int do_ncall)11217836SJohn.Forte@Sun.COM _nsc_setval(nsc_dev_t *dev, char *path, char *name, int val, int do_ncall)
11227836SJohn.Forte@Sun.COM {
11237836SJohn.Forte@Sun.COM 	nsc_devval_t *dv;
11247836SJohn.Forte@Sun.COM 	nsc_rval_t *rval;
11257836SJohn.Forte@Sun.COM 	ncall_t *ncall;
11267836SJohn.Forte@Sun.COM 	nsc_val_t *vp;
11277836SJohn.Forte@Sun.COM 	uint64_t phash;
11287836SJohn.Forte@Sun.COM 	char *pp;
11297836SJohn.Forte@Sun.COM 	int rc;
11307836SJohn.Forte@Sun.COM 
11317836SJohn.Forte@Sun.COM 	ASSERT(dev != NULL || path != NULL);
11327836SJohn.Forte@Sun.COM #ifdef DEBUG
11337836SJohn.Forte@Sun.COM 	if (dev != NULL && path != NULL) {
11347836SJohn.Forte@Sun.COM 		ASSERT(strcmp(dev->nsc_path, path) == 0);
11357836SJohn.Forte@Sun.COM 	}
11367836SJohn.Forte@Sun.COM #endif
11377836SJohn.Forte@Sun.COM 
11387836SJohn.Forte@Sun.COM 	pp = (dev != NULL) ? dev->nsc_path : path;
11397836SJohn.Forte@Sun.COM 
11407836SJohn.Forte@Sun.COM 	if (strlen(name) >= NSC_SETVAL_MAX) {
11417836SJohn.Forte@Sun.COM #ifdef DEBUG
1142*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nsc_setval: max name size(%d) exceeded(%d)",
11437836SJohn.Forte@Sun.COM 		    NSC_SETVAL_MAX-1, (int)strlen(name));
11447836SJohn.Forte@Sun.COM #endif
11457836SJohn.Forte@Sun.COM 		return (0);
11467836SJohn.Forte@Sun.COM 	}
11477836SJohn.Forte@Sun.COM 
11487836SJohn.Forte@Sun.COM 	phash = nsc_strhash(pp);
11497836SJohn.Forte@Sun.COM 
11507836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_devval_lock);
11517836SJohn.Forte@Sun.COM 
11527836SJohn.Forte@Sun.COM 	if (dev != NULL)
11537836SJohn.Forte@Sun.COM 		dv = dev->nsc_values;
11547836SJohn.Forte@Sun.COM 	else {
11557836SJohn.Forte@Sun.COM 		for (dv = _nsc_devval_top; dv != NULL; dv = dv->dv_next) {
11567836SJohn.Forte@Sun.COM 			if (phash == dv->dv_phash &&
11577836SJohn.Forte@Sun.COM 			    strcmp(pp, dv->dv_path) == 0)
11587836SJohn.Forte@Sun.COM 				/* found dv for device */
11597836SJohn.Forte@Sun.COM 				break;
11607836SJohn.Forte@Sun.COM 		}
11617836SJohn.Forte@Sun.COM 	}
11627836SJohn.Forte@Sun.COM 
11637836SJohn.Forte@Sun.COM 	if (dv == NULL) {
11647836SJohn.Forte@Sun.COM 		dv = nsc_kmem_zalloc(sizeof (*dv), KM_SLEEP, _nsc_local_mem);
11657836SJohn.Forte@Sun.COM 		if (dv == NULL) {
11667836SJohn.Forte@Sun.COM 			mutex_exit(&_nsc_devval_lock);
11677836SJohn.Forte@Sun.COM 			return (0);
11687836SJohn.Forte@Sun.COM 		}
11697836SJohn.Forte@Sun.COM 
11707836SJohn.Forte@Sun.COM 		(void) strncpy(dv->dv_path, pp, sizeof (dv->dv_path));
11717836SJohn.Forte@Sun.COM 		dv->dv_phash = phash;
11727836SJohn.Forte@Sun.COM 
11737836SJohn.Forte@Sun.COM 		dv->dv_next = _nsc_devval_top;
11747836SJohn.Forte@Sun.COM 		_nsc_devval_top = dv;
11757836SJohn.Forte@Sun.COM 		if (dev != NULL)
11767836SJohn.Forte@Sun.COM 			dev->nsc_values = dv;
11777836SJohn.Forte@Sun.COM 	}
11787836SJohn.Forte@Sun.COM 
11797836SJohn.Forte@Sun.COM 	for (vp = dv->dv_values; vp; vp = vp->sv_next) {
11807836SJohn.Forte@Sun.COM 		if (strcmp(vp->sv_name, name) == 0) {
11817836SJohn.Forte@Sun.COM 			vp->sv_value = val;
11827836SJohn.Forte@Sun.COM 			break;
11837836SJohn.Forte@Sun.COM 		}
11847836SJohn.Forte@Sun.COM 	}
11857836SJohn.Forte@Sun.COM 
11867836SJohn.Forte@Sun.COM 	if (vp == NULL) {
11877836SJohn.Forte@Sun.COM 		vp = nsc_kmem_zalloc(sizeof (*vp), KM_SLEEP, _nsc_local_mem);
11887836SJohn.Forte@Sun.COM 		if (vp != NULL) {
11897836SJohn.Forte@Sun.COM 			(void) strncpy(vp->sv_name, name, sizeof (vp->sv_name));
11907836SJohn.Forte@Sun.COM 			vp->sv_value = val;
11917836SJohn.Forte@Sun.COM 			vp->sv_next = dv->dv_values;
11927836SJohn.Forte@Sun.COM 			dv->dv_values = vp;
11937836SJohn.Forte@Sun.COM 		}
11947836SJohn.Forte@Sun.COM 	}
11957836SJohn.Forte@Sun.COM 
11967836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_devval_lock);
11977836SJohn.Forte@Sun.COM 
11987836SJohn.Forte@Sun.COM 	/*
11997836SJohn.Forte@Sun.COM 	 * phoenix: ncall the new value to the other node now.
12007836SJohn.Forte@Sun.COM 	 */
12017836SJohn.Forte@Sun.COM 
12027836SJohn.Forte@Sun.COM 	if (vp && do_ncall) {
12037836SJohn.Forte@Sun.COM 		/* CONSTCOND */
12047836SJohn.Forte@Sun.COM 		ASSERT(sizeof (nsc_rval_t) <= NCALL_DATA_SZ);
12057836SJohn.Forte@Sun.COM 
12067836SJohn.Forte@Sun.COM 		rval = nsc_kmem_zalloc(sizeof (*rval), KM_SLEEP,
12077836SJohn.Forte@Sun.COM 		    _nsc_local_mem);
12087836SJohn.Forte@Sun.COM 		if (rval == NULL) {
12097836SJohn.Forte@Sun.COM 			goto out;
12107836SJohn.Forte@Sun.COM 		}
12117836SJohn.Forte@Sun.COM 
12127836SJohn.Forte@Sun.COM 		rc = ncall_alloc(ncall_mirror(ncall_self()), 0, 0, &ncall);
12137836SJohn.Forte@Sun.COM 		if (rc == 0) {
12147836SJohn.Forte@Sun.COM 			(void) strncpy(rval->path, pp, sizeof (rval->path));
12157836SJohn.Forte@Sun.COM 			(void) strncpy(rval->name, name, sizeof (rval->name));
12167836SJohn.Forte@Sun.COM 			rval->value = val;
12177836SJohn.Forte@Sun.COM 
12187836SJohn.Forte@Sun.COM 			rc = ncall_put_data(ncall, rval, sizeof (*rval));
12197836SJohn.Forte@Sun.COM 			if (rc == 0) {
12207836SJohn.Forte@Sun.COM 				/*
12217836SJohn.Forte@Sun.COM 				 * Send synchronously and read a reply
12227836SJohn.Forte@Sun.COM 				 * so that we know that the remote
12237836SJohn.Forte@Sun.COM 				 * setval has completed before this
12247836SJohn.Forte@Sun.COM 				 * function returns and hence whilst
12257836SJohn.Forte@Sun.COM 				 * the device is still reserved on this
12267836SJohn.Forte@Sun.COM 				 * node.
12277836SJohn.Forte@Sun.COM 				 */
12287836SJohn.Forte@Sun.COM 				if (ncall_send(ncall, 0, NSC_SETVAL) == 0)
12297836SJohn.Forte@Sun.COM 					(void) ncall_read_reply(ncall, 1, &rc);
12307836SJohn.Forte@Sun.COM 			}
12317836SJohn.Forte@Sun.COM 
12327836SJohn.Forte@Sun.COM 			ncall_free(ncall);
12337836SJohn.Forte@Sun.COM 		}
12347836SJohn.Forte@Sun.COM 
12357836SJohn.Forte@Sun.COM 		nsc_kmem_free(rval, sizeof (*rval));
12367836SJohn.Forte@Sun.COM 	}
12377836SJohn.Forte@Sun.COM 
12387836SJohn.Forte@Sun.COM out:
12397836SJohn.Forte@Sun.COM 	return (vp ? 1 : 0);
12407836SJohn.Forte@Sun.COM }
12417836SJohn.Forte@Sun.COM 
12427836SJohn.Forte@Sun.COM 
12437836SJohn.Forte@Sun.COM /* ARGSUSED */
12447836SJohn.Forte@Sun.COM 
12457836SJohn.Forte@Sun.COM static void
r_nsc_setval(ncall_t * ncall,int * ap)12467836SJohn.Forte@Sun.COM r_nsc_setval(ncall_t *ncall, int *ap)
12477836SJohn.Forte@Sun.COM {
12487836SJohn.Forte@Sun.COM 	nsc_rval_t *rval;
12497836SJohn.Forte@Sun.COM 	int rc;
12507836SJohn.Forte@Sun.COM 
12517836SJohn.Forte@Sun.COM 	rval = nsc_kmem_zalloc(sizeof (*rval), KM_SLEEP, _nsc_local_mem);
12527836SJohn.Forte@Sun.COM 	if (rval == NULL) {
12537836SJohn.Forte@Sun.COM 		ncall_reply(ncall, ENOMEM);
12547836SJohn.Forte@Sun.COM 		return;
12557836SJohn.Forte@Sun.COM 	}
12567836SJohn.Forte@Sun.COM 
12577836SJohn.Forte@Sun.COM 	rc = ncall_get_data(ncall, rval, sizeof (*rval));
12587836SJohn.Forte@Sun.COM 	if (rc != 0) {
12597836SJohn.Forte@Sun.COM 		ncall_reply(ncall, EFAULT);
12607836SJohn.Forte@Sun.COM 		return;
12617836SJohn.Forte@Sun.COM 	}
12627836SJohn.Forte@Sun.COM 
12637836SJohn.Forte@Sun.COM 	if (_nsc_setval(NULL, rval->path, rval->name, rval->value, FALSE))
12647836SJohn.Forte@Sun.COM 		rc = 0;
12657836SJohn.Forte@Sun.COM 	else
12667836SJohn.Forte@Sun.COM 		rc = ENOMEM;
12677836SJohn.Forte@Sun.COM 
12687836SJohn.Forte@Sun.COM 	ncall_reply(ncall, rc);
12697836SJohn.Forte@Sun.COM 	nsc_kmem_free(rval, sizeof (*rval));
12707836SJohn.Forte@Sun.COM }
12717836SJohn.Forte@Sun.COM 
12727836SJohn.Forte@Sun.COM 
12737836SJohn.Forte@Sun.COM /* ARGSUSED */
12747836SJohn.Forte@Sun.COM 
12757836SJohn.Forte@Sun.COM static void
r_nsc_setval_all(ncall_t * ncall,int * ap)12767836SJohn.Forte@Sun.COM r_nsc_setval_all(ncall_t *ncall, int *ap)
12777836SJohn.Forte@Sun.COM {
12787836SJohn.Forte@Sun.COM 	nsc_rval_t *in = NULL, *out = NULL;
12797836SJohn.Forte@Sun.COM 	nsc_devval_t *dv;
12807836SJohn.Forte@Sun.COM 	nsc_val_t *vp;
12817836SJohn.Forte@Sun.COM 	ncall_t *np;
12827836SJohn.Forte@Sun.COM 	uint64_t phash;
12837836SJohn.Forte@Sun.COM 	int rc;
12847836SJohn.Forte@Sun.COM 
12857836SJohn.Forte@Sun.COM 	/* CONSTCOND */
12867836SJohn.Forte@Sun.COM 	ASSERT(sizeof (nsc_rval_t) <= NCALL_DATA_SZ);
12877836SJohn.Forte@Sun.COM 
12887836SJohn.Forte@Sun.COM 	in = nsc_kmem_zalloc(sizeof (*in), KM_SLEEP, _nsc_local_mem);
12897836SJohn.Forte@Sun.COM 	out = nsc_kmem_zalloc(sizeof (*out), KM_SLEEP, _nsc_local_mem);
12907836SJohn.Forte@Sun.COM 	if (in == NULL || out == NULL) {
12917836SJohn.Forte@Sun.COM 		if (in != NULL) {
12927836SJohn.Forte@Sun.COM 			nsc_kmem_free(in, sizeof (*in));
12937836SJohn.Forte@Sun.COM 			in = NULL;
12947836SJohn.Forte@Sun.COM 		}
12957836SJohn.Forte@Sun.COM 		if (out != NULL) {
12967836SJohn.Forte@Sun.COM 			nsc_kmem_free(out, sizeof (*out));
12977836SJohn.Forte@Sun.COM 			out = NULL;
12987836SJohn.Forte@Sun.COM 		}
12997836SJohn.Forte@Sun.COM 		ncall_reply(ncall, ENOMEM);
13007836SJohn.Forte@Sun.COM 	}
13017836SJohn.Forte@Sun.COM 
13027836SJohn.Forte@Sun.COM 	rc = ncall_get_data(ncall, in, sizeof (*in));
13037836SJohn.Forte@Sun.COM 	if (rc != 0) {
13047836SJohn.Forte@Sun.COM 		ncall_reply(ncall, EFAULT);
13057836SJohn.Forte@Sun.COM 		return;
13067836SJohn.Forte@Sun.COM 	}
13077836SJohn.Forte@Sun.COM 
13087836SJohn.Forte@Sun.COM 	phash = nsc_strhash(in->path);
13097836SJohn.Forte@Sun.COM 
13107836SJohn.Forte@Sun.COM 	(void) strncpy(out->path, in->path, sizeof (out->path));
13117836SJohn.Forte@Sun.COM 
13127836SJohn.Forte@Sun.COM 	rc = ncall_alloc(ncall_mirror(ncall_self()), 0, 0, &np);
13137836SJohn.Forte@Sun.COM 	if (rc != 0) {
13147836SJohn.Forte@Sun.COM 		ncall_reply(ncall, ENOMEM);
13157836SJohn.Forte@Sun.COM 		return;
13167836SJohn.Forte@Sun.COM 	}
13177836SJohn.Forte@Sun.COM 
13187836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_devval_lock);
13197836SJohn.Forte@Sun.COM 
13207836SJohn.Forte@Sun.COM 	for (dv = _nsc_devval_top; dv; dv = dv->dv_next) {
13217836SJohn.Forte@Sun.COM 		if (dv->dv_phash == phash &&
13227836SJohn.Forte@Sun.COM 		    strcmp(dv->dv_path, in->path) == 0)
13237836SJohn.Forte@Sun.COM 			break;
13247836SJohn.Forte@Sun.COM 	}
13257836SJohn.Forte@Sun.COM 
13267836SJohn.Forte@Sun.COM 	if (dv) {
13277836SJohn.Forte@Sun.COM 		for (vp = dv->dv_values; vp; vp = vp->sv_next) {
13287836SJohn.Forte@Sun.COM 			if (strcmp(vp->sv_name, NSC_DEVMIN) == 0 ||
13297836SJohn.Forte@Sun.COM 			    strcmp(vp->sv_name, NSC_DEVMAJ) == 0) {
13307836SJohn.Forte@Sun.COM 				/* ignore the implicit DevMin/DevMaj values */
13317836SJohn.Forte@Sun.COM 				continue;
13327836SJohn.Forte@Sun.COM 			}
13337836SJohn.Forte@Sun.COM 
13347836SJohn.Forte@Sun.COM 			(void) strncpy(out->name, vp->sv_name,
13357836SJohn.Forte@Sun.COM 			    sizeof (out->name));
13367836SJohn.Forte@Sun.COM 			out->value = vp->sv_value;
13377836SJohn.Forte@Sun.COM 
13387836SJohn.Forte@Sun.COM 			rc = ncall_put_data(np, out, sizeof (*out));
13397836SJohn.Forte@Sun.COM 			if (rc == 0) {
13407836SJohn.Forte@Sun.COM 				/*
13417836SJohn.Forte@Sun.COM 				 * Send synchronously and read a reply
13427836SJohn.Forte@Sun.COM 				 * so that we know that the remote
13437836SJohn.Forte@Sun.COM 				 * setval has completed before this
13447836SJohn.Forte@Sun.COM 				 * function returns.
13457836SJohn.Forte@Sun.COM 				 */
13467836SJohn.Forte@Sun.COM 				if (ncall_send(np, 0, NSC_SETVAL) == 0)
13477836SJohn.Forte@Sun.COM 					(void) ncall_read_reply(np, 1, &rc);
13487836SJohn.Forte@Sun.COM 			}
13497836SJohn.Forte@Sun.COM 
13507836SJohn.Forte@Sun.COM 			ncall_reset(np);
13517836SJohn.Forte@Sun.COM 		}
13527836SJohn.Forte@Sun.COM 
13537836SJohn.Forte@Sun.COM 		ncall_free(np);
13547836SJohn.Forte@Sun.COM 		rc = 0;
13557836SJohn.Forte@Sun.COM 	} else {
13567836SJohn.Forte@Sun.COM 		rc = ENODEV;
13577836SJohn.Forte@Sun.COM 	}
13587836SJohn.Forte@Sun.COM 
13597836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_devval_lock);
13607836SJohn.Forte@Sun.COM 
13617836SJohn.Forte@Sun.COM 	ncall_reply(ncall, rc);
13627836SJohn.Forte@Sun.COM 
13637836SJohn.Forte@Sun.COM 	nsc_kmem_free(out, sizeof (*out));
13647836SJohn.Forte@Sun.COM 	nsc_kmem_free(in, sizeof (*in));
13657836SJohn.Forte@Sun.COM }
13667836SJohn.Forte@Sun.COM 
13677836SJohn.Forte@Sun.COM 
13687836SJohn.Forte@Sun.COM /*
13697836SJohn.Forte@Sun.COM  * int
13707836SJohn.Forte@Sun.COM  * nsc_setval (nsc_fd_t *fd, char *name, int val)
13717836SJohn.Forte@Sun.COM  *	Set value for device.
13727836SJohn.Forte@Sun.COM  *
13737836SJohn.Forte@Sun.COM  * Calling/Exit State:
13747836SJohn.Forte@Sun.COM  *	Returns 1 if the value has been set, otherwise 0.
13757836SJohn.Forte@Sun.COM  *	Must be called with the fd reserved.
13767836SJohn.Forte@Sun.COM  *
13777836SJohn.Forte@Sun.COM  * Description:
13787836SJohn.Forte@Sun.COM  *	Sets the specified global variable for the device
13797836SJohn.Forte@Sun.COM  *	to the value provided.
13807836SJohn.Forte@Sun.COM  */
13817836SJohn.Forte@Sun.COM int
nsc_setval(nsc_fd_t * fd,char * name,int val)13827836SJohn.Forte@Sun.COM nsc_setval(nsc_fd_t *fd, char *name, int val)
13837836SJohn.Forte@Sun.COM {
13847836SJohn.Forte@Sun.COM 	if (!fd)
13857836SJohn.Forte@Sun.COM 		return (0);
13867836SJohn.Forte@Sun.COM 
13877836SJohn.Forte@Sun.COM 	if (!nsc_held(fd))
13887836SJohn.Forte@Sun.COM 		return (0);
13897836SJohn.Forte@Sun.COM 
13907836SJohn.Forte@Sun.COM 	return (_nsc_setval(fd->sf_dev, NULL, name, val, TRUE));
13917836SJohn.Forte@Sun.COM }
13927836SJohn.Forte@Sun.COM 
13937836SJohn.Forte@Sun.COM 
13947836SJohn.Forte@Sun.COM /*
13957836SJohn.Forte@Sun.COM  * int
13967836SJohn.Forte@Sun.COM  * nsc_getval (nsc_fd_t *fd, char *name, int *vp)
13977836SJohn.Forte@Sun.COM  *	Get value from device.
13987836SJohn.Forte@Sun.COM  *
13997836SJohn.Forte@Sun.COM  * Calling/Exit State:
14007836SJohn.Forte@Sun.COM  *	Returns 1 if the value has been found, otherwise 0.
14017836SJohn.Forte@Sun.COM  *	Must be called with the fd reserved, except for "DevMaj" / "DevMin".
14027836SJohn.Forte@Sun.COM  *
14037836SJohn.Forte@Sun.COM  * Description:
14047836SJohn.Forte@Sun.COM  *	Finds the value of the specified device variable for
14057836SJohn.Forte@Sun.COM  *	the device and returns it in the location pointed to
14067836SJohn.Forte@Sun.COM  *	by vp.
14077836SJohn.Forte@Sun.COM  */
14087836SJohn.Forte@Sun.COM int
nsc_getval(nsc_fd_t * fd,char * name,int * vp)14097836SJohn.Forte@Sun.COM nsc_getval(nsc_fd_t *fd, char *name, int *vp)
14107836SJohn.Forte@Sun.COM {
14117836SJohn.Forte@Sun.COM 	nsc_devval_t *dv;
14127836SJohn.Forte@Sun.COM 	nsc_val_t *val;
14137836SJohn.Forte@Sun.COM 
14147836SJohn.Forte@Sun.COM 	if (!fd)
14157836SJohn.Forte@Sun.COM 		return (0);
14167836SJohn.Forte@Sun.COM 
14177836SJohn.Forte@Sun.COM 	/*
14187836SJohn.Forte@Sun.COM 	 * Don't check for nsc_held() for the device number values
14197836SJohn.Forte@Sun.COM 	 * since these are magically created and cannot change when
14207836SJohn.Forte@Sun.COM 	 * the fd is not reserved.
14217836SJohn.Forte@Sun.COM 	 */
14227836SJohn.Forte@Sun.COM 
14237836SJohn.Forte@Sun.COM 	if (strcmp(name, NSC_DEVMAJ) != 0 &&
14247836SJohn.Forte@Sun.COM 	    strcmp(name, NSC_DEVMIN) != 0 &&
14257836SJohn.Forte@Sun.COM 	    !nsc_held(fd))
14267836SJohn.Forte@Sun.COM 		return (0);
14277836SJohn.Forte@Sun.COM 
14287836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_devval_lock);
14297836SJohn.Forte@Sun.COM 
14307836SJohn.Forte@Sun.COM 	dv = fd->sf_dev->nsc_values;
14317836SJohn.Forte@Sun.COM 	val = NULL;
14327836SJohn.Forte@Sun.COM 
14337836SJohn.Forte@Sun.COM 	if (dv != NULL) {
14347836SJohn.Forte@Sun.COM 		for (val = dv->dv_values; val; val = val->sv_next) {
14357836SJohn.Forte@Sun.COM 			if (strcmp(val->sv_name, name) == 0) {
14367836SJohn.Forte@Sun.COM 				*vp = val->sv_value;
14377836SJohn.Forte@Sun.COM 				break;
14387836SJohn.Forte@Sun.COM 			}
14397836SJohn.Forte@Sun.COM 		}
14407836SJohn.Forte@Sun.COM 	}
14417836SJohn.Forte@Sun.COM 
14427836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_devval_lock);
14437836SJohn.Forte@Sun.COM 
14447836SJohn.Forte@Sun.COM 	return (val ? 1 : 0);
14457836SJohn.Forte@Sun.COM }
14467836SJohn.Forte@Sun.COM 
14477836SJohn.Forte@Sun.COM 
14487836SJohn.Forte@Sun.COM /*
14497836SJohn.Forte@Sun.COM  * char *
14507836SJohn.Forte@Sun.COM  * nsc_shared (nsc_fd_t *fd)
14517836SJohn.Forte@Sun.COM  *	Device is currently shared.
14527836SJohn.Forte@Sun.COM  *
14537836SJohn.Forte@Sun.COM  * Calling/Exit State:
14547836SJohn.Forte@Sun.COM  *	The device lock must be held across calls to this
14557836SJohn.Forte@Sun.COM  *	this function.
14567836SJohn.Forte@Sun.COM  *
14577836SJohn.Forte@Sun.COM  *	Returns an indication of whether the device accessed
14587836SJohn.Forte@Sun.COM  *	by the file descriptor is currently referenced by more
14597836SJohn.Forte@Sun.COM  *	than one user.
14607836SJohn.Forte@Sun.COM  *
14617836SJohn.Forte@Sun.COM  *	This is only intended for use in performance critical
14627836SJohn.Forte@Sun.COM  *	situations.
14637836SJohn.Forte@Sun.COM  */
14647836SJohn.Forte@Sun.COM int
nsc_shared(fd)14657836SJohn.Forte@Sun.COM nsc_shared(fd)
14667836SJohn.Forte@Sun.COM nsc_fd_t *fd;
14677836SJohn.Forte@Sun.COM {
14687836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev;
14697836SJohn.Forte@Sun.COM 	int cnt = 0;
14707836SJohn.Forte@Sun.COM 
14717836SJohn.Forte@Sun.COM 	if (!fd)
14727836SJohn.Forte@Sun.COM 		return (0);
14737836SJohn.Forte@Sun.COM 	if (!fd->sf_iodev)
14747836SJohn.Forte@Sun.COM 		return (1);
14757836SJohn.Forte@Sun.COM 
14767836SJohn.Forte@Sun.COM 	for (iodev = fd->sf_dev->nsc_list; iodev; iodev = iodev->si_next)
14777836SJohn.Forte@Sun.COM 		for (fd = iodev->si_open; fd; fd = fd->sf_next)
14787836SJohn.Forte@Sun.COM 			if (!fd->sf_owner && cnt++)
14797836SJohn.Forte@Sun.COM 				return (1);
14807836SJohn.Forte@Sun.COM 
14817836SJohn.Forte@Sun.COM 	return (0);
14827836SJohn.Forte@Sun.COM }
14837836SJohn.Forte@Sun.COM 
14847836SJohn.Forte@Sun.COM 
14857836SJohn.Forte@Sun.COM /*
14867836SJohn.Forte@Sun.COM  * kmutex_t *
14877836SJohn.Forte@Sun.COM  * nsc_lock_addr (nsc_fd_t *fd)
14887836SJohn.Forte@Sun.COM  *	Address of device lock.
14897836SJohn.Forte@Sun.COM  *
14907836SJohn.Forte@Sun.COM  * Calling/Exit State:
14917836SJohn.Forte@Sun.COM  *	Returns a pointer to the spin lock associated with the
14927836SJohn.Forte@Sun.COM  *	device.
14937836SJohn.Forte@Sun.COM  *
14947836SJohn.Forte@Sun.COM  * Description:
14957836SJohn.Forte@Sun.COM  *	This is only intended for use in performance critical
14967836SJohn.Forte@Sun.COM  *	situations in conjunction with nsc_reserve_lk.
14977836SJohn.Forte@Sun.COM  */
14987836SJohn.Forte@Sun.COM kmutex_t *
nsc_lock_addr(fd)14997836SJohn.Forte@Sun.COM nsc_lock_addr(fd)
15007836SJohn.Forte@Sun.COM nsc_fd_t *fd;
15017836SJohn.Forte@Sun.COM {
15027836SJohn.Forte@Sun.COM 	return (&fd->sf_dev->nsc_lock);
15037836SJohn.Forte@Sun.COM }
15047836SJohn.Forte@Sun.COM 
15057836SJohn.Forte@Sun.COM 
15067836SJohn.Forte@Sun.COM /*
15077836SJohn.Forte@Sun.COM  * int
15087836SJohn.Forte@Sun.COM  * _nsc_call_io (long f, blind_t a, blind_t b, blind_t c)
15097836SJohn.Forte@Sun.COM  *	Call information function.
15107836SJohn.Forte@Sun.COM  *
15117836SJohn.Forte@Sun.COM  * Calling/Exit State:
15127836SJohn.Forte@Sun.COM  *	Returns result from function or 0 if not available.
15137836SJohn.Forte@Sun.COM  *	f represents the offset into the I/O structure at which
15147836SJohn.Forte@Sun.COM  *	the required function can be found and a, b, c are the
15157836SJohn.Forte@Sun.COM  *	desired arguments.
15167836SJohn.Forte@Sun.COM  *
15177836SJohn.Forte@Sun.COM  * Description:
15187836SJohn.Forte@Sun.COM  *	Calls the requested function for the first available
15197836SJohn.Forte@Sun.COM  *	cache interface.
15207836SJohn.Forte@Sun.COM  */
15217836SJohn.Forte@Sun.COM int
_nsc_call_io(long f,blind_t a,blind_t b,blind_t c)15227836SJohn.Forte@Sun.COM _nsc_call_io(long f, blind_t a, blind_t b, blind_t c)
15237836SJohn.Forte@Sun.COM {
15247836SJohn.Forte@Sun.COM 	nsc_io_t *io;
15257836SJohn.Forte@Sun.COM 	int (*fn)();
15267836SJohn.Forte@Sun.COM 	int rc;
15277836SJohn.Forte@Sun.COM 
15287836SJohn.Forte@Sun.COM 	io = _nsc_reserve_io(NULL, NSC_SDBC_ID);
15297836SJohn.Forte@Sun.COM 	if (!io)
15307836SJohn.Forte@Sun.COM 		io = _nsc_reserve_io(NULL, NSC_NULL);
15317836SJohn.Forte@Sun.COM 
15327836SJohn.Forte@Sun.COM 	fn = (blindfn_t)(((long *)io)[f]);
15337836SJohn.Forte@Sun.COM 	rc = (*fn)(a, b, c);
15347836SJohn.Forte@Sun.COM 
15357836SJohn.Forte@Sun.COM 	_nsc_release_io(io);
15367836SJohn.Forte@Sun.COM 	return (rc);
15377836SJohn.Forte@Sun.COM }
15387836SJohn.Forte@Sun.COM 
15397836SJohn.Forte@Sun.COM 
15407836SJohn.Forte@Sun.COM /*
15417836SJohn.Forte@Sun.COM  * nsc_io_t *
15427836SJohn.Forte@Sun.COM  * _nsc_reserve_io (char *, int type)
15437836SJohn.Forte@Sun.COM  *	Reserve I/O module.
15447836SJohn.Forte@Sun.COM  *
15457836SJohn.Forte@Sun.COM  * Calling/Exit State:
15467836SJohn.Forte@Sun.COM  *	Returns address of I/O structure matching specified
15477836SJohn.Forte@Sun.COM  *	type, or NULL.
15487836SJohn.Forte@Sun.COM  *
15497836SJohn.Forte@Sun.COM  * Description:
15507836SJohn.Forte@Sun.COM  *	Searches for an appropriate I/O module and increments
15517836SJohn.Forte@Sun.COM  *	the reference count to prevent it being unregistered.
15527836SJohn.Forte@Sun.COM  */
15537836SJohn.Forte@Sun.COM nsc_io_t *
_nsc_reserve_io(path,type)15547836SJohn.Forte@Sun.COM _nsc_reserve_io(path, type)
15557836SJohn.Forte@Sun.COM char *path;
15567836SJohn.Forte@Sun.COM int type;
15577836SJohn.Forte@Sun.COM {
15587836SJohn.Forte@Sun.COM 	nsc_io_t *io;
15597836SJohn.Forte@Sun.COM 
15607836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
15617836SJohn.Forte@Sun.COM 
15627836SJohn.Forte@Sun.COM 	if ((io = _nsc_find_io(path, type, NULL)) != 0)
15637836SJohn.Forte@Sun.COM 		io->refcnt++;
15647836SJohn.Forte@Sun.COM 
15657836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
15667836SJohn.Forte@Sun.COM 	return (io);
15677836SJohn.Forte@Sun.COM }
15687836SJohn.Forte@Sun.COM 
15697836SJohn.Forte@Sun.COM 
15707836SJohn.Forte@Sun.COM /*
15717836SJohn.Forte@Sun.COM  * static nsc_io_t *
15727836SJohn.Forte@Sun.COM  * _nsc_find_io (char *path, int type, int *changed)
15737836SJohn.Forte@Sun.COM  *	Find I/O module.
15747836SJohn.Forte@Sun.COM  *
15757836SJohn.Forte@Sun.COM  * Calling/Exit State:
15767836SJohn.Forte@Sun.COM  *	The _nsc_io_lock must be held across calls to
15777836SJohn.Forte@Sun.COM  *	this function.
15787836SJohn.Forte@Sun.COM  *
15797836SJohn.Forte@Sun.COM  *	Returns address of I/O structure matching specified
15807836SJohn.Forte@Sun.COM  *	type, or NULL.
15817836SJohn.Forte@Sun.COM  *
15827836SJohn.Forte@Sun.COM  *	'changed' will be set to non-zero if there is a pending
15837836SJohn.Forte@Sun.COM  *	nsc_path_t that matches the criteria for the requested type.
15847836SJohn.Forte@Sun.COM  *	This allows nsctl to distinguish between multiple
15857836SJohn.Forte@Sun.COM  *	nsc_register_path's done by the same I/O provider.
15867836SJohn.Forte@Sun.COM  *
15877836SJohn.Forte@Sun.COM  * Description:
15887836SJohn.Forte@Sun.COM  *	Searches for an appropriate I/O module.
15897836SJohn.Forte@Sun.COM  *
15907836SJohn.Forte@Sun.COM  *	1.  If <type> is a single module id find the specified I/O
15917836SJohn.Forte@Sun.COM  *	    module by module id.
15927836SJohn.Forte@Sun.COM  *
15937836SJohn.Forte@Sun.COM  *	2.  Find the highest module that provides any of the I/O types
15947836SJohn.Forte@Sun.COM  *	    included in <type>, taking into account any modules
15957836SJohn.Forte@Sun.COM  *	    registered via the nsc_register_path() interface if <path>
15967836SJohn.Forte@Sun.COM  *	    is non-NULL.
15977836SJohn.Forte@Sun.COM  *
15987836SJohn.Forte@Sun.COM  *	3.  Find an I/O module following the rules in (2), but whose
15997836SJohn.Forte@Sun.COM  *	    module id is less than the id OR'd into <type>.
16007836SJohn.Forte@Sun.COM  *
16017836SJohn.Forte@Sun.COM  *	If no module is found by the above algorithms and NSC_NULL was
16027836SJohn.Forte@Sun.COM  *	included in <type>, return the _nsc_null_io module. Otherwise
16037836SJohn.Forte@Sun.COM  *	return NULL.
16047836SJohn.Forte@Sun.COM  */
16057836SJohn.Forte@Sun.COM static nsc_io_t *
_nsc_find_io(char * path,int type,int * changed)16067836SJohn.Forte@Sun.COM _nsc_find_io(char *path, int type, int *changed)
16077836SJohn.Forte@Sun.COM {
16087836SJohn.Forte@Sun.COM 	nsc_path_t *sp = NULL;
16097836SJohn.Forte@Sun.COM 	nsc_path_t *pp = NULL;
16107836SJohn.Forte@Sun.COM 	nsc_io_t *io;
16117836SJohn.Forte@Sun.COM 
16127836SJohn.Forte@Sun.COM 	type &= NSC_TYPES;
16137836SJohn.Forte@Sun.COM 
16147836SJohn.Forte@Sun.COM 	if (path) {
16157836SJohn.Forte@Sun.COM 		for (sp = _nsc_path_top; sp; sp = sp->sp_next) {
16167836SJohn.Forte@Sun.COM 			if ((type & NSC_ID) &&
16177836SJohn.Forte@Sun.COM 			    sp->sp_io->id >= (type & NSC_IDS))
16187836SJohn.Forte@Sun.COM 				continue;
16197836SJohn.Forte@Sun.COM 
16207836SJohn.Forte@Sun.COM 			if (sp->sp_pend || (type & sp->sp_type) == 0)
16217836SJohn.Forte@Sun.COM 				continue;
16227836SJohn.Forte@Sun.COM 
16237836SJohn.Forte@Sun.COM 			if (nsc_strmatch(path, sp->sp_path))
16247836SJohn.Forte@Sun.COM 				break;
16257836SJohn.Forte@Sun.COM 		}
16267836SJohn.Forte@Sun.COM 
16277836SJohn.Forte@Sun.COM 		if (sp) {
16287836SJohn.Forte@Sun.COM 			/* look for matching pending paths */
16297836SJohn.Forte@Sun.COM 			for (pp = _nsc_path_top; pp; pp = pp->sp_next) {
16307836SJohn.Forte@Sun.COM 				if (pp->sp_pend &&
16317836SJohn.Forte@Sun.COM 				    (type & pp->sp_type) &&
16327836SJohn.Forte@Sun.COM 				    nsc_strmatch(path, pp->sp_path)) {
16337836SJohn.Forte@Sun.COM 					break;
16347836SJohn.Forte@Sun.COM 				}
16357836SJohn.Forte@Sun.COM 			}
16367836SJohn.Forte@Sun.COM 		}
16377836SJohn.Forte@Sun.COM 	}
16387836SJohn.Forte@Sun.COM 
16397836SJohn.Forte@Sun.COM 	for (io = _nsc_io_top; io; io = io->next) {
16407836SJohn.Forte@Sun.COM 		if (io->pend)
16417836SJohn.Forte@Sun.COM 			continue;
16427836SJohn.Forte@Sun.COM 
16437836SJohn.Forte@Sun.COM 		if (type & NSC_ID) {
16447836SJohn.Forte@Sun.COM 			if ((type & ~NSC_IDS) == 0) {
16457836SJohn.Forte@Sun.COM 				if (io->id == type)
16467836SJohn.Forte@Sun.COM 					break;
16477836SJohn.Forte@Sun.COM 				continue;
16487836SJohn.Forte@Sun.COM 			}
16497836SJohn.Forte@Sun.COM 
16507836SJohn.Forte@Sun.COM 			if (io->id >= (type & NSC_IDS))
16517836SJohn.Forte@Sun.COM 				continue;
16527836SJohn.Forte@Sun.COM 		}
16537836SJohn.Forte@Sun.COM 
16547836SJohn.Forte@Sun.COM 		if (io->provide & type)
16557836SJohn.Forte@Sun.COM 			break;
16567836SJohn.Forte@Sun.COM 	}
16577836SJohn.Forte@Sun.COM 
16587836SJohn.Forte@Sun.COM 	if (pp && (!io || pp->sp_io->id >= io->id)) {
16597836SJohn.Forte@Sun.COM 		/*
16607836SJohn.Forte@Sun.COM 		 * Mark this as a path change.
16617836SJohn.Forte@Sun.COM 		 */
16627836SJohn.Forte@Sun.COM 		if (changed) {
16637836SJohn.Forte@Sun.COM 			*changed = 1;
16647836SJohn.Forte@Sun.COM 		}
16657836SJohn.Forte@Sun.COM 	}
16667836SJohn.Forte@Sun.COM 
16677836SJohn.Forte@Sun.COM 	if (sp && (!io || sp->sp_io->id >= io->id))
16687836SJohn.Forte@Sun.COM 		io = sp->sp_io;
16697836SJohn.Forte@Sun.COM 
16707836SJohn.Forte@Sun.COM 	if (!io && !(type & NSC_NULL))
16717836SJohn.Forte@Sun.COM 		return (NULL);
16727836SJohn.Forte@Sun.COM 
16737836SJohn.Forte@Sun.COM 	if (!io)
16747836SJohn.Forte@Sun.COM 		io = _nsc_null_io;
16757836SJohn.Forte@Sun.COM 
16767836SJohn.Forte@Sun.COM 	return (io);
16777836SJohn.Forte@Sun.COM }
16787836SJohn.Forte@Sun.COM 
16797836SJohn.Forte@Sun.COM 
16807836SJohn.Forte@Sun.COM /*
16817836SJohn.Forte@Sun.COM  * void
16827836SJohn.Forte@Sun.COM  * _nsc_release_io (nsc_io_t *)
16837836SJohn.Forte@Sun.COM  *	Release I/O module.
16847836SJohn.Forte@Sun.COM  *
16857836SJohn.Forte@Sun.COM  * Description:
16867836SJohn.Forte@Sun.COM  *	Releases reference to I/O structure and wakes up
16877836SJohn.Forte@Sun.COM  *	anybody waiting on it.
16887836SJohn.Forte@Sun.COM  */
16897836SJohn.Forte@Sun.COM void
_nsc_release_io(io)16907836SJohn.Forte@Sun.COM _nsc_release_io(io)
16917836SJohn.Forte@Sun.COM nsc_io_t *io;
16927836SJohn.Forte@Sun.COM {
16937836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
16947836SJohn.Forte@Sun.COM 
16957836SJohn.Forte@Sun.COM 	io->refcnt--;
16967836SJohn.Forte@Sun.COM 	cv_broadcast(&io->cv);
16977836SJohn.Forte@Sun.COM 
16987836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
16997836SJohn.Forte@Sun.COM }
17007836SJohn.Forte@Sun.COM 
17017836SJohn.Forte@Sun.COM 
17027836SJohn.Forte@Sun.COM /*
17037836SJohn.Forte@Sun.COM  * static int
17047836SJohn.Forte@Sun.COM  * _nsc_alloc_fd (char *path, int type, int flag, nsc_fd_t **fdp)
17057836SJohn.Forte@Sun.COM  *	Allocate file descriptor structure.
17067836SJohn.Forte@Sun.COM  *
17077836SJohn.Forte@Sun.COM  * Calling/Exit State:
17087836SJohn.Forte@Sun.COM  *	Stores address of file descriptor through fdp and
17097836SJohn.Forte@Sun.COM  *	returns 0 on success, otherwise returns error code.
17107836SJohn.Forte@Sun.COM  *
17117836SJohn.Forte@Sun.COM  * Description:
17127836SJohn.Forte@Sun.COM  *	A new file descriptor is allocated and linked in to
17137836SJohn.Forte@Sun.COM  *	the file descriptor chain which is protected by the
17147836SJohn.Forte@Sun.COM  *	device lock.
17157836SJohn.Forte@Sun.COM  *
17167836SJohn.Forte@Sun.COM  *	On return the file descriptor must contain all the
17177836SJohn.Forte@Sun.COM  *	information necessary to perform an open. Details
17187836SJohn.Forte@Sun.COM  *	specific to user callbacks are not required yet.
17197836SJohn.Forte@Sun.COM  */
17207836SJohn.Forte@Sun.COM static int
_nsc_alloc_fd(path,type,flag,fdp)17217836SJohn.Forte@Sun.COM _nsc_alloc_fd(path, type, flag, fdp)
17227836SJohn.Forte@Sun.COM char *path;
17237836SJohn.Forte@Sun.COM int type, flag;
17247836SJohn.Forte@Sun.COM nsc_fd_t **fdp;
17257836SJohn.Forte@Sun.COM {
17267836SJohn.Forte@Sun.COM 	nsc_dev_t *dev;
17277836SJohn.Forte@Sun.COM 	nsc_fd_t *fd;
17287836SJohn.Forte@Sun.COM 	int rc;
17297836SJohn.Forte@Sun.COM 
17307836SJohn.Forte@Sun.COM 	if (!(fd = (nsc_fd_t *)nsc_kmem_zalloc(
17317836SJohn.Forte@Sun.COM 				sizeof (*fd), KM_SLEEP, _nsc_local_mem)))
17327836SJohn.Forte@Sun.COM 		return (ENOMEM);
17337836SJohn.Forte@Sun.COM 
17347836SJohn.Forte@Sun.COM 	if ((rc = _nsc_alloc_dev(path, &dev)) != 0) {
17357836SJohn.Forte@Sun.COM 		nsc_kmem_free(fd, sizeof (*fd));
17367836SJohn.Forte@Sun.COM 		return (rc);
17377836SJohn.Forte@Sun.COM 	}
17387836SJohn.Forte@Sun.COM 
17397836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
17407836SJohn.Forte@Sun.COM 
17417836SJohn.Forte@Sun.COM 	fd->sf_type = type;
17427836SJohn.Forte@Sun.COM 	fd->sf_flag = flag;
17437836SJohn.Forte@Sun.COM 	fd->sf_dev = dev;
17447836SJohn.Forte@Sun.COM 	fd->sf_next = dev->nsc_close;
17457836SJohn.Forte@Sun.COM 	dev->nsc_close = fd;
17467836SJohn.Forte@Sun.COM 
17477836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
17487836SJohn.Forte@Sun.COM 
17497836SJohn.Forte@Sun.COM 	*fdp = fd;
17507836SJohn.Forte@Sun.COM 	return (0);
17517836SJohn.Forte@Sun.COM }
17527836SJohn.Forte@Sun.COM 
17537836SJohn.Forte@Sun.COM 
17547836SJohn.Forte@Sun.COM /*
17557836SJohn.Forte@Sun.COM  * static int
17567836SJohn.Forte@Sun.COM  * _nsc_free_fd (nsc_fd_t *)
17577836SJohn.Forte@Sun.COM  *	Free file descriptor.
17587836SJohn.Forte@Sun.COM  *
17597836SJohn.Forte@Sun.COM  * Description:
17607836SJohn.Forte@Sun.COM  *	The file descriptor is removed from the chain and free'd
17617836SJohn.Forte@Sun.COM  *	once pending activity has completed.
17627836SJohn.Forte@Sun.COM  */
17637836SJohn.Forte@Sun.COM static void
_nsc_free_fd(fd)17647836SJohn.Forte@Sun.COM _nsc_free_fd(fd)
17657836SJohn.Forte@Sun.COM nsc_fd_t *fd;
17667836SJohn.Forte@Sun.COM {
17677836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
17687836SJohn.Forte@Sun.COM 	nsc_fd_t **fdp;
17697836SJohn.Forte@Sun.COM 
17707836SJohn.Forte@Sun.COM 	if (!fd)
17717836SJohn.Forte@Sun.COM 		return;
17727836SJohn.Forte@Sun.COM 
17737836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
17747836SJohn.Forte@Sun.COM 
17757836SJohn.Forte@Sun.COM 	for (fdp = &dev->nsc_close; *fdp; fdp = &(*fdp)->sf_next)
17767836SJohn.Forte@Sun.COM 		if (*fdp == fd) {
17777836SJohn.Forte@Sun.COM 			*fdp = fd->sf_next;
17787836SJohn.Forte@Sun.COM 			break;
17797836SJohn.Forte@Sun.COM 		}
17807836SJohn.Forte@Sun.COM 
17817836SJohn.Forte@Sun.COM 	if (dev->nsc_wait || dev->nsc_refcnt <= 0)
17827836SJohn.Forte@Sun.COM 		cv_broadcast(&dev->nsc_cv);
17837836SJohn.Forte@Sun.COM 
17847836SJohn.Forte@Sun.COM 	while (fd->sf_pend)
17857836SJohn.Forte@Sun.COM 		(void) _nsc_wait_dev(dev, 0);
17867836SJohn.Forte@Sun.COM 
17877836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
17887836SJohn.Forte@Sun.COM 
17897836SJohn.Forte@Sun.COM 	_nsc_free_dev(dev);
17907836SJohn.Forte@Sun.COM 
17917836SJohn.Forte@Sun.COM 	nsc_kmem_free(fd, sizeof (*fd));
17927836SJohn.Forte@Sun.COM }
17937836SJohn.Forte@Sun.COM 
17947836SJohn.Forte@Sun.COM 
17957836SJohn.Forte@Sun.COM /*
17967836SJohn.Forte@Sun.COM  * static void
17977836SJohn.Forte@Sun.COM  * _nsc_relink_fd (nsc_fd_t *fd, nsc_fd_t **from,
17987836SJohn.Forte@Sun.COM  *				nsc_fd_t **to, nsc_iodev_t *iodev)
17997836SJohn.Forte@Sun.COM  *	Relink file descriptor.
18007836SJohn.Forte@Sun.COM  *
18017836SJohn.Forte@Sun.COM  * Description:
18027836SJohn.Forte@Sun.COM  *	Remove the file descriptor from the 'from' chain and
18037836SJohn.Forte@Sun.COM  *	add it to the 'to' chain. The busy flag in iodev is
18047836SJohn.Forte@Sun.COM  *	used to prevent modifications to the chain whilst a
18057836SJohn.Forte@Sun.COM  *	callback is in progress.
18067836SJohn.Forte@Sun.COM  */
18077836SJohn.Forte@Sun.COM static void
_nsc_relink_fd(nsc_fd_t * fd,nsc_fd_t ** from,nsc_fd_t ** to,nsc_iodev_t * iodev)18087836SJohn.Forte@Sun.COM _nsc_relink_fd(nsc_fd_t *fd, nsc_fd_t **from, nsc_fd_t **to, nsc_iodev_t *iodev)
18097836SJohn.Forte@Sun.COM {
18107836SJohn.Forte@Sun.COM 	nsc_dev_t *dev = fd->sf_dev;
18117836SJohn.Forte@Sun.COM 	nsc_fd_t **fdp;
18127836SJohn.Forte@Sun.COM 
18137836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
18147836SJohn.Forte@Sun.COM 
18157836SJohn.Forte@Sun.COM 	while (iodev->si_busy)
18167836SJohn.Forte@Sun.COM 		(void) _nsc_wait_dev(dev, 0);
18177836SJohn.Forte@Sun.COM 
18187836SJohn.Forte@Sun.COM 	for (fdp = from; *fdp; fdp = &(*fdp)->sf_next)
18197836SJohn.Forte@Sun.COM 		if (*fdp == fd) {
18207836SJohn.Forte@Sun.COM 			*fdp = fd->sf_next;
18217836SJohn.Forte@Sun.COM 			break;
18227836SJohn.Forte@Sun.COM 		}
18237836SJohn.Forte@Sun.COM 
18247836SJohn.Forte@Sun.COM 	fd->sf_next = (*to);
18257836SJohn.Forte@Sun.COM 	(*to) = fd;
18267836SJohn.Forte@Sun.COM 
18277836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
18287836SJohn.Forte@Sun.COM }
18297836SJohn.Forte@Sun.COM 
18307836SJohn.Forte@Sun.COM 
18317836SJohn.Forte@Sun.COM /*
18327836SJohn.Forte@Sun.COM  * static int
18337836SJohn.Forte@Sun.COM  * _nsc_alloc_iodev (nsc_dev_t *dev, int type, nsc_iodev_t **iodevp)
18347836SJohn.Forte@Sun.COM  *	Allocate I/O device structure.
18357836SJohn.Forte@Sun.COM  *
18367836SJohn.Forte@Sun.COM  * Calling/Exit State:
18377836SJohn.Forte@Sun.COM  *	Stores address of I/O device structure through iodevp
18387836SJohn.Forte@Sun.COM  *	and returns 0 on success, otherwise returns error code.
18397836SJohn.Forte@Sun.COM  *
18407836SJohn.Forte@Sun.COM  * Description:
18417836SJohn.Forte@Sun.COM  *	If an entry for the I/O device already exists increment
18427836SJohn.Forte@Sun.COM  *	the reference count and return the address, otherwise
18437836SJohn.Forte@Sun.COM  *	allocate a new structure.
18447836SJohn.Forte@Sun.COM  *
18457836SJohn.Forte@Sun.COM  *	A new structure is allocated before scanning the chain
18467836SJohn.Forte@Sun.COM  *	to avoid calling the memory allocator with a spin lock
18477836SJohn.Forte@Sun.COM  *	held. If an entry is found the new structure is free'd.
18487836SJohn.Forte@Sun.COM  *
18497836SJohn.Forte@Sun.COM  *	The I/O device chain is protected by the device lock.
18507836SJohn.Forte@Sun.COM  */
18517836SJohn.Forte@Sun.COM static int
_nsc_alloc_iodev(dev,type,iodevp)18527836SJohn.Forte@Sun.COM _nsc_alloc_iodev(dev, type, iodevp)
18537836SJohn.Forte@Sun.COM nsc_dev_t *dev;
18547836SJohn.Forte@Sun.COM int type;
18557836SJohn.Forte@Sun.COM nsc_iodev_t **iodevp;
18567836SJohn.Forte@Sun.COM {
18577836SJohn.Forte@Sun.COM 	nsc_iodev_t *iodev, *ip;
18587836SJohn.Forte@Sun.COM 	nsc_io_t *io;
18597836SJohn.Forte@Sun.COM 
18607836SJohn.Forte@Sun.COM 	if (!(iodev = (nsc_iodev_t *)nsc_kmem_zalloc(
18617836SJohn.Forte@Sun.COM 				sizeof (*iodev), KM_SLEEP, _nsc_local_mem)))
18627836SJohn.Forte@Sun.COM 		return (ENOMEM);
18637836SJohn.Forte@Sun.COM 
18647836SJohn.Forte@Sun.COM 	mutex_init(&iodev->si_lock, NULL, MUTEX_DRIVER, NULL);
18657836SJohn.Forte@Sun.COM 	cv_init(&iodev->si_cv, NULL, CV_DRIVER, NULL);
18667836SJohn.Forte@Sun.COM 
18677836SJohn.Forte@Sun.COM 	if (!(io = _nsc_reserve_io(dev->nsc_path, type))) {
18687836SJohn.Forte@Sun.COM 		mutex_destroy(&iodev->si_lock);
18697836SJohn.Forte@Sun.COM 		cv_destroy(&iodev->si_cv);
18707836SJohn.Forte@Sun.COM 		nsc_kmem_free(iodev, sizeof (*iodev));
18717836SJohn.Forte@Sun.COM 		return (ENXIO);
18727836SJohn.Forte@Sun.COM 	}
18737836SJohn.Forte@Sun.COM 
18747836SJohn.Forte@Sun.COM 	iodev->si_refcnt++;
18757836SJohn.Forte@Sun.COM 	iodev->si_io = io;
18767836SJohn.Forte@Sun.COM 	iodev->si_dev = dev;
18777836SJohn.Forte@Sun.COM 
18787836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
18797836SJohn.Forte@Sun.COM 	dev->nsc_refcnt++;
18807836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
18817836SJohn.Forte@Sun.COM 
18827836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
18837836SJohn.Forte@Sun.COM 
18847836SJohn.Forte@Sun.COM 	for (ip = dev->nsc_list; ip; ip = ip->si_next)
18857836SJohn.Forte@Sun.COM 		if (ip->si_io == io) {
18867836SJohn.Forte@Sun.COM 			ip->si_refcnt++;
18877836SJohn.Forte@Sun.COM 			break;
18887836SJohn.Forte@Sun.COM 		}
18897836SJohn.Forte@Sun.COM 
18907836SJohn.Forte@Sun.COM 	if (!ip) {
18917836SJohn.Forte@Sun.COM 		iodev->si_next = dev->nsc_list;
18927836SJohn.Forte@Sun.COM 		dev->nsc_list = iodev;
18937836SJohn.Forte@Sun.COM 	}
18947836SJohn.Forte@Sun.COM 
18957836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
18967836SJohn.Forte@Sun.COM 
18977836SJohn.Forte@Sun.COM 	if (ip) {
18987836SJohn.Forte@Sun.COM 		_nsc_free_iodev(iodev);
18997836SJohn.Forte@Sun.COM 		iodev = ip;
19007836SJohn.Forte@Sun.COM 	}
19017836SJohn.Forte@Sun.COM 
19027836SJohn.Forte@Sun.COM 	*iodevp = iodev;
19037836SJohn.Forte@Sun.COM 	return (0);
19047836SJohn.Forte@Sun.COM }
19057836SJohn.Forte@Sun.COM 
19067836SJohn.Forte@Sun.COM 
19077836SJohn.Forte@Sun.COM /*
19087836SJohn.Forte@Sun.COM  * static int
19097836SJohn.Forte@Sun.COM  * _nsc_free_iodev (nsc_iodev_t *iodev)
19107836SJohn.Forte@Sun.COM  *	Free I/O device structure.
19117836SJohn.Forte@Sun.COM  *
19127836SJohn.Forte@Sun.COM  * Description:
19137836SJohn.Forte@Sun.COM  *	Decrements the reference count of a previously allocated
19147836SJohn.Forte@Sun.COM  *	I/O device structure. If this is the last reference it
19157836SJohn.Forte@Sun.COM  *	is removed from the device chain and free'd once pending
19167836SJohn.Forte@Sun.COM  *	activity has completed.
19177836SJohn.Forte@Sun.COM  */
19187836SJohn.Forte@Sun.COM static void
_nsc_free_iodev(nsc_iodev_t * iodev)19197836SJohn.Forte@Sun.COM _nsc_free_iodev(nsc_iodev_t *iodev)
19207836SJohn.Forte@Sun.COM {
19217836SJohn.Forte@Sun.COM 	nsc_iodev_t **ipp;
19227836SJohn.Forte@Sun.COM 	nsc_dev_t *dev;
19237836SJohn.Forte@Sun.COM 
19247836SJohn.Forte@Sun.COM 	if (!iodev)
19257836SJohn.Forte@Sun.COM 		return;
19267836SJohn.Forte@Sun.COM 
19277836SJohn.Forte@Sun.COM 	dev = iodev->si_dev;
19287836SJohn.Forte@Sun.COM 
19297836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
19307836SJohn.Forte@Sun.COM 
19317836SJohn.Forte@Sun.COM 	if (--iodev->si_refcnt > 0) {
19327836SJohn.Forte@Sun.COM 		mutex_exit(&dev->nsc_lock);
19337836SJohn.Forte@Sun.COM 		return;
19347836SJohn.Forte@Sun.COM 	}
19357836SJohn.Forte@Sun.COM 
19367836SJohn.Forte@Sun.COM 	for (ipp = &dev->nsc_list; *ipp; ipp = &(*ipp)->si_next)
19377836SJohn.Forte@Sun.COM 		if (*ipp == iodev) {
19387836SJohn.Forte@Sun.COM 			*ipp = iodev->si_next;
19397836SJohn.Forte@Sun.COM 			break;
19407836SJohn.Forte@Sun.COM 		}
19417836SJohn.Forte@Sun.COM 
19427836SJohn.Forte@Sun.COM 	if (dev->nsc_wait || dev->nsc_refcnt <= 0)
19437836SJohn.Forte@Sun.COM 		cv_broadcast(&dev->nsc_cv);
19447836SJohn.Forte@Sun.COM 
19457836SJohn.Forte@Sun.COM 	while (iodev->si_pend || iodev->si_rpend || iodev->si_busy)
19467836SJohn.Forte@Sun.COM 		(void) _nsc_wait_dev(dev, 0);
19477836SJohn.Forte@Sun.COM 
19487836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
19497836SJohn.Forte@Sun.COM 
19507836SJohn.Forte@Sun.COM 	_nsc_release_io(iodev->si_io);
19517836SJohn.Forte@Sun.COM 	_nsc_free_dev(dev);
19527836SJohn.Forte@Sun.COM 
19537836SJohn.Forte@Sun.COM 	mutex_destroy(&iodev->si_lock);
19547836SJohn.Forte@Sun.COM 	cv_destroy(&iodev->si_cv);
19557836SJohn.Forte@Sun.COM 
19567836SJohn.Forte@Sun.COM 	nsc_kmem_free(iodev, sizeof (*iodev));
19577836SJohn.Forte@Sun.COM }
19587836SJohn.Forte@Sun.COM 
19597836SJohn.Forte@Sun.COM 
19607836SJohn.Forte@Sun.COM /*
19617836SJohn.Forte@Sun.COM  * static int
19627836SJohn.Forte@Sun.COM  * _nsc_alloc_dev (char *path, nsc_dev_t **devp)
19637836SJohn.Forte@Sun.COM  *	Allocate device structure.
19647836SJohn.Forte@Sun.COM  *
19657836SJohn.Forte@Sun.COM  * Calling/Exit State:
19667836SJohn.Forte@Sun.COM  *	Stores address of device structure through devp
19677836SJohn.Forte@Sun.COM  *	and returns 0 on success, otherwise returns error
19687836SJohn.Forte@Sun.COM  *	code.
19697836SJohn.Forte@Sun.COM  *
19707836SJohn.Forte@Sun.COM  * Description:
19717836SJohn.Forte@Sun.COM  *	If an entry for the device already exists increment
19727836SJohn.Forte@Sun.COM  *	the reference count and return the address, otherwise
19737836SJohn.Forte@Sun.COM  *	allocate a new structure.
19747836SJohn.Forte@Sun.COM  *
19757836SJohn.Forte@Sun.COM  *	A new structure is allocated before scanning the device
19767836SJohn.Forte@Sun.COM  *	chain to avoid calling the memory allocator with a spin
19777836SJohn.Forte@Sun.COM  *	lock held. If the device is found the new structure is
19787836SJohn.Forte@Sun.COM  *	free'd.
19797836SJohn.Forte@Sun.COM  *
19807836SJohn.Forte@Sun.COM  *	The device chain is protected by _nsc_io_lock.
19817836SJohn.Forte@Sun.COM  */
19827836SJohn.Forte@Sun.COM static int
_nsc_alloc_dev(char * path,nsc_dev_t ** devp)19837836SJohn.Forte@Sun.COM _nsc_alloc_dev(char *path, nsc_dev_t **devp)
19847836SJohn.Forte@Sun.COM {
19857836SJohn.Forte@Sun.COM 	nsc_dev_t *dev, *dp, **ddp;
19867836SJohn.Forte@Sun.COM 	nsc_devval_t *dv;
19877836SJohn.Forte@Sun.COM 	nsc_rval_t *rval;
19887836SJohn.Forte@Sun.COM 	ncall_t *ncall;
19897836SJohn.Forte@Sun.COM 	int rc;
19907836SJohn.Forte@Sun.COM 
19917836SJohn.Forte@Sun.COM 	if (!(dev = (nsc_dev_t *)nsc_kmem_zalloc(
19927836SJohn.Forte@Sun.COM 	    sizeof (*dev), KM_SLEEP, _nsc_local_mem)))
19937836SJohn.Forte@Sun.COM 		return (ENOMEM);
19947836SJohn.Forte@Sun.COM 
19957836SJohn.Forte@Sun.COM 	dev->nsc_refcnt++;
19967836SJohn.Forte@Sun.COM 
19977836SJohn.Forte@Sun.COM 	mutex_init(&dev->nsc_lock, NULL, MUTEX_DRIVER, NULL);
19987836SJohn.Forte@Sun.COM 	cv_init(&dev->nsc_cv, NULL, CV_DRIVER, NULL);
19997836SJohn.Forte@Sun.COM 
20007836SJohn.Forte@Sun.COM 	dev->nsc_phash = nsc_strhash(path);
20017836SJohn.Forte@Sun.COM 	dev->nsc_path = nsc_strdup(path);
20027836SJohn.Forte@Sun.COM 
20037836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
20047836SJohn.Forte@Sun.COM 
20057836SJohn.Forte@Sun.COM 	dev->nsc_next = _nsc_dev_pend;
20067836SJohn.Forte@Sun.COM 	_nsc_dev_pend = dev;
20077836SJohn.Forte@Sun.COM 
20087836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
20097836SJohn.Forte@Sun.COM 
20107836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
20117836SJohn.Forte@Sun.COM 
20127836SJohn.Forte@Sun.COM 	for (dp = _nsc_dev_top; dp; dp = dp->nsc_next)
20137836SJohn.Forte@Sun.COM 		if (dp->nsc_phash == dev->nsc_phash &&
20147836SJohn.Forte@Sun.COM 		    strcmp(dp->nsc_path, dev->nsc_path) == 0) {
20157836SJohn.Forte@Sun.COM 			dp->nsc_refcnt++;
20167836SJohn.Forte@Sun.COM 			break;
20177836SJohn.Forte@Sun.COM 		}
20187836SJohn.Forte@Sun.COM 
20197836SJohn.Forte@Sun.COM 	if (!dp) {
20207836SJohn.Forte@Sun.COM 		for (ddp = &_nsc_dev_pend; *ddp; ddp = &(*ddp)->nsc_next)
20217836SJohn.Forte@Sun.COM 			if (*ddp == dev) {
20227836SJohn.Forte@Sun.COM 				*ddp = dev->nsc_next;
20237836SJohn.Forte@Sun.COM 				break;
20247836SJohn.Forte@Sun.COM 			}
20257836SJohn.Forte@Sun.COM 
20267836SJohn.Forte@Sun.COM 		dev->nsc_next = _nsc_dev_top;
20277836SJohn.Forte@Sun.COM 		_nsc_dev_top = dev;
20287836SJohn.Forte@Sun.COM 	}
20297836SJohn.Forte@Sun.COM 
20307836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
20317836SJohn.Forte@Sun.COM 
20327836SJohn.Forte@Sun.COM 	if (dp) {
20337836SJohn.Forte@Sun.COM 		_nsc_free_dev(dev);
20347836SJohn.Forte@Sun.COM 		dev = dp;
20357836SJohn.Forte@Sun.COM 	}
20367836SJohn.Forte@Sun.COM 
20377836SJohn.Forte@Sun.COM 	/*
20387836SJohn.Forte@Sun.COM 	 * Try and find the device/values header for this device
20397836SJohn.Forte@Sun.COM 	 * and link it back to the device structure.
20407836SJohn.Forte@Sun.COM 	 */
20417836SJohn.Forte@Sun.COM 
20427836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_devval_lock);
20437836SJohn.Forte@Sun.COM 
20447836SJohn.Forte@Sun.COM 	if (dev->nsc_values == NULL) {
20457836SJohn.Forte@Sun.COM 		for (dv = _nsc_devval_top; dv; dv = dv->dv_next) {
20467836SJohn.Forte@Sun.COM 			if (dv->dv_phash == dev->nsc_phash &&
20477836SJohn.Forte@Sun.COM 			    strcmp(dv->dv_path, dev->nsc_path) == 0) {
20487836SJohn.Forte@Sun.COM 				dev->nsc_values = dv;
20497836SJohn.Forte@Sun.COM 				break;
20507836SJohn.Forte@Sun.COM 			}
20517836SJohn.Forte@Sun.COM 		}
20527836SJohn.Forte@Sun.COM 	}
20537836SJohn.Forte@Sun.COM 
20547836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_devval_lock);
20557836SJohn.Forte@Sun.COM 
20567836SJohn.Forte@Sun.COM 	/*
20577836SJohn.Forte@Sun.COM 	 * Refresh the device/values from the other node
20587836SJohn.Forte@Sun.COM 	 */
20597836SJohn.Forte@Sun.COM 
20607836SJohn.Forte@Sun.COM 	rval = nsc_kmem_zalloc(sizeof (*rval), KM_SLEEP, _nsc_local_mem);
20617836SJohn.Forte@Sun.COM 	if (rval == NULL) {
20627836SJohn.Forte@Sun.COM 		goto out;
20637836SJohn.Forte@Sun.COM 	}
20647836SJohn.Forte@Sun.COM 
20657836SJohn.Forte@Sun.COM 	rc = ncall_alloc(ncall_mirror(ncall_self()), 0, 0, &ncall);
20667836SJohn.Forte@Sun.COM 	if (rc == 0) {
20677836SJohn.Forte@Sun.COM 		(void) strncpy(rval->path, path, sizeof (rval->path));
20687836SJohn.Forte@Sun.COM 
20697836SJohn.Forte@Sun.COM 		rc = ncall_put_data(ncall, rval, sizeof (*rval));
20707836SJohn.Forte@Sun.COM 		if (rc == 0) {
20717836SJohn.Forte@Sun.COM 			/*
20727836SJohn.Forte@Sun.COM 			 * Send synchronously and read a reply
20737836SJohn.Forte@Sun.COM 			 * so that we know that the updates
20747836SJohn.Forte@Sun.COM 			 * have completed before this
20757836SJohn.Forte@Sun.COM 			 * function returns.
20767836SJohn.Forte@Sun.COM 			 */
20777836SJohn.Forte@Sun.COM 			if (ncall_send(ncall, 0, NSC_SETVAL_ALL) == 0)
20787836SJohn.Forte@Sun.COM 				(void) ncall_read_reply(ncall, 1, &rc);
20797836SJohn.Forte@Sun.COM 		}
20807836SJohn.Forte@Sun.COM 
20817836SJohn.Forte@Sun.COM 		ncall_free(ncall);
20827836SJohn.Forte@Sun.COM 	}
20837836SJohn.Forte@Sun.COM 
20847836SJohn.Forte@Sun.COM 	nsc_kmem_free(rval, sizeof (*rval));
20857836SJohn.Forte@Sun.COM 
20867836SJohn.Forte@Sun.COM out:
20877836SJohn.Forte@Sun.COM 	*devp = dev;
20887836SJohn.Forte@Sun.COM 	return (0);
20897836SJohn.Forte@Sun.COM }
20907836SJohn.Forte@Sun.COM 
20917836SJohn.Forte@Sun.COM 
20927836SJohn.Forte@Sun.COM /*
20937836SJohn.Forte@Sun.COM  * static void
20947836SJohn.Forte@Sun.COM  * _nsc_free_dev (nsc_dev_t *dev)
20957836SJohn.Forte@Sun.COM  *	Free device structure.
20967836SJohn.Forte@Sun.COM  *
20977836SJohn.Forte@Sun.COM  * Description:
20987836SJohn.Forte@Sun.COM  *	Decrements the reference count of a previously allocated
20997836SJohn.Forte@Sun.COM  *	device structure. If this is the last reference it is
21007836SJohn.Forte@Sun.COM  *	removed from the device chain and free'd once pending
21017836SJohn.Forte@Sun.COM  *	activity has completed.
21027836SJohn.Forte@Sun.COM  *
21037836SJohn.Forte@Sun.COM  *	Whilst waiting for pending activity to cease the device is
21047836SJohn.Forte@Sun.COM  *	relinked onto the pending chain.
21057836SJohn.Forte@Sun.COM  */
21067836SJohn.Forte@Sun.COM static void
_nsc_free_dev(dev)21077836SJohn.Forte@Sun.COM _nsc_free_dev(dev)
21087836SJohn.Forte@Sun.COM nsc_dev_t *dev;
21097836SJohn.Forte@Sun.COM {
21107836SJohn.Forte@Sun.COM 	nsc_dev_t **ddp;
21117836SJohn.Forte@Sun.COM 
21127836SJohn.Forte@Sun.COM 	if (!dev)
21137836SJohn.Forte@Sun.COM 		return;
21147836SJohn.Forte@Sun.COM 
21157836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
21167836SJohn.Forte@Sun.COM 
21177836SJohn.Forte@Sun.COM 	if (--dev->nsc_refcnt > 0) {
21187836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_io_lock);
21197836SJohn.Forte@Sun.COM 		return;
21207836SJohn.Forte@Sun.COM 	}
21217836SJohn.Forte@Sun.COM 
21227836SJohn.Forte@Sun.COM 	for (ddp = &_nsc_dev_top; *ddp; ddp = &(*ddp)->nsc_next)
21237836SJohn.Forte@Sun.COM 		if (*ddp == dev) {
21247836SJohn.Forte@Sun.COM 			*ddp = dev->nsc_next;
21257836SJohn.Forte@Sun.COM 			dev->nsc_next = _nsc_dev_pend;
21267836SJohn.Forte@Sun.COM 			_nsc_dev_pend = dev;
21277836SJohn.Forte@Sun.COM 			break;
21287836SJohn.Forte@Sun.COM 		}
21297836SJohn.Forte@Sun.COM 
21307836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
21317836SJohn.Forte@Sun.COM 
21327836SJohn.Forte@Sun.COM 	mutex_enter(&dev->nsc_lock);
21337836SJohn.Forte@Sun.COM 
21347836SJohn.Forte@Sun.COM 	while (dev->nsc_pend || dev->nsc_rpend || dev->nsc_wait) {
21357836SJohn.Forte@Sun.COM 		cv_wait(&dev->nsc_cv, &dev->nsc_lock);
21367836SJohn.Forte@Sun.COM 	}
21377836SJohn.Forte@Sun.COM 
21387836SJohn.Forte@Sun.COM 	mutex_exit(&dev->nsc_lock);
21397836SJohn.Forte@Sun.COM 
21407836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
21417836SJohn.Forte@Sun.COM 
21427836SJohn.Forte@Sun.COM 	for (ddp = &_nsc_dev_pend; *ddp; ddp = &(*ddp)->nsc_next)
21437836SJohn.Forte@Sun.COM 		if (*ddp == dev) {
21447836SJohn.Forte@Sun.COM 			*ddp = dev->nsc_next;
21457836SJohn.Forte@Sun.COM 			break;
21467836SJohn.Forte@Sun.COM 		}
21477836SJohn.Forte@Sun.COM 
21487836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
21497836SJohn.Forte@Sun.COM 
21507836SJohn.Forte@Sun.COM 	mutex_destroy(&dev->nsc_lock);
21517836SJohn.Forte@Sun.COM 	cv_destroy(&dev->nsc_cv);
21527836SJohn.Forte@Sun.COM 	nsc_strfree(dev->nsc_path);
21537836SJohn.Forte@Sun.COM 
21547836SJohn.Forte@Sun.COM 	nsc_kmem_free(dev, sizeof (*dev));
21557836SJohn.Forte@Sun.COM }
21567836SJohn.Forte@Sun.COM 
21577836SJohn.Forte@Sun.COM 
21587836SJohn.Forte@Sun.COM /*
21597836SJohn.Forte@Sun.COM  * static nsc_io_t *
21607836SJohn.Forte@Sun.COM  * _nsc_alloc_io (int id, char *name, int flag)
21617836SJohn.Forte@Sun.COM  *	Allocate an I/O structure.
21627836SJohn.Forte@Sun.COM  *
21637836SJohn.Forte@Sun.COM  * Calling/Exit State:
21647836SJohn.Forte@Sun.COM  *	Returns the address of the I/O structure, or NULL.
21657836SJohn.Forte@Sun.COM  */
21667836SJohn.Forte@Sun.COM static nsc_io_t *
_nsc_alloc_io(id,name,flag)21677836SJohn.Forte@Sun.COM _nsc_alloc_io(id, name, flag)
21687836SJohn.Forte@Sun.COM int id;
21697836SJohn.Forte@Sun.COM char *name;
21707836SJohn.Forte@Sun.COM int flag;
21717836SJohn.Forte@Sun.COM {
21727836SJohn.Forte@Sun.COM 	nsc_io_t *io;
21737836SJohn.Forte@Sun.COM 
21747836SJohn.Forte@Sun.COM 	if (!(io = (nsc_io_t *)nsc_kmem_zalloc(
21757836SJohn.Forte@Sun.COM 			sizeof (*io), KM_NOSLEEP, _nsc_local_mem)))
21767836SJohn.Forte@Sun.COM 		return (NULL);
21777836SJohn.Forte@Sun.COM 
21787836SJohn.Forte@Sun.COM 	cv_init(&io->cv, NULL, CV_DRIVER, NULL);
21797836SJohn.Forte@Sun.COM 
21807836SJohn.Forte@Sun.COM 	io->id = id;
21817836SJohn.Forte@Sun.COM 	io->name = name;
21827836SJohn.Forte@Sun.COM 	io->flag = flag;
21837836SJohn.Forte@Sun.COM 
21847836SJohn.Forte@Sun.COM 	return (io);
21857836SJohn.Forte@Sun.COM }
21867836SJohn.Forte@Sun.COM 
21877836SJohn.Forte@Sun.COM 
21887836SJohn.Forte@Sun.COM /*
21897836SJohn.Forte@Sun.COM  * static void
21907836SJohn.Forte@Sun.COM  * _nsc_free_io (int id, char *name, int flag)
21917836SJohn.Forte@Sun.COM  *	Free an I/O structure.
21927836SJohn.Forte@Sun.COM  *
21937836SJohn.Forte@Sun.COM  * Calling/Exit State:
21947836SJohn.Forte@Sun.COM  *	Free the I/O structure and remove it from the chain.
21957836SJohn.Forte@Sun.COM  */
21967836SJohn.Forte@Sun.COM static void
_nsc_free_io(io)21977836SJohn.Forte@Sun.COM _nsc_free_io(io)
21987836SJohn.Forte@Sun.COM nsc_io_t *io;
21997836SJohn.Forte@Sun.COM {
22007836SJohn.Forte@Sun.COM 	nsc_io_t **iop;
22017836SJohn.Forte@Sun.COM 
22027836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_io_lock);
22037836SJohn.Forte@Sun.COM 
22047836SJohn.Forte@Sun.COM 	for (iop = &_nsc_io_top; *iop; iop = &(*iop)->next)
22057836SJohn.Forte@Sun.COM 		if (*iop == io)
22067836SJohn.Forte@Sun.COM 			break;
22077836SJohn.Forte@Sun.COM 
22087836SJohn.Forte@Sun.COM 	if (*iop)
22097836SJohn.Forte@Sun.COM 		(*iop) = io->next;
22107836SJohn.Forte@Sun.COM 
22117836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_io_lock);
22127836SJohn.Forte@Sun.COM 
22137836SJohn.Forte@Sun.COM 	cv_destroy(&io->cv);
22147836SJohn.Forte@Sun.COM 	nsc_kmem_free(io, sizeof (*io));
22157836SJohn.Forte@Sun.COM }
2216