Home | History | Annotate | Download | only in md
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/param.h>
     27 #include <sys/systm.h>
     28 #include <sys/sysmacros.h>
     29 #include <sys/errno.h>
     30 #include <sys/cmn_err.h>
     31 #include <sys/buf.h>
     32 #include <sys/disp.h>
     33 #include <sys/kmem.h>
     34 /* #include <sys/ddi.h> */
     35 /* #include <sys/sunddi.h> */
     36 #include <sys/debug.h>
     37 
     38 #include <sys/time.h>
     39 #include <sys/pathname.h>
     40 #include <sys/netconfig.h>
     41 #include <sys/socket.h>
     42 #include <netinet/in.h>
     43 
     44 #include <rpc/types.h>
     45 #include <rpc/auth.h>
     46 #include <rpc/clnt.h>
     47 #include <rpc/clnt_soc.h>
     48 #include <rpc/pmap_prot.h>	/* PMAPPORT */
     49 #include <rpc/rpc.h>
     50 #include <rpc/rpcb_prot.h>
     51 #include <rpc/xdr.h>		/* This also gets us htonl() et al. */
     52 
     53 
     54 #include <sys/lvm/mdmed.h>
     55 
     56 #define	MDDB
     57 #include <sys/lvm/mdvar.h>
     58 #include <sys/lvm/md_mddb.h>
     59 #include <sys/lvm/md_crc.h>
     60 #include <sys/callb.h>
     61 
     62 /*
     63  * Flag to turn off the kernel RPC client delay code. This only takes effect
     64  * if the route to the remote node is marked as RTF_REJECT and the RPC path
     65  * manager has been flushed such that any 'old' path information is no longer
     66  * present.
     67  */
     68 static	bool_t		clset = TRUE;
     69 
     70 extern	int		md_nmedh;			/* declared in md.c */
     71 extern	char		*md_med_trans_lst;
     72 extern md_set_t		md_set[];			/* declared in md.c */
     73 
     74 /*
     75  * Structures used only by mediators
     76  */
     77 typedef	struct	med_thr_a_args {
     78 	uint_t			mtaa_mag;
     79 	char			*mtaa_h_nm;
     80 	in_addr_t		mtaa_h_ip;
     81 	uint_t			mtaa_h_flags;
     82 	int			(*mtaa_err_func)(struct med_thr_a_args *);
     83 	struct med_thr_h_args	*mtaa_mthap;
     84 	int			mtaa_flags;
     85 	rpcprog_t		mtaa_prog;
     86 	rpcvers_t		mtaa_vers;
     87 	rpcproc_t		mtaa_proc;
     88 	xdrproc_t		mtaa_inproc;
     89 	caddr_t			mtaa_in;
     90 	xdrproc_t		mtaa_outproc;
     91 	caddr_t			mtaa_out;
     92 	struct	timeval		*mtaa_timout;
     93 	int			mtaa_err;
     94 } med_thr_a_args_t;
     95 
     96 #define	MTAA_MAGIC		0xbadbabed
     97 #define	MDT_A_OK		0x00000001
     98 
     99 typedef	struct	med_thr_h_args {
    100 	uint_t			mtha_mag;
    101 	md_hi_t			*mtha_mhp;
    102 	char			*mtha_setname;
    103 	med_data_t		*mtha_meddp;
    104 	struct	med_thr		*mtha_mtp;
    105 	int			mtha_flags;
    106 	set_t			mtha_setno;
    107 	int			mtha_a_cnt;
    108 	kcondvar_t		mtha_a_cv;
    109 	kmutex_t		mtha_a_mx;
    110 	uint_t			mtha_a_nthr;
    111 	med_thr_a_args_t	mtha_a_args[MAX_HOST_ADDRS];
    112 } med_thr_h_args_t;
    113 
    114 #define	MTHA_MAGIC		0xbadbabee
    115 #define	MDT_H_OK		0x00000001
    116 
    117 typedef	struct	med_thr	{
    118 	uint_t			mt_mag;
    119 	kmutex_t		mt_mx;
    120 	kcondvar_t		mt_cv;
    121 	uint_t			mt_nthr;
    122 	med_thr_h_args_t	*mt_h_args[MED_MAX_HOSTS];
    123 } med_thr_t;
    124 
    125 #define	MTH_MAGIC		0xbadbabef
    126 
    127 #ifdef DEBUG
    128 
    129 static	struct	timeval	btv;
    130 static	struct	timeval	etv;
    131 
    132 #define	DBGLVL_NONE	0x00000000
    133 #define	DBGLVL_MAJOR	0x00000100
    134 #define	DBGLVL_MINOR	0x00000200
    135 #define	DBGLVL_MINUTE	0x00000400
    136 #define	DBGLVL_TRIVIA	0x00000800
    137 #define	DBGLVL_HIDEOUS	0x00001000
    138 
    139 #define	DBGFLG_NONE		0x00000000
    140 #define	DBGFLG_NOPANIC		0x00000001
    141 #define	DBGFLG_LVLONLY		0x00000002
    142 #define	DBGFLG_FIXWOULDPANIC	0x00000004
    143 
    144 #define	DBGFLG_FLAGMASK		0x0000000F
    145 #define	DBGFLG_LEVELMASK	~DBGFLG_FLAGMASK
    146 
    147 #define	DEBUG_FLAGS	(md_medup_failure_dbg & DBGFLG_FLAGMASK)
    148 #define	DEBUG_LEVEL	(md_medup_failure_dbg & DBGFLG_LEVELMASK)
    149 
    150 #ifdef JEC
    151 unsigned int md_medup_failure_dbg =	DBGLVL_MINOR | DBGFLG_NONE;
    152 #else	/* ! JEC */
    153 unsigned int md_medup_failure_dbg =	DBGLVL_NONE | DBGFLG_NONE;
    154 #endif	/* JEC */
    155 
    156 #define	DCALL(dbg_level, call)						\
    157 	{								\
    158 		if (DEBUG_LEVEL != DBGLVL_NONE) {			\
    159 			if (DEBUG_FLAGS & DBGFLG_LVLONLY) {		\
    160 				if (DEBUG_LEVEL & dbg_level) {		\
    161 					call;				\
    162 				}					\
    163 			} else {					\
    164 				if (dbg_level <= DEBUG_LEVEL) {		\
    165 					call;				\
    166 				}					\
    167 			}						\
    168 		}							\
    169 	}
    170 
    171 #define	DPRINTF(dbg_level, msg)		DCALL(dbg_level, printf msg)
    172 
    173 #define	MAJOR(msg)			DPRINTF(DBGLVL_MAJOR, msg)
    174 #define	MINOR(msg)			DPRINTF(DBGLVL_MINOR, msg)
    175 #define	MINUTE(msg)			DPRINTF(DBGLVL_MINUTE, msg)
    176 #define	TRIVIA(msg)			DPRINTF(DBGLVL_TRIVIA, msg)
    177 #define	HIDEOUS(msg)			DPRINTF(DBGLVL_HIDEOUS, msg)
    178 #define	BSTAMP				{ uniqtime(&btv); }
    179 
    180 #define	ESTAMP(msg)							\
    181 	{								\
    182 		time_t	esec, eusec;					\
    183 									\
    184 		uniqtime(&etv);						\
    185 									\
    186 		eusec = etv.tv_usec - btv.tv_usec;			\
    187 		esec = etv.tv_sec - btv.tv_sec;				\
    188 		if (eusec < 0) {					\
    189 			eusec += MICROSEC;				\
    190 			esec--;						\
    191 		}							\
    192 		MINOR(("%s: sec=%ld, usec=%ld\n", msg, esec, eusec));	\
    193 	}
    194 
    195 #else	/* ! DEBUG */
    196 
    197 #define	DCALL(ignored_dbg_level, ignored_routine)
    198 #define	MAJOR(ignored)
    199 #define	MINOR(ignored)
    200 #define	MINUTE(ignored)
    201 #define	TRIVIA(ignored)
    202 #define	HIDEOUS(ignored)
    203 #define	BSTAMP		{ }
    204 #define	ESTAMP(msg)	{ }
    205 
    206 #endif /* DEBUG */
    207 
    208 static	int		md_med_protocol_retry = 2;
    209 static	int		md_med_transdevs_set = 0;
    210 
    211 /*
    212  * Definitions and declarations.
    213  */
    214 kmutex_t		med_lck;
    215 
    216 struct med_client {
    217 	rpcprog_t prog;
    218 	rpcvers_t vers;
    219 	struct netbuf addr;	/* Address to this <prog,vers> */
    220 	CLIENT *client;
    221 };
    222 
    223 /*
    224  * unrecoverable RPC status codes; cf. rfscall()
    225  */
    226 #define	MED_IS_UNRECOVERABLE_RPC(s)	(((s) == RPC_AUTHERROR) || \
    227 	((s) == RPC_CANTENCODEARGS) || \
    228 	((s) == RPC_CANTDECODERES) || \
    229 	((s) == RPC_VERSMISMATCH) || \
    230 	((s) == RPC_PROCUNAVAIL) || \
    231 	((s) == RPC_PROGUNAVAIL) || \
    232 	((s) == RPC_PROGVERSMISMATCH) || \
    233 	((s) == RPC_CANTDECODEARGS))
    234 
    235 /*
    236  * When trying to contact a portmapper that doesn't speak the version we're
    237  * using, we should theoretically get back RPC_PROGVERSMISMATCH.
    238  * Unfortunately, some (all?) 4.x hosts return an accept_stat of
    239  * PROG_UNAVAIL, which gets mapped to RPC_PROGUNAVAIL, so we have to check
    240  * for that, too.
    241  */
    242 #define	PMAP_WRONG_VERSION(s)	((s) == RPC_PROGVERSMISMATCH || \
    243 	(s) == RPC_PROGUNAVAIL)
    244 
    245 #define	NULLSTR(str)	(! (str) || *(str) == '\0'? "<null>" : (str))
    246 #define	NULSTRING	""
    247 
    248 /* Flags used in med_addr (netconfig) table */
    249 
    250 #define	UAFLG_NONE		0x00000000
    251 #define	UAFLG_SKIP		0x00000001
    252 #define	UAFLG_ERROR		0x00000002
    253 #define	UAFLG_RPCERROR		0x00000004
    254 #define	UAFLG_LOOPBACK		0x00000008
    255 #define	UAFLG_LOCKINIT		0x00000010
    256 
    257 /*
    258  * most of this data is static.  The mutex protects the changable items:
    259  *	ua_flags
    260  */
    261 static struct med_addr {
    262 	struct knetconfig	ua_kn;
    263 	char			*ua_devname;	/* const */
    264 	char			*ua_netid;	/* const */
    265 	uint_t			ua_flags;
    266 	kmutex_t		ua_mutex;
    267 } med_addr_tab[] =
    268 
    269 /*
    270  * The order of the entries in this table is the order in
    271  * which we'll try to connect to the user-level daemon.
    272  * The final entry must have a NULL ua_devname.
    273  *
    274  * This is basically a tablified version of /etc/netconfig
    275  * (with additional entries for loopback TCP and UDP networks
    276  * that are missing from the user-level version.)
    277  */
    278 {
    279 
    280 /* loopback UDP */
    281 	/* semantics	protofmly	proto,		dev_t */
    282 {	{ NC_TPI_CLTS,	NC_INET,	NC_UDP,		NODEV },
    283 	/* devname	netid		flags */
    284 	"/dev/udp",	"udp-loopback",	UAFLG_LOOPBACK
    285 },
    286 
    287 /* UDP */
    288 	/* semantics	protofmly	proto,		dev_t */
    289 {	{ NC_TPI_CLTS,	NC_INET,	NC_UDP,		NODEV },
    290 	/* devname	netid		flags */
    291 	"/dev/udp",	"udp", 		UAFLG_NONE
    292 },
    293 
    294 /* loopback TCP */
    295 	/* semantics	protofmly	proto,		dev_t */
    296 {	{ NC_TPI_COTS_ORD, NC_INET,	NC_TCP,		NODEV },
    297 	/* devname	netid		flags */
    298 	"/dev/tcp",	"tcp-loopback",	UAFLG_LOOPBACK
    299 },
    300 
    301 /* TCP */
    302 	/* semantics	protofmly	proto,		dev_t */
    303 {	{ NC_TPI_COTS_ORD, NC_INET,	NC_TCP,		NODEV },
    304 	/* devname	netid		flags */
    305 	"/dev/tcp",	"tcp",		UAFLG_NONE
    306 },
    307 
    308 /* ticlts */
    309 	/* semantics	protofmly	proto,		dev_t */
    310 {	{ NC_TPI_CLTS,	NC_LOOPBACK,	NC_NOPROTO,	NODEV },
    311 	/* devname	netid		flags */
    312 	"/dev/ticlts",	"ticlts",	UAFLG_LOOPBACK
    313 },
    314 
    315 /* ticotsord */
    316 	/* semantics	protofmly	proto,		dev_t */
    317 {	{ NC_TPI_COTS_ORD, NC_LOOPBACK,	NC_NOPROTO,	NODEV },
    318 	/* devname	  netid		flags */
    319 	"/dev/ticotsord", "ticotsord",	UAFLG_LOOPBACK
    320 },
    321 
    322 /* ticots */
    323 	/* semantics	protofmly	proto,		dev_t */
    324 {	{ NC_TPI_COTS,	NC_LOOPBACK,	NC_NOPROTO,	NODEV },
    325 	/* devname	netid		flags */
    326 	"/dev/ticots",	"ticots",	UAFLG_LOOPBACK
    327 }
    328 };
    329 
    330 /* The number of entries in the table */
    331 int	med_addr_tab_nents = sizeof (med_addr_tab) / sizeof (med_addr_tab[0]);
    332 
    333 /*
    334  * Private Functions
    335  */
    336 
    337 /* A useful utility. */
    338 static char *
    339 med_dup(void *str, int len)
    340 {
    341 	char *s = (char *)kmem_zalloc(len, KM_SLEEP);
    342 
    343 	if (s == NULL)
    344 		return (NULL);
    345 
    346 	bcopy(str, s, len);
    347 
    348 	return (s);
    349 }
    350 
    351 /*
    352  * Utilities for manipulating netbuf's.
    353  * These utilities are the only knc_protofmly specific functions in the MED.
    354  */
    355 
    356 /*
    357  * Utilities to patch a port number (for NC_INET protocols) or a
    358  *	port name (for NC_LOOPBACK) into a network address.
    359  */
    360 static void
    361 med_put_inet_port(struct netbuf *addr, ushort_t port)
    362 {
    363 	/*
    364 	 * Easy - we always patch an unsigned short on top of an
    365 	 * unsigned short.  No changes to addr's len or maxlen are
    366 	 * necessary.
    367 	 */
    368 	/*LINTED*/
    369 	((struct sockaddr_in *)(addr->buf))->sin_port = port;
    370 }
    371 
    372 static void
    373 med_put_loopback_port(struct netbuf *addr, char *port)
    374 {
    375 	char *dot;
    376 	char *newbuf;
    377 	int newlen;
    378 
    379 	/*
    380 	 * We must make sure the addr has enough space for us,
    381 	 * patch in `port', and then adjust addr's len and maxlen
    382 	 * to reflect the change.
    383 	 */
    384 	if ((dot = strchr(addr->buf, '.')) == (char *)NULL) {
    385 		TRIVIA(("put_loopb_port - malformed loopback addr %s\n",
    386 		    addr->buf));
    387 		return;
    388 	}
    389 
    390 	newlen = (int)((dot - addr->buf + 1) + strlen(port));
    391 	if (newlen > addr->maxlen) {
    392 		newbuf = (char *)kmem_zalloc((size_t)newlen, KM_SLEEP);
    393 		(void) bcopy(addr->buf, newbuf, (size_t)addr->len);
    394 		kmem_free(addr->buf, (size_t)addr->maxlen);
    395 		addr->buf = newbuf;
    396 		addr->len = addr->maxlen = (uint_t)newlen;
    397 		dot = strchr(addr->buf, '.');
    398 	} else {
    399 		addr->len = newlen;
    400 	}
    401 
    402 	(void) strncpy(++dot, port, strlen(port));
    403 
    404 }
    405 
    406 /*
    407  * Make sure the given netbuf has a maxlen at least as big as the given
    408  * length.
    409  */
    410 static void
    411 grow_netbuf(struct netbuf *nb, size_t length)
    412 {
    413 	char *newbuf;
    414 
    415 	if (nb->maxlen >= length)
    416 		return;
    417 
    418 	newbuf = kmem_zalloc(length, KM_SLEEP);
    419 	bcopy(nb->buf, newbuf, (size_t)nb->len);
    420 	kmem_free(nb->buf, (size_t)nb->maxlen);
    421 	nb->buf = newbuf;
    422 	nb->maxlen = (uint_t)length;
    423 }
    424 
    425 /*
    426  * Convert a loopback universal address to a loopback transport address.
    427  */
    428 static void
    429 loopb_u2t(const char *ua, struct netbuf *addr)
    430 {
    431 	size_t stringlen = strlen(ua) + 1;
    432 	const char *univp;		/* ptr into universal addr */
    433 	char *transp;			/* ptr into transport addr */
    434 
    435 	/* Make sure the netbuf will be big enough. */
    436 	if (addr->maxlen < stringlen) {
    437 		grow_netbuf(addr, stringlen);
    438 	}
    439 
    440 	univp = ua;
    441 	transp = addr->buf;
    442 	while (*univp != NULL) {
    443 		if (*univp == '\\' && *(univp+1) == '\\') {
    444 			*transp = '\\';
    445 			univp += 2;
    446 		} else if (*univp == '\\') {
    447 			/* octal character */
    448 			*transp = (((*(univp+1) - '0') & 3) << 6) +
    449 			    (((*(univp+2) - '0') & 7) << 3) +
    450 			    ((*(univp+3) - '0') & 7);
    451 			univp += 4;
    452 		} else {
    453 			*transp = *univp;
    454 			univp++;
    455 		}
    456 		transp++;
    457 	}
    458 
    459 	addr->len = (uint_t)(transp - addr->buf);
    460 	ASSERT(addr->len <= addr->maxlen);
    461 }
    462 
    463 
    464 /*
    465  * xdr_md_pmap
    466  *
    467  * Taken from libnsl/rpc/pmap_prot.c
    468  */
    469 bool_t
    470 xdr_md_pmap(xdrs, regs)
    471 	XDR *xdrs;
    472 	struct pmap *regs;
    473 {
    474 	if (xdr_u_int(xdrs, &regs->pm_prog) &&
    475 		xdr_u_int(xdrs, &regs->pm_vers) &&
    476 		xdr_u_int(xdrs, &regs->pm_prot))
    477 		return (xdr_u_int(xdrs, &regs->pm_port));
    478 	return (FALSE);
    479 }
    480 
    481 /*
    482  * We need an version of CLNT_DESTROY which also frees the auth structure.
    483  */
    484 static void
    485 med_clnt_destroy(CLIENT **clp)
    486 {
    487 	if (*clp) {
    488 		if ((*clp)->cl_auth) {
    489 			AUTH_DESTROY((*clp)->cl_auth);
    490 			(*clp)->cl_auth = NULL;
    491 		}
    492 		CLNT_DESTROY(*clp);
    493 		*clp = NULL;
    494 	}
    495 }
    496 
    497 /*
    498  * Release this med_client entry.
    499  * Do also destroy the entry if there was an error != EINTR,
    500  * and mark the entry as not-valid, by setting time=0.
    501  */
    502 static void
    503 med_rel_client(struct med_client *medc, int error)
    504 {
    505 	TRIVIA(("rel_client - addr = (%p, %u %u)\n",
    506 	    (void *) medc->addr.buf, medc->addr.len, medc->addr.maxlen));
    507 	/*LINTED*/
    508 	if (1 || error && error != EINTR) {
    509 		TRIVIA(("rel_client - destroying addr = (%p, %u %u)\n",
    510 		    (void *) medc->addr.buf, medc->addr.len,
    511 		    medc->addr.maxlen));
    512 		med_clnt_destroy(&medc->client);
    513 		if (medc->addr.buf) {
    514 			kmem_free(medc->addr.buf, medc->addr.maxlen);
    515 			medc->addr.buf = NULL;
    516 		}
    517 	}
    518 }
    519 
    520 /*
    521  * Try to get the address for the desired service by using the old
    522  * portmapper protocol.  Ignores signals.
    523  *
    524  * Returns RPC_UNKNOWNPROTO if the request uses the loopback transport.
    525  * Use med_get_rpcb_addr instead.
    526  */
    527 static enum clnt_stat
    528 med_get_pmap_addr(
    529 	struct	knetconfig	*kncfp,
    530 	rpcprog_t		prog,
    531 	rpcvers_t		vers,
    532 	struct	netbuf		*addr
    533 )
    534 {
    535 	ushort_t			port = 0;
    536 	int			error;
    537 	enum	clnt_stat	status;
    538 	CLIENT			*client = NULL;
    539 	struct	pmap		parms;
    540 	struct	timeval		tmo;
    541 	k_sigset_t		oldmask;
    542 	k_sigset_t		newmask;
    543 
    544 	/*
    545 	 * Call rpcbind version 2 or earlier (SunOS portmapper, remote
    546 	 * only) to get an address we can use in an RPC client handle.
    547 	 * We simply obtain a port no. for <prog, vers> and plug it
    548 	 * into `addr'.
    549 	 */
    550 	if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
    551 		med_put_inet_port(addr, htons(PMAPPORT));
    552 	} else {
    553 		TRIVIA(("get_pmap_addr - unsupported protofmly %s\n",
    554 		    kncfp->knc_protofmly));
    555 		status = RPC_UNKNOWNPROTO;
    556 		goto out;
    557 	}
    558 
    559 	TRIVIA(("get_pmap_addr - semantics=%u, protofmly=%s, proto=%s\n",
    560 	    kncfp->knc_semantics, kncfp->knc_protofmly, kncfp->knc_proto));
    561 
    562 	/*
    563 	 * Mask signals for the duration of the handle creation and
    564 	 * RPC call.  This allows relatively normal operation with a
    565 	 * signal already posted to our thread.
    566 	 *
    567 	 * Any further exit paths from this routine must restore
    568 	 * the original signal mask.
    569 	 */
    570 	sigfillset(&newmask);
    571 	sigreplace(&newmask, &oldmask);
    572 
    573 	if ((error = clnt_tli_kcreate(kncfp, addr, PMAPPROG, PMAPVERS,
    574 	    0, 0, kcred, &client)) != RPC_SUCCESS) {
    575 		status = RPC_TLIERROR;
    576 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    577 		MINUTE(("get_pmap_addr - kcreate() returned %d\n", error));
    578 		goto out;
    579 	}
    580 
    581 	if (!CLNT_CONTROL(client, CLSET_NODELAYONERR, (char *)&clset)) {
    582 		MINUTE(("get_pmap_addr - unable to set CLSET_NODELAYONERR\n"));
    583 	}
    584 
    585 	client->cl_auth = authkern_create();
    586 
    587 	parms.pm_prog = prog;
    588 	parms.pm_vers = vers;
    589 	if (strcmp(kncfp->knc_proto, NC_TCP) == 0) {
    590 		parms.pm_prot = IPPROTO_TCP;
    591 	} else {
    592 		parms.pm_prot = IPPROTO_UDP;
    593 	}
    594 	parms.pm_port = 0;
    595 	tmo = md_med_pmap_timeout;
    596 
    597 	if ((status = CLNT_CALL(client, PMAPPROC_GETPORT,
    598 	    xdr_md_pmap, (char *)&parms,
    599 	    xdr_u_short, (char *)&port,
    600 	    tmo)) != RPC_SUCCESS) {
    601 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    602 		MINUTE(("get_pmap_addr - CLNT_CALL(GETPORT) returned %d\n",
    603 		    status));
    604 		goto out;
    605 	}
    606 
    607 	sigreplace(&oldmask, (k_sigset_t *)NULL);
    608 
    609 	/* A zero value of port indicates a mapping failure */
    610 	if (port == 0) {
    611 		status = RPC_PROGNOTREGISTERED;
    612 		MINUTE(("get_pmap_addr - program not registered\n"));
    613 		goto out;
    614 	}
    615 
    616 	TRIVIA(("get_pmap_addr - port=%d\n", port));
    617 	med_put_inet_port(addr, ntohs(port));
    618 
    619 out:
    620 	if (client)
    621 		med_clnt_destroy(&client);
    622 	return (status);
    623 }
    624 
    625 /*
    626  * Try to get the address for the desired service by using the rpcbind
    627  * protocol.  Ignores signals.
    628  */
    629 static enum clnt_stat
    630 med_get_rpcb_addr(
    631 	struct	knetconfig	*kncfp,
    632 	rpcprog_t		prog,
    633 	rpcvers_t		vers,
    634 	struct	netbuf		 *addr
    635 )
    636 {
    637 	int			error;
    638 	char			*ua = NULL;
    639 	enum	clnt_stat	status;
    640 	RPCB			parms;
    641 	struct	timeval		tmo;
    642 	CLIENT			*client = NULL;
    643 	k_sigset_t		oldmask;
    644 	k_sigset_t		newmask;
    645 	ushort_t			port;
    646 
    647 	/*
    648 	 * Call rpcbind (local or remote) to get an address we can use
    649 	 * in an RPC client handle.
    650 	 */
    651 	tmo = md_med_pmap_timeout;
    652 	parms.r_prog = prog;
    653 	parms.r_vers = vers;
    654 	parms.r_addr = parms.r_owner = "";
    655 
    656 	if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
    657 		if (strcmp(kncfp->knc_proto, NC_TCP) == 0) {
    658 			parms.r_netid = "tcp";
    659 		} else {
    660 			parms.r_netid = "udp";
    661 		}
    662 		med_put_inet_port(addr, htons(PMAPPORT));
    663 	} else if (strcmp(kncfp->knc_protofmly, NC_LOOPBACK) == 0) {
    664 		parms.r_netid = "ticlts";
    665 		med_put_loopback_port(addr, "rpc");
    666 		TRIVIA((
    667 		    "get_rpcb_addr - semantics=%s, protofmly=%s, proto=%s\n",
    668 		    (kncfp->knc_semantics == NC_TPI_CLTS ?
    669 		    "NC_TPI_CLTS" : "?"),
    670 		    kncfp->knc_protofmly, kncfp->knc_proto));
    671 	} else {
    672 		TRIVIA(("get_rpcb_addr - unsupported protofmly %s\n",
    673 		    kncfp->knc_protofmly));
    674 		status = RPC_UNKNOWNPROTO;
    675 		goto out;
    676 	}
    677 
    678 	/*
    679 	 * Mask signals for the duration of the handle creation and
    680 	 * RPC calls.  This allows relatively normal operation with a
    681 	 * signal already posted to our thread.
    682 	 *
    683 	 * Any further exit paths from this routine must restore
    684 	 * the original signal mask.
    685 	 */
    686 	sigfillset(&newmask);
    687 	sigreplace(&newmask, &oldmask);
    688 
    689 	if ((error = clnt_tli_kcreate(kncfp, addr, RPCBPROG, RPCBVERS,
    690 	    0, 0, kcred, &client)) != 0) {
    691 		status = RPC_TLIERROR;
    692 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    693 		MINUTE(("get_rpcb_addr - kcreate() returned %d\n", error));
    694 		goto out;
    695 	}
    696 
    697 	if (!CLNT_CONTROL(client, CLSET_NODELAYONERR, (char *)&clset)) {
    698 		MINUTE(("get_rpcb_addr - unable to set CLSET_NODELAYONERR\n"));
    699 	}
    700 
    701 	client->cl_auth = authkern_create();
    702 
    703 	if ((status = CLNT_CALL(client, RPCBPROC_GETADDR,
    704 	    xdr_rpcb, (char *)&parms, xdr_wrapstring, (char *)&ua,
    705 	    tmo)) != RPC_SUCCESS) {
    706 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    707 		MINUTE(("get_rpcb_addr - CLNT_CALL(GETADDR) returned %d\n",
    708 		    status));
    709 		goto out;
    710 	}
    711 
    712 	sigreplace(&oldmask, (k_sigset_t *)NULL);
    713 
    714 	if (ua == NULL || *ua == NULL) {
    715 		status = RPC_PROGNOTREGISTERED;
    716 		MINUTE(("get_rpcb_addr - program not registered\n"));
    717 		goto out;
    718 	}
    719 
    720 	/*
    721 	 * Convert the universal address to the transport address.
    722 	 * Theoretically, we should call the local rpcbind to translate
    723 	 * from the universal address to the transport address, but it gets
    724 	 * complicated (e.g., there's no direct way to tell rpcbind that we
    725 	 * want an IP address instead of a loopback address).  Note that
    726 	 * the transport address is potentially host-specific, so we can't
    727 	 * just ask the remote rpcbind, because it might give us the wrong
    728 	 * answer.
    729 	 */
    730 	if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
    731 		port = rpc_uaddr2port(AF_INET, ua);
    732 		med_put_inet_port(addr, ntohs(port));
    733 	} else if (strcmp(kncfp->knc_protofmly, NC_LOOPBACK) == 0) {
    734 		loopb_u2t(ua, addr);
    735 	} else {
    736 		/* "can't happen" - should have been checked for above */
    737 		cmn_err(CE_PANIC, "med_get_rpcb_addr: bad protocol family");
    738 	}
    739 
    740 out:
    741 	if (client != NULL)
    742 		med_clnt_destroy(&client);
    743 	if (ua != NULL)
    744 		xdr_free(xdr_wrapstring, (char *)&ua);
    745 	return (status);
    746 }
    747 
    748 /*
    749  * Get the RPC client handle to talk to the service at addrp.
    750  * Returns:
    751  * RPC_SUCCESS		Success.
    752  * RPC_RPCBFAILURE	Couldn't talk to the remote portmapper (e.g.,
    753  * 			timeouts).
    754  * RPC_INTR		Caught a signal before we could successfully return.
    755  * RPC_TLIERROR		Couldn't initialize the handle after talking to the
    756  * 			remote portmapper (shouldn't happen).
    757  */
    758 static enum clnt_stat
    759 med_get_rpc_handle(
    760 	struct	knetconfig	*kncfp,
    761 	struct	netbuf		*addrp,
    762 	rpcprog_t		prog,
    763 	rpcvers_t		vers,
    764 	CLIENT			**clientp
    765 )
    766 {
    767 	enum	clnt_stat	status;
    768 	k_sigset_t		oldmask;
    769 	k_sigset_t		newmask;
    770 	int			error;
    771 
    772 	/*
    773 	 * Try to get the address from either portmapper or rpcbind.
    774 	 * We check for posted signals after trying and failing to
    775 	 * contact the portmapper since it can take uncomfortably
    776 	 * long for this entire procedure to time out.
    777 	 */
    778 	BSTAMP
    779 	status = med_get_pmap_addr(kncfp, prog, vers, addrp);
    780 	if (MED_IS_UNRECOVERABLE_RPC(status) && status != RPC_UNKNOWNPROTO &&
    781 	    ! PMAP_WRONG_VERSION(status)) {
    782 		status = RPC_RPCBFAILURE;
    783 		goto bailout;
    784 	}
    785 
    786 	if (status == RPC_SUCCESS)
    787 		ESTAMP("done OK med_get_pmap_addr")
    788 	else
    789 		ESTAMP("done Not OK med_get_pmap_addr")
    790 
    791 	if (status != RPC_SUCCESS) {
    792 		BSTAMP
    793 		status = med_get_rpcb_addr(kncfp, prog, vers, addrp);
    794 		if (status != RPC_SUCCESS) {
    795 			ESTAMP("done Not OK med_get_rpcb_addr")
    796 			MINOR((
    797 		    "get_rpc_handle - can't contact portmapper or rpcbind\n"));
    798 			status = RPC_RPCBFAILURE;
    799 			goto bailout;
    800 		}
    801 	}
    802 	ESTAMP("done OK med_get_rpcb_addr")
    803 
    804 	med_clnt_destroy(clientp);
    805 
    806 	/*
    807 	 * Mask signals for the duration of the handle creation,
    808 	 * allowing relatively normal operation with a signal
    809 	 * already posted to our thread.
    810 	 *
    811 	 * Any further exit paths from this routine must restore
    812 	 * the original signal mask.
    813 	 */
    814 	sigfillset(&newmask);
    815 	sigreplace(&newmask, &oldmask);
    816 
    817 	if ((error = clnt_tli_kcreate(kncfp, addrp, prog, vers,
    818 	    0, 0, kcred, clientp)) != 0) {
    819 		status = RPC_TLIERROR;
    820 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    821 		MINUTE(("get_rpc_handle - kcreate(prog) returned %d\n", error));
    822 		goto bailout;
    823 	}
    824 
    825 	if (!CLNT_CONTROL(*clientp, CLSET_NODELAYONERR, (char *)&clset)) {
    826 		MINUTE(("get_rpc_handle - unable to set CLSET_NODELAYONERR\n"));
    827 	}
    828 
    829 	(*clientp)->cl_auth = authkern_create();
    830 
    831 	sigreplace(&oldmask, (k_sigset_t *)NULL);
    832 
    833 bailout:
    834 	return (status);
    835 }
    836 
    837 /*
    838  * Return a med_client to the <prog,vers>.
    839  * The med_client found is marked as in_use.
    840  * It is the responsibility of the caller to release the med_client by
    841  * calling med_rel_client().
    842  *
    843  * Returns:
    844  * RPC_SUCCESS		Success.
    845  * RPC_CANTSEND		Temporarily cannot send.
    846  * RPC_TLIERROR		Unspecified TLI error.
    847  * RPC_UNKNOWNPROTO	kncfp is from an unrecognised protocol family.
    848  * RPC_PROGNOTREGISTERED The prog `prog' isn't registered on the server.
    849  * RPC_RPCBFAILURE	Couldn't contact portmapper on remote host.
    850  * Any unsuccessful return codes from CLNT_CALL().
    851  */
    852 static enum clnt_stat
    853 med_get_client(
    854 	struct	knetconfig	*kncfp,
    855 	struct	netbuf		*addrp,
    856 	rpcprog_t		prog,
    857 	rpcvers_t		vers,
    858 	struct	med_client	**mcp
    859 )
    860 {
    861 	struct	med_client	*med_clnt = NULL;
    862 	enum	clnt_stat	status = RPC_SUCCESS;
    863 
    864 	mutex_enter(&med_lck);
    865 
    866 	/*
    867 	 * Create an med_client
    868 	 */
    869 	med_clnt = kmem_zalloc(sizeof (*med_clnt), KM_SLEEP);
    870 	med_clnt->client = NULL;
    871 	med_clnt->prog = prog;
    872 	med_clnt->vers = vers;
    873 	med_clnt->addr.buf = med_dup(addrp->buf, addrp->maxlen);
    874 	med_clnt->addr.len = addrp->len;
    875 	med_clnt->addr.maxlen = addrp->maxlen;
    876 
    877 	mutex_exit(&med_lck);
    878 
    879 	status = med_get_rpc_handle(kncfp, &med_clnt->addr, prog, vers,
    880 	    &med_clnt->client);
    881 
    882 out:
    883 	TRIVIA(("get_client - End: med_clnt=%p status=%d, client=%p\n",
    884 	    (void *)med_clnt, status,
    885 	    (med_clnt ? med_clnt->client : (void *) -1L)));
    886 
    887 	if (status == RPC_SUCCESS) {
    888 		*mcp = med_clnt;
    889 	} else {
    890 		/* Cleanup */
    891 		if (med_clnt) {
    892 			mutex_enter(&med_lck);
    893 			med_rel_client(med_clnt, EINVAL);
    894 			kmem_free(med_clnt, sizeof (*med_clnt));
    895 			mutex_exit(&med_lck);
    896 		}
    897 		*mcp = NULL;
    898 	}
    899 
    900 	return (status);
    901 }
    902 
    903 /*
    904  * Make an RPC call to addr via config.
    905  *
    906  * Returns:
    907  * 0		Success.
    908  * EIO		Couldn't get client handle, timed out, or got unexpected
    909  *		RPC status within md_med_protocol_retry attempts.
    910  * EINVAL	Unrecoverable error in RPC call.  Causes client handle
    911  *		to be destroyed.
    912  * EINTR	RPC call was interrupted within md_med_protocol_retry attempts.
    913  */
    914 static int
    915 med_callrpc(
    916 	struct	knetconfig	*kncfp,
    917 	struct	netbuf		*addrp,
    918 	rpcprog_t		prog,
    919 	rpcvers_t		vers,
    920 	rpcproc_t		proc,
    921 	xdrproc_t		inproc,
    922 	caddr_t			in,
    923 	xdrproc_t		outproc,
    924 	caddr_t			out,
    925 	struct	timeval		*timout
    926 )
    927 {
    928 	struct	med_client	*med_clnt = NULL;
    929 	enum	clnt_stat	cl_stat;
    930 	int			tries = md_med_protocol_retry;
    931 	int			error;
    932 	k_sigset_t		oldmask;
    933 	k_sigset_t		newmask;
    934 
    935 	MINUTE(("med_callrpc - Calling [%u, %u, %u]\n", prog, vers, proc));
    936 
    937 	sigfillset(&newmask);
    938 
    939 	while (tries--) {
    940 		error = 0;
    941 		cl_stat = med_get_client(kncfp, addrp, prog, vers, &med_clnt);
    942 		if (MED_IS_UNRECOVERABLE_RPC(cl_stat)) {
    943 			error = EINVAL;
    944 			goto rel_client;
    945 		} else if (cl_stat != RPC_SUCCESS) {
    946 			error = EIO;
    947 			continue;
    948 		}
    949 
    950 		ASSERT(med_clnt != NULL);
    951 		ASSERT(med_clnt->client != NULL);
    952 
    953 		sigreplace(&newmask, &oldmask);
    954 		cl_stat = CLNT_CALL(med_clnt->client, proc, inproc, in,
    955 		    outproc, out, *timout);
    956 		sigreplace(&oldmask, (k_sigset_t *)NULL);
    957 
    958 		switch (cl_stat) {
    959 		case RPC_SUCCESS:
    960 			/*
    961 			 * Update the timestamp on the client cache entry.
    962 			 */
    963 			error = 0;
    964 			break;
    965 
    966 		case RPC_TIMEDOUT:
    967 			MINOR(("med_callrpc - RPC_TIMEDOUT\n"));
    968 			if (timout == 0) {
    969 				/*
    970 				 * We will always time out when timout == 0.
    971 				 */
    972 				error = 0;
    973 				break;
    974 			}
    975 			/* FALLTHROUGH */
    976 		case RPC_CANTSEND:
    977 		case RPC_XPRTFAILED:
    978 		default:
    979 			if (MED_IS_UNRECOVERABLE_RPC(cl_stat)) {
    980 				error = EINVAL;
    981 			} else {
    982 				error = EIO;
    983 			}
    984 		}
    985 
    986 rel_client:
    987 		MINOR(("med_callrpc - RPC cl_stat=%d error=%d\n",
    988 		    cl_stat, error));
    989 		if (med_clnt != NULL) {
    990 			med_rel_client(med_clnt, error);
    991 			kmem_free(med_clnt, sizeof (*med_clnt));
    992 		}
    993 
    994 		/*
    995 		 * If EIO, loop else we're done.
    996 		 */
    997 		if (error != EIO) {
    998 			break;
    999 		}
   1000 	}
   1001 
   1002 	MINUTE(("med_callrpc - End: error=%d, tries=%d\n", error, tries));
   1003 
   1004 	return (error);
   1005 }
   1006 
   1007 /*
   1008  * Try various transports to get the rpc call through.
   1009  */
   1010 static int
   1011 med_net_callrpc(
   1012 	char			*h_nm,
   1013 	in_addr_t		h_ip,
   1014 	uint_t			h_flags,
   1015 	rpcprog_t		prog,
   1016 	rpcvers_t		vers,
   1017 	rpcproc_t		proc,
   1018 	xdrproc_t		inproc,
   1019 	caddr_t			in,
   1020 	xdrproc_t		outproc,
   1021 	caddr_t			out,
   1022 	struct	timeval		*timout
   1023 )
   1024 {
   1025 	int			err;
   1026 	struct	med_addr	*uap;
   1027 	int			uapi;
   1028 	struct	netbuf		dst;
   1029 	int			done = 0;
   1030 
   1031 	ASSERT(h_nm != NULL);
   1032 	ASSERT(h_ip != 0);
   1033 
   1034 	/*
   1035 	 * Loop through our table of transports and try to get the data out.
   1036 	 */
   1037 	for (uapi = 0; uapi < med_addr_tab_nents && ! done; uapi++) {
   1038 
   1039 		/* Shorthand */
   1040 		uap = &med_addr_tab[uapi];
   1041 
   1042 		/*
   1043 		 * UAFLG_SKIP is used for debugging and by the protocol
   1044 		 * selection code.
   1045 		 */
   1046 		if (uap->ua_flags & UAFLG_SKIP) {
   1047 			MINUTE(("med_net_callrpc - %s - marked \"skip\"\n",
   1048 			    uap->ua_netid));
   1049 			continue;
   1050 		}
   1051 
   1052 		/*
   1053 		 * If we are not talking to this host, we can skip all LOOPBACK
   1054 		 * transport options.
   1055 		 */
   1056 		if (! (h_flags & NMIP_F_LOCAL) &&
   1057 		    (uap->ua_flags & UAFLG_LOOPBACK))
   1058 			continue;
   1059 
   1060 		if (uap->ua_flags & UAFLG_ERROR)
   1061 			continue;
   1062 
   1063 		if (uap->ua_flags & UAFLG_RPCERROR)
   1064 			continue;
   1065 
   1066 		/* Unknown protocol, skip it */
   1067 		if (! uap->ua_kn.knc_protofmly) {
   1068 			MINUTE(("med_net_callrpc - bad protofmly\n"));
   1069 			continue;
   1070 		}
   1071 
   1072 		if (strcmp(uap->ua_kn.knc_protofmly, NC_LOOPBACK) == 0) {
   1073 			size_t	alen = strlen(utsname.nodename) + 1 + 1;
   1074 
   1075 			dst.buf = kmem_zalloc(alen, KM_SLEEP);
   1076 			dst.maxlen = (uint_t)alen;
   1077 
   1078 			(void) strcpy(dst.buf, utsname.nodename);
   1079 			(void) strcat(dst.buf, ".");
   1080 
   1081 		} else if (strcmp(uap->ua_kn.knc_protofmly, NC_INET) == 0) {
   1082 			struct sockaddr_in	*s;
   1083 
   1084 			/*
   1085 			 * If we have not allocated a buffer for an INET addrs
   1086 			 * or the buffer allocated will not contain an INET
   1087 			 * addr, allocate or re-allocate.
   1088 			 */
   1089 			dst.buf = kmem_zalloc(sizeof (struct sockaddr_in),
   1090 			    KM_SLEEP);
   1091 			dst.maxlen = sizeof (struct sockaddr_in);
   1092 
   1093 			/* Short hand */
   1094 			/*LINTED*/
   1095 			s = (struct sockaddr_in *)dst.buf;
   1096 
   1097 			/* Initialize the socket */
   1098 			if (uap->ua_flags & UAFLG_LOOPBACK)
   1099 				s->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   1100 			else
   1101 				s->sin_addr.s_addr = h_ip;
   1102 			s->sin_port = 0;
   1103 			s->sin_family = AF_INET;
   1104 		}
   1105 
   1106 		dst.len = dst.maxlen;
   1107 
   1108 		MINOR(("med_net_callrpc - Trying %s\n", uap->ua_netid));
   1109 
   1110 		err = med_callrpc(&uap->ua_kn, &dst, prog, vers, proc, inproc,
   1111 		    in, outproc, out, timout);
   1112 
   1113 		if (dst.buf) {
   1114 			kmem_free(dst.buf, dst.maxlen);
   1115 			dst.buf = NULL;
   1116 			dst.len = 0;
   1117 			dst.maxlen = 0;
   1118 		}
   1119 
   1120 		if (err) {
   1121 			MINUTE(("med_net_callrpc - %s failed\n\n",
   1122 			    uap->ua_netid));
   1123 			continue;
   1124 		}
   1125 
   1126 		MINUTE(("med_net_callrpc - %s OK\n\n", uap->ua_netid));
   1127 		done = 1;
   1128 	}
   1129 
   1130 	/*
   1131 	 * Print a message if we could not reach a host.
   1132 	 */
   1133 	if (! done) {
   1134 		cmn_err(CE_WARN, "%s on host %s not responding", MED_SERVNAME,
   1135 		    h_nm);
   1136 		return (1);
   1137 	}
   1138 
   1139 	return (0);
   1140 }
   1141 
   1142 /*
   1143  * Validate the mediator data
   1144  */
   1145 static int
   1146 med_ok(set_t setno, med_data_t *meddp)
   1147 {
   1148 	/* Not initialized, or not a mediator data record */
   1149 	if (meddp->med_dat_mag != MED_DATA_MAGIC)
   1150 		goto fail;
   1151 
   1152 	MINUTE(("Magic OK\n"));
   1153 
   1154 	/* Mismatch in revisions */
   1155 	if (meddp->med_dat_rev != MED_DATA_REV)
   1156 		goto fail;
   1157 
   1158 	MINUTE(("Revision OK\n"));
   1159 
   1160 	/* Not for the right set, this is paranoid */
   1161 	if (setno != meddp->med_dat_sn)
   1162 		goto fail;
   1163 
   1164 	MINUTE(("Setno OK\n"));
   1165 
   1166 	/* The record checksum is not correct */
   1167 	if (crcchk(meddp, &meddp->med_dat_cks, sizeof (med_data_t), NULL))
   1168 		goto fail;
   1169 
   1170 	MINUTE(("Mediator validated\n"));
   1171 
   1172 	return (1);
   1173 
   1174 fail:
   1175 	return (0);
   1176 }
   1177 
   1178 static void
   1179 med_adl(med_data_lst_t **meddlpp, med_data_t *meddp)
   1180 {
   1181 	/*
   1182 	 * Run to the end of the list
   1183 	 */
   1184 	for (/* void */; (*meddlpp != NULL); meddlpp = &(*meddlpp)->mdl_nx)
   1185 		/* void */;
   1186 
   1187 	*meddlpp = (med_data_lst_t *)kmem_zalloc(sizeof (med_data_lst_t),
   1188 	    KM_SLEEP);
   1189 
   1190 	(*meddlpp)->mdl_med = (med_data_t *)med_dup(meddp, sizeof (med_data_t));
   1191 }
   1192 
   1193 static void
   1194 mtaa_upd_init(med_thr_a_args_t *mtaap, med_thr_h_args_t *mthap)
   1195 {
   1196 	med_upd_data_args_t	*argsp;
   1197 	med_err_t		*resp;
   1198 
   1199 	argsp = kmem_zalloc(sizeof (med_upd_data_args_t), KM_SLEEP);
   1200 	argsp->med.med_setno = mthap->mtha_setno;
   1201 	if (MD_MNSET_SETNO(argsp->med.med_setno)) {
   1202 		/*
   1203 		 * In MN diskset, use a generic nodename, multiowner, in the
   1204 		 * mediator record which allows any node to access mediator
   1205 		 * information.  MN diskset reconfig cycle forces consistent
   1206 		 * view of set/node/drive/mediator information across all nodes
   1207 		 * in the MN diskset.  This allows the relaxation of
   1208 		 * node name checking in rpc.metamedd for MN disksets.
   1209 		 */
   1210 		argsp->med.med_caller = md_strdup(MED_MN_CALLER);
   1211 	} else {
   1212 		argsp->med.med_caller = md_strdup(utsname.nodename);
   1213 	}
   1214 	argsp->med.med_setname = md_strdup(mthap->mtha_setname);
   1215 	argsp->med_data = *mthap->mtha_meddp;
   1216 
   1217 	resp = kmem_zalloc(sizeof (med_err_t), KM_SLEEP);
   1218 
   1219 	mtaap->mtaa_mag = MTAA_MAGIC;
   1220 	mtaap->mtaa_mthap = mthap;
   1221 	mtaap->mtaa_prog = MED_PROG;
   1222 	mtaap->mtaa_vers = MED_VERS;
   1223 	mtaap->mtaa_proc = MED_UPD_DATA;
   1224 	mtaap->mtaa_inproc = xdr_med_upd_data_args_t;
   1225 	mtaap->mtaa_in = (caddr_t)argsp;
   1226 	mtaap->mtaa_outproc = xdr_med_err_t;
   1227 	mtaap->mtaa_out = (caddr_t)resp;
   1228 	mtaap->mtaa_timout = (struct timeval *)&md_med_def_timeout;
   1229 }
   1230 
   1231 static void
   1232 mtaa_upd_free(med_thr_a_args_t *mtaap)
   1233 {
   1234 	med_upd_data_args_t	*argsp = (med_upd_data_args_t *)mtaap->mtaa_in;
   1235 	med_err_t		*resp = (med_err_t *)mtaap->mtaa_out;
   1236 
   1237 	freestr(argsp->med.med_caller);
   1238 	freestr(argsp->med.med_setname);
   1239 	kmem_free(argsp, sizeof (med_upd_data_args_t));
   1240 
   1241 	if (mtaap->mtaa_flags & MDT_A_OK)
   1242 		xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
   1243 
   1244 	kmem_free(resp, sizeof (med_err_t));
   1245 }
   1246 
   1247 static int
   1248 mtaa_upd_err(med_thr_a_args_t *mtaap)
   1249 {
   1250 	/*LINTED*/
   1251 	med_err_t		*resp = (med_err_t *)mtaap->mtaa_out;
   1252 
   1253 	if (resp->med_errno == MDE_MED_NOERROR) {
   1254 		MAJOR(("upd_med_hosts - %s - OK\n\n", mtaap->mtaa_h_nm));
   1255 		return (0);
   1256 	} else {
   1257 		MAJOR(("upd_med_hosts - %s - errno=%d\n\n", mtaap->mtaa_h_nm,
   1258 		    resp->med_errno));
   1259 		return (1);
   1260 	}
   1261 }
   1262 
   1263 static void
   1264 mtaa_get_init(med_thr_a_args_t *mtaap, med_thr_h_args_t *mthap)
   1265 {
   1266 	med_args_t		*argsp;
   1267 	med_get_data_res_t	*resp;
   1268 
   1269 	argsp = kmem_zalloc(sizeof (med_args_t), KM_SLEEP);
   1270 	argsp->med.med_setno = mthap->mtha_setno;
   1271 	if (MD_MNSET_SETNO(argsp->med.med_setno)) {
   1272 		/*
   1273 		 * In MN diskset, use a generic nodename, multiowner, in the
   1274 		 * mediator record which allows any node to access mediator
   1275 		 * information.  MN diskset reconfig cycle forces consistent
   1276 		 * view of set/node/drive/mediator information across all nodes
   1277 		 * in the MN diskset.  This allows the relaxation of
   1278 		 * node name checking in rpc.metamedd for MN disksets.
   1279 		 */
   1280 		argsp->med.med_caller = md_strdup(MED_MN_CALLER);
   1281 	} else {
   1282 		argsp->med.med_caller = md_strdup(utsname.nodename);
   1283 	}
   1284 
   1285 	argsp->med.med_setname = md_strdup(mthap->mtha_setname);
   1286 
   1287 	resp = kmem_zalloc(sizeof (med_get_data_res_t), KM_SLEEP);
   1288 
   1289 	mtaap->mtaa_mag = MTAA_MAGIC;
   1290 	mtaap->mtaa_mthap = mthap;
   1291 	mtaap->mtaa_prog = MED_PROG;
   1292 	mtaap->mtaa_vers = MED_VERS;
   1293 	mtaap->mtaa_proc = MED_GET_DATA;
   1294 	mtaap->mtaa_inproc = xdr_med_args_t;
   1295 	mtaap->mtaa_in = (caddr_t)argsp;
   1296 	mtaap->mtaa_outproc = xdr_med_get_data_res_t;
   1297 	mtaap->mtaa_out = (caddr_t)resp;
   1298 	mtaap->mtaa_timout = (struct timeval *)&md_med_def_timeout;
   1299 }
   1300 
   1301 static void
   1302 mtaa_get_free(med_thr_a_args_t *mtaap)
   1303 {
   1304 	/*LINTED*/
   1305 	med_args_t		*argsp = (med_args_t *)mtaap->mtaa_in;
   1306 	/*LINTED*/
   1307 	med_get_data_res_t	*resp = (med_get_data_res_t *)mtaap->mtaa_out;
   1308 
   1309 	freestr(argsp->med.med_caller);
   1310 	freestr(argsp->med.med_setname);
   1311 	kmem_free(argsp, sizeof (med_args_t));
   1312 
   1313 	if (mtaap->mtaa_flags & MDT_A_OK)
   1314 		xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
   1315 
   1316 	kmem_free(resp, sizeof (med_get_data_res_t));
   1317 }
   1318 
   1319 static int
   1320 mtaa_get_err(med_thr_a_args_t *mtaap)
   1321 {
   1322 	/*LINTED*/
   1323 	med_get_data_res_t	*resp = (med_get_data_res_t *)mtaap->mtaa_out;
   1324 
   1325 	if (resp->med_status.med_errno == MDE_MED_NOERROR) {
   1326 		MAJOR(("get_med_host_data - %s - OK\n\n", mtaap->mtaa_h_nm));
   1327 		return (0);
   1328 	} else {
   1329 		MAJOR(("get_med_host_data - %s - errno=%d\n\n",
   1330 		    mtaap->mtaa_h_nm, resp->med_status.med_errno));
   1331 		return (1);
   1332 	}
   1333 }
   1334 
   1335 static void
   1336 mtha_init(
   1337 	med_thr_t		*mtp,
   1338 	med_thr_h_args_t	*mthap,
   1339 	md_hi_t			*mhp,
   1340 	char			*setname,
   1341 	med_data_t		*meddp,
   1342 	set_t			setno,
   1343 	void			(*mtaa_init_func)(med_thr_a_args_t *,
   1344 				    med_thr_h_args_t *),
   1345 	int			(*mtaa_err_func)(med_thr_a_args_t *)
   1346 )
   1347 {
   1348 	int		j;
   1349 
   1350 	mthap->mtha_mag		= MTHA_MAGIC;
   1351 	mthap->mtha_mtp 	= mtp;
   1352 	mthap->mtha_mhp 	= mhp;
   1353 	mthap->mtha_setname	= md_strdup(setname);
   1354 	if (meddp)
   1355 		mthap->mtha_meddp	= meddp;
   1356 	else
   1357 		mthap->mtha_meddp	= NULL;
   1358 	mthap->mtha_setno 	= setno;
   1359 	mthap->mtha_a_cnt 	= mhp->a_cnt;
   1360 	mthap->mtha_a_nthr	= 0;
   1361 
   1362 	mutex_init(&mthap->mtha_a_mx, NULL, MUTEX_DEFAULT,
   1363 	    NULL);
   1364 	cv_init(&mthap->mtha_a_cv, NULL, CV_DEFAULT, NULL);
   1365 
   1366 	j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
   1367 	for (; j >= 0; j--) {
   1368 		(*mtaa_init_func)(&mthap->mtha_a_args[j], mthap);
   1369 		mthap->mtha_a_args[j].mtaa_h_nm = mhp->a_nm[j];
   1370 		mthap->mtha_a_args[j].mtaa_h_ip = mhp->a_ip[j];
   1371 		mthap->mtha_a_args[j].mtaa_h_flags = mhp->a_flg;
   1372 		mthap->mtha_a_args[j].mtaa_err_func = mtaa_err_func;
   1373 	}
   1374 }
   1375 
   1376 static void
   1377 mtha_free(
   1378 	med_thr_h_args_t	*mthap,
   1379 	void			(*mtaa_free_func)(med_thr_a_args_t *)
   1380 )
   1381 {
   1382 	int		j;
   1383 
   1384 	freestr(mthap->mtha_setname);
   1385 
   1386 	j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
   1387 	for (; j >= 0; j--)
   1388 		(*mtaa_free_func)(&mthap->mtha_a_args[j]);
   1389 
   1390 	mutex_destroy(&mthap->mtha_a_mx);
   1391 	cv_destroy(&mthap->mtha_a_cv);
   1392 }
   1393 
   1394 static void
   1395 med_a_thr(med_thr_a_args_t *mtaap)
   1396 {
   1397 	callb_cpr_t	cprinfo;
   1398 
   1399 	/*
   1400 	 * Register cpr callback
   1401 	 */
   1402 	CALLB_CPR_INIT(&cprinfo, &mtaap->mtaa_mthap->mtha_a_mx,
   1403 	    callb_generic_cpr, "med_a_thr");
   1404 
   1405 	mutex_enter(&mtaap->mtaa_mthap->mtha_a_mx);
   1406 	if (mtaap->mtaa_mthap->mtha_flags & MDT_H_OK)
   1407 		goto done;
   1408 
   1409 	mutex_exit(&mtaap->mtaa_mthap->mtha_a_mx);
   1410 
   1411 	mtaap->mtaa_err = med_net_callrpc(
   1412 	    mtaap->mtaa_h_nm, mtaap->mtaa_h_ip, mtaap->mtaa_h_flags,
   1413 	    mtaap->mtaa_prog, mtaap->mtaa_vers, mtaap->mtaa_proc,
   1414 	    mtaap->mtaa_inproc, mtaap->mtaa_in,
   1415 	    mtaap->mtaa_outproc, mtaap->mtaa_out,
   1416 	    mtaap->mtaa_timout);
   1417 
   1418 	mutex_enter(&mtaap->mtaa_mthap->mtha_a_mx);
   1419 
   1420 	if (mtaap->mtaa_err) {
   1421 		MAJOR(("med_net_callrpc(%u, %u, %u) - %s - failed\n\n",
   1422 		    mtaap->mtaa_prog, mtaap->mtaa_vers, mtaap->mtaa_proc,
   1423 		    mtaap->mtaa_h_nm));
   1424 		xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
   1425 	} else {
   1426 		if ((*mtaap->mtaa_err_func)(mtaap) == 0) {
   1427 			if (! (mtaap->mtaa_mthap->mtha_flags & MDT_H_OK)) {
   1428 				mtaap->mtaa_mthap->mtha_flags |= MDT_H_OK;
   1429 				mtaap->mtaa_flags |= MDT_A_OK;
   1430 			} else
   1431 				xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
   1432 		} else
   1433 			xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
   1434 	}
   1435 
   1436 done:
   1437 	mtaap->mtaa_mthap->mtha_a_nthr--;
   1438 	cv_signal(&mtaap->mtaa_mthap->mtha_a_cv);
   1439 
   1440 	/*
   1441 	 * CALLB_CPR_EXIT will do mutex_exit(&mtaap->mtaa_mthap->mtha_a_mx)
   1442 	 */
   1443 	CALLB_CPR_EXIT(&cprinfo);
   1444 	thread_exit();
   1445 }
   1446 
   1447 static void
   1448 med_h_thr(med_thr_h_args_t *mthap)
   1449 {
   1450 	int		j;
   1451 	callb_cpr_t	cprinfo;
   1452 
   1453 	/*
   1454 	 * Register cpr callback
   1455 	 */
   1456 	CALLB_CPR_INIT(&cprinfo, &mthap->mtha_mtp->mt_mx, callb_generic_cpr,
   1457 	    "med_a_thr");
   1458 	/*
   1459 	 * Lock mthap->mtha_mtp->mt_mx is held early to avoid releasing the
   1460 	 * locks out of order.
   1461 	 */
   1462 	mutex_enter(&mthap->mtha_mtp->mt_mx);
   1463 	mutex_enter(&mthap->mtha_a_mx);
   1464 
   1465 	j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
   1466 	for (; j >= 0; j--) {
   1467 		(void) thread_create(NULL, 0, med_a_thr,
   1468 		    &mthap->mtha_a_args[j], 0, &p0, TS_RUN, minclsyspri);
   1469 		mthap->mtha_a_nthr++;
   1470 	}
   1471 
   1472 	/*
   1473 	 * cpr safe to suspend while waiting for other threads
   1474 	 */
   1475 	CALLB_CPR_SAFE_BEGIN(&cprinfo);
   1476 	while (mthap->mtha_a_nthr > 0)
   1477 		cv_wait(&mthap->mtha_a_cv, &mthap->mtha_a_mx);
   1478 	mutex_exit(&mthap->mtha_a_mx);
   1479 	CALLB_CPR_SAFE_END(&cprinfo, &mthap->mtha_mtp->mt_mx);
   1480 
   1481 
   1482 	mthap->mtha_mtp->mt_nthr--;
   1483 	cv_signal(&mthap->mtha_mtp->mt_cv);
   1484 
   1485 	/*
   1486 	 * set up cpr exit
   1487 	 * CALLB_CPR_EXIT will do mutex_exit(&mtaap->mta_mtp->mt_mx)
   1488 	 */
   1489 	CALLB_CPR_EXIT(&cprinfo);
   1490 	thread_exit();
   1491 }
   1492 
   1493 static med_get_data_res_t *
   1494 mtaa_get_resp(med_thr_h_args_t *mthap)
   1495 {
   1496 	med_thr_a_args_t	*mtaap;
   1497 	int			j;
   1498 
   1499 	j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
   1500 	for (; j >= 0; j--) {
   1501 		mtaap = &mthap->mtha_a_args[j];
   1502 		if (mtaap->mtaa_flags & MDT_A_OK)
   1503 			/*LINTED*/
   1504 			return ((med_get_data_res_t *)mtaap->mtaa_out);
   1505 	}
   1506 	return ((med_get_data_res_t *)NULL);
   1507 }
   1508 
   1509 /*
   1510  * Public Functions
   1511  */
   1512 
   1513 /*
   1514  * initializes med structs, locks, etc
   1515  */
   1516 void
   1517 med_init(void)
   1518 {
   1519 	int		uapi;
   1520 
   1521 	TRIVIA(("[med_init"));
   1522 
   1523 	for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
   1524 		struct	med_addr	*uap = &med_addr_tab[uapi];
   1525 
   1526 		/* If the protocol is skipped, the mutex is not needed either */
   1527 		if (md_med_trans_lst != NULL &&
   1528 		    strstr(md_med_trans_lst, uap->ua_kn.knc_proto) == NULL &&
   1529 		    strstr(md_med_trans_lst, uap->ua_netid) == NULL) {
   1530 			uap->ua_flags |= UAFLG_SKIP;
   1531 			continue;
   1532 		}
   1533 
   1534 		mutex_init(&uap->ua_mutex, NULL, MUTEX_DEFAULT, NULL);
   1535 		uap->ua_flags |= UAFLG_LOCKINIT;
   1536 		bzero((caddr_t)&uap->ua_kn.knc_unused,
   1537 		    sizeof (uap->ua_kn.knc_unused));
   1538 	}
   1539 
   1540 	TRIVIA(("]\n"));
   1541 }
   1542 
   1543 /*
   1544  * free any med structs, locks, etc
   1545  */
   1546 void
   1547 med_fini(void)
   1548 {
   1549 	int	uapi;
   1550 
   1551 	TRIVIA(("[med_fini"));
   1552 
   1553 	for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
   1554 		struct med_addr *uap = &med_addr_tab[uapi];
   1555 
   1556 		if (uap->ua_flags & UAFLG_LOCKINIT) {
   1557 			mutex_destroy(&uap->ua_mutex);
   1558 			uap->ua_flags &= ~UAFLG_LOCKINIT;
   1559 		}
   1560 	}
   1561 
   1562 	TRIVIA(("]\n"));
   1563 }
   1564 
   1565 /*
   1566  * Update all the mediators
   1567  */
   1568 int
   1569 upd_med_hosts(
   1570 	md_hi_arr_t		*mp,
   1571 	char			*setname,
   1572 	med_data_t		*meddp,
   1573 	char			*caller
   1574 )
   1575 {
   1576 	med_thr_t		*mtp;
   1577 	med_thr_h_args_t	*mthap;
   1578 	int			i;
   1579 	int			medok = 0;
   1580 
   1581 	MAJOR(("upd_med_hosts - called from <%s>\n", NULLSTR(caller)));
   1582 
   1583 	/* No mediators, were done */
   1584 	if (mp->n_cnt == 0)
   1585 		return (0);
   1586 
   1587 	mtp = kmem_zalloc(sizeof (med_thr_t), KM_SLEEP);
   1588 	ASSERT(mtp != NULL);
   1589 
   1590 	mutex_init(&mtp->mt_mx, NULL, MUTEX_DEFAULT, NULL);
   1591 	cv_init(&mtp->mt_cv, NULL, CV_DEFAULT, NULL);
   1592 	mtp->mt_mag = MTH_MAGIC;
   1593 
   1594 	mutex_enter(&mtp->mt_mx);
   1595 
   1596 	mtp->mt_nthr = 0;
   1597 
   1598 	/* Loop through our list of mediator hosts, start a thread per host */
   1599 	for (i = 0; i < md_nmedh; i++) {
   1600 
   1601 		if (mp->n_lst[i].a_cnt == 0)
   1602 			continue;
   1603 
   1604 		mtp->mt_h_args[i] = kmem_zalloc(sizeof (med_thr_h_args_t),
   1605 		    KM_SLEEP);
   1606 		mthap = mtp->mt_h_args[i];
   1607 		ASSERT(mthap != NULL);
   1608 		mtha_init(mtp, mthap, &mp->n_lst[i], setname, meddp,
   1609 		    meddp->med_dat_sn, mtaa_upd_init, mtaa_upd_err);
   1610 
   1611 		MAJOR(("upd_med_hosts - updating %s\n",
   1612 		    NULLSTR(mp->n_lst[i].a_nm[0])));
   1613 
   1614 		(void) thread_create(NULL, 0, med_h_thr, mthap, 0, &p0,
   1615 		    TS_RUN, minclsyspri);
   1616 
   1617 		mtp->mt_nthr++;
   1618 	}
   1619 
   1620 	while (mtp->mt_nthr > 0)
   1621 		cv_wait(&mtp->mt_cv, &mtp->mt_mx);
   1622 
   1623 	mutex_exit(&mtp->mt_mx);
   1624 
   1625 	for (i = 0; i < md_nmedh; i++) {
   1626 		mthap = mtp->mt_h_args[i];
   1627 		if (mthap != NULL) {
   1628 			if (mthap->mtha_flags & MDT_H_OK)
   1629 				medok++;
   1630 			mtha_free(mthap, mtaa_upd_free);
   1631 			kmem_free(mthap, sizeof (med_thr_h_args_t));
   1632 		}
   1633 	}
   1634 
   1635 	mutex_destroy(&mtp->mt_mx);
   1636 	cv_destroy(&mtp->mt_cv);
   1637 
   1638 	kmem_free(mtp, sizeof (med_thr_t));
   1639 
   1640 	return (medok);
   1641 }
   1642 
   1643 /*
   1644  * Get the mediator data.
   1645  */
   1646 med_data_lst_t *
   1647 get_med_host_data(
   1648 	md_hi_arr_t		*mp,
   1649 	char			*setname,
   1650 	set_t			setno
   1651 )
   1652 {
   1653 	med_thr_t		*mtp;
   1654 	med_thr_h_args_t	*mthap;
   1655 	med_get_data_res_t	*resp;
   1656 	med_data_lst_t		*retval = NULL;
   1657 	int			i;
   1658 
   1659 	/* No mediators, were done */
   1660 	if (mp->n_cnt == 0)
   1661 		return (NULL);
   1662 
   1663 	mtp = kmem_zalloc(sizeof (med_thr_t), KM_SLEEP);
   1664 	ASSERT(mtp != NULL);
   1665 
   1666 	mutex_init(&mtp->mt_mx, NULL, MUTEX_DEFAULT, NULL);
   1667 	cv_init(&mtp->mt_cv, NULL, CV_DEFAULT, NULL);
   1668 
   1669 	mutex_enter(&mtp->mt_mx);
   1670 
   1671 	mtp->mt_nthr = 0;
   1672 
   1673 	/* Loop through our list of mediator hosts, start a thread per host */
   1674 	for (i = 0; i < md_nmedh; i++) {
   1675 
   1676 		if (mp->n_lst[i].a_cnt == 0)
   1677 			continue;
   1678 
   1679 		mtp->mt_h_args[i] = kmem_zalloc(sizeof (med_thr_h_args_t),
   1680 		    KM_SLEEP);
   1681 		mthap = mtp->mt_h_args[i];
   1682 		ASSERT(mthap != NULL);
   1683 		mtha_init(mtp, mthap, &mp->n_lst[i], setname, NULL, setno,
   1684 		    mtaa_get_init, mtaa_get_err);
   1685 
   1686 		MAJOR(("get_med_host_data from %s\n",
   1687 		    NULLSTR(mp->n_lst[i].a_nm[0])));
   1688 
   1689 		(void) thread_create(NULL, 0, med_h_thr, mthap, 0, &p0,
   1690 		    TS_RUN, minclsyspri);
   1691 
   1692 		mtp->mt_nthr++;
   1693 	}
   1694 
   1695 	while (mtp->mt_nthr > 0)
   1696 		cv_wait(&mtp->mt_cv, &mtp->mt_mx);
   1697 
   1698 	mutex_exit(&mtp->mt_mx);
   1699 
   1700 	for (i = 0; i < md_nmedh; i++) {
   1701 		mthap = mtp->mt_h_args[i];
   1702 		if (mthap != NULL) {
   1703 			if (mthap->mtha_flags & MDT_H_OK) {
   1704 				resp = mtaa_get_resp(mthap);
   1705 				ASSERT(resp != NULL);
   1706 
   1707 				if (med_ok(setno, &resp->med_data))
   1708 					med_adl(&retval, &resp->med_data);
   1709 			}
   1710 			mtha_free(mthap, mtaa_get_free);
   1711 			kmem_free(mthap, sizeof (med_thr_h_args_t));
   1712 		}
   1713 	}
   1714 
   1715 	mutex_destroy(&mtp->mt_mx);
   1716 	cv_destroy(&mtp->mt_cv);
   1717 
   1718 	kmem_free(mtp, sizeof (med_thr_t));
   1719 
   1720 	return (retval);
   1721 }
   1722 
   1723 int
   1724 med_get_t_size_ioctl(mddb_med_t_parm_t *tpp, int mode)
   1725 {
   1726 	md_error_t	*ep = &tpp->med_tp_mde;
   1727 
   1728 	mdclrerror(ep);
   1729 
   1730 	if ((mode & FREAD) == 0)
   1731 		return (mdsyserror(ep, EACCES));
   1732 
   1733 	tpp->med_tp_nents = med_addr_tab_nents;
   1734 	tpp->med_tp_setup = md_med_transdevs_set;
   1735 
   1736 	return (0);
   1737 }
   1738 
   1739 int
   1740 med_get_t_ioctl(mddb_med_t_parm_t *tpp, int mode)
   1741 {
   1742 	md_error_t	*ep = &tpp->med_tp_mde;
   1743 	int		uapi = 0;
   1744 
   1745 	mdclrerror(ep);
   1746 
   1747 	if ((mode & FREAD) == 0)
   1748 		return (mdsyserror(ep, EACCES));
   1749 
   1750 	for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
   1751 		struct	med_addr	*uap = &med_addr_tab[uapi];
   1752 
   1753 		(void) strncpy(tpp->med_tp_ents[uapi].med_te_nm,
   1754 		    uap->ua_devname, MED_TE_NM_LEN);
   1755 		tpp->med_tp_ents[uapi].med_te_dev =
   1756 		    (md_dev64_t)uap->ua_kn.knc_rdev;
   1757 	}
   1758 
   1759 	tpp->med_tp_nents = med_addr_tab_nents;
   1760 
   1761 	return (0);
   1762 }
   1763 
   1764 int
   1765 med_set_t_ioctl(mddb_med_t_parm_t *tpp, int mode)
   1766 {
   1767 	md_error_t	*ep = &tpp->med_tp_mde;
   1768 	int		uapi = 0;
   1769 
   1770 	mdclrerror(ep);
   1771 
   1772 	if ((mode & FWRITE) == 0)
   1773 		return (mdsyserror(ep, EACCES));
   1774 
   1775 	for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
   1776 		struct	med_addr	*uap = &med_addr_tab[uapi];
   1777 
   1778 		mutex_enter(&uap->ua_mutex);
   1779 		uap->ua_kn.knc_rdev = md_dev64_to_dev(
   1780 		    tpp->med_tp_ents[uapi].med_te_dev);
   1781 		mutex_exit(&uap->ua_mutex);
   1782 	}
   1783 
   1784 	md_med_transdevs_set = 1;
   1785 
   1786 	return (0);
   1787 }
   1788