xref: /onnv-gate/usr/src/uts/common/rpc/rpcmod.c (revision 2610)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52470Sgt29601  * Common Development and Distribution License (the "License").
62470Sgt29601  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
222470Sgt29601  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * Kernel RPC filtering module
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/stream.h>
400Sstevel@tonic-gate #include <sys/stropts.h>
410Sstevel@tonic-gate #include <sys/tihdr.h>
420Sstevel@tonic-gate #include <sys/timod.h>
430Sstevel@tonic-gate #include <sys/tiuser.h>
440Sstevel@tonic-gate #include <sys/debug.h>
450Sstevel@tonic-gate #include <sys/signal.h>
460Sstevel@tonic-gate #include <sys/pcb.h>
470Sstevel@tonic-gate #include <sys/user.h>
480Sstevel@tonic-gate #include <sys/errno.h>
490Sstevel@tonic-gate #include <sys/cred.h>
500Sstevel@tonic-gate #include <sys/policy.h>
510Sstevel@tonic-gate #include <sys/inline.h>
520Sstevel@tonic-gate #include <sys/cmn_err.h>
530Sstevel@tonic-gate #include <sys/kmem.h>
540Sstevel@tonic-gate #include <sys/file.h>
550Sstevel@tonic-gate #include <sys/sysmacros.h>
560Sstevel@tonic-gate #include <sys/systm.h>
570Sstevel@tonic-gate #include <sys/t_lock.h>
580Sstevel@tonic-gate #include <sys/ddi.h>
590Sstevel@tonic-gate #include <sys/vtrace.h>
600Sstevel@tonic-gate #include <sys/callb.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <sys/strlog.h>
630Sstevel@tonic-gate #include <rpc/rpc_com.h>
640Sstevel@tonic-gate #include <inet/common.h>
650Sstevel@tonic-gate #include <rpc/types.h>
660Sstevel@tonic-gate #include <sys/time.h>
670Sstevel@tonic-gate #include <rpc/xdr.h>
680Sstevel@tonic-gate #include <rpc/auth.h>
690Sstevel@tonic-gate #include <rpc/clnt.h>
700Sstevel@tonic-gate #include <rpc/rpc_msg.h>
710Sstevel@tonic-gate #include <rpc/clnt.h>
720Sstevel@tonic-gate #include <rpc/svc.h>
730Sstevel@tonic-gate #include <rpc/rpcsys.h>
740Sstevel@tonic-gate #include <rpc/rpc_rdma.h>
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * This is the loadable module wrapper.
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate #include <sys/conf.h>
800Sstevel@tonic-gate #include <sys/modctl.h>
810Sstevel@tonic-gate #include <sys/syscall.h>
820Sstevel@tonic-gate 
830Sstevel@tonic-gate extern struct streamtab rpcinfo;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static struct fmodsw fsw = {
860Sstevel@tonic-gate 	"rpcmod",
870Sstevel@tonic-gate 	&rpcinfo,
880Sstevel@tonic-gate 	D_NEW|D_MP,
890Sstevel@tonic-gate };
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * Module linkage information for the kernel.
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
960Sstevel@tonic-gate 	&mod_strmodops, "rpc interface str mod", &fsw
970Sstevel@tonic-gate };
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * For the RPC system call.
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate static struct sysent rpcsysent = {
1030Sstevel@tonic-gate 	2,
1040Sstevel@tonic-gate 	SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
1050Sstevel@tonic-gate 	rpcsys
1060Sstevel@tonic-gate };
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate static struct modlsys modlsys = {
1090Sstevel@tonic-gate 	&mod_syscallops,
1100Sstevel@tonic-gate 	"RPC syscall",
1110Sstevel@tonic-gate 	&rpcsysent
1120Sstevel@tonic-gate };
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1150Sstevel@tonic-gate static struct modlsys modlsys32 = {
1160Sstevel@tonic-gate 	&mod_syscallops32,
1170Sstevel@tonic-gate 	"32-bit RPC syscall",
1180Sstevel@tonic-gate 	&rpcsysent
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static struct modlinkage modlinkage = {
1230Sstevel@tonic-gate 	MODREV_1,
1240Sstevel@tonic-gate 	{
1250Sstevel@tonic-gate 		&modlsys,
1260Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1270Sstevel@tonic-gate 		&modlsys32,
1280Sstevel@tonic-gate #endif
1290Sstevel@tonic-gate 		&modlstrmod,
1300Sstevel@tonic-gate 		NULL
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate int
1350Sstevel@tonic-gate _init(void)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	int error = 0;
1380Sstevel@tonic-gate 	callb_id_t cid;
1390Sstevel@tonic-gate 	int status;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	svc_init();
1420Sstevel@tonic-gate 	clnt_init();
1430Sstevel@tonic-gate 	cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc");
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (error = mod_install(&modlinkage)) {
1460Sstevel@tonic-gate 		/*
1470Sstevel@tonic-gate 		 * Could not install module, cleanup previous
1480Sstevel@tonic-gate 		 * initialization work.
1490Sstevel@tonic-gate 		 */
1500Sstevel@tonic-gate 		clnt_fini();
1510Sstevel@tonic-gate 		if (cid != NULL)
1520Sstevel@tonic-gate 			(void) callb_delete(cid);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		return (error);
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * Load up the RDMA plugins and initialize the stats. Even if the
1590Sstevel@tonic-gate 	 * plugins loadup fails, but rpcmod was successfully installed the
1600Sstevel@tonic-gate 	 * counters still get initialized.
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 	rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL);
1630Sstevel@tonic-gate 	mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL);
1640Sstevel@tonic-gate 	mt_kstat_init();
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	/*
1670Sstevel@tonic-gate 	 * Get our identification into ldi.  This is used for loading
1680Sstevel@tonic-gate 	 * other modules, e.g. rpcib.
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	status = ldi_ident_from_mod(&modlinkage, &rpcmod_li);
1710Sstevel@tonic-gate 	if (status != 0) {
1720Sstevel@tonic-gate 		cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status);
1730Sstevel@tonic-gate 		rpcmod_li = NULL;
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (error);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * The unload entry point fails, because we advertise entry points into
1810Sstevel@tonic-gate  * rpcmod from the rest of kRPC: rpcmod_release().
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate int
1840Sstevel@tonic-gate _fini(void)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	return (EBUSY);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate int
1900Sstevel@tonic-gate _info(struct modinfo *modinfop)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate extern int nulldev();
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate #define	RPCMOD_ID	2049
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate int rmm_open(), rmm_close();
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * To save instructions, since STREAMS ignores the return value
2030Sstevel@tonic-gate  * from these functions, they are defined as void here. Kind of icky, but...
2040Sstevel@tonic-gate  */
2050Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *);
2060Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *);
2070Sstevel@tonic-gate void rmm_rsrv(queue_t *);
2080Sstevel@tonic-gate void rmm_wsrv(queue_t *);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate int rpcmodopen(), rpcmodclose();
2110Sstevel@tonic-gate void rpcmodrput(), rpcmodwput();
2120Sstevel@tonic-gate void rpcmodrsrv(), rpcmodwsrv();
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate static	void	rpcmodwput_other(queue_t *, mblk_t *);
2150Sstevel@tonic-gate static	int	mir_close(queue_t *q);
2160Sstevel@tonic-gate static	int	mir_open(queue_t *q, dev_t *devp, int flag, int sflag,
2170Sstevel@tonic-gate 		    cred_t *credp);
2180Sstevel@tonic-gate static	void	mir_rput(queue_t *q, mblk_t *mp);
2190Sstevel@tonic-gate static	void	mir_rsrv(queue_t *q);
2200Sstevel@tonic-gate static	void	mir_wput(queue_t *q, mblk_t *mp);
2210Sstevel@tonic-gate static	void	mir_wsrv(queue_t *q);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate static struct module_info rpcmod_info =
2240Sstevel@tonic-gate 	{RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024};
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate  * Read side has no service procedure.
2280Sstevel@tonic-gate  */
2290Sstevel@tonic-gate static struct qinit rpcmodrinit = {
2300Sstevel@tonic-gate 	(int (*)())rmm_rput,
2310Sstevel@tonic-gate 	(int (*)())rmm_rsrv,
2320Sstevel@tonic-gate 	rmm_open,
2330Sstevel@tonic-gate 	rmm_close,
2340Sstevel@tonic-gate 	nulldev,
2350Sstevel@tonic-gate 	&rpcmod_info,
2360Sstevel@tonic-gate 	NULL
2370Sstevel@tonic-gate };
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate  * The write put procedure is simply putnext to conserve stack space.
2410Sstevel@tonic-gate  * The write service procedure is not used to queue data, but instead to
2420Sstevel@tonic-gate  * synchronize with flow control.
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate static struct qinit rpcmodwinit = {
2450Sstevel@tonic-gate 	(int (*)())rmm_wput,
2460Sstevel@tonic-gate 	(int (*)())rmm_wsrv,
2470Sstevel@tonic-gate 	rmm_open,
2480Sstevel@tonic-gate 	rmm_close,
2490Sstevel@tonic-gate 	nulldev,
2500Sstevel@tonic-gate 	&rpcmod_info,
2510Sstevel@tonic-gate 	NULL
2520Sstevel@tonic-gate };
2530Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL };
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate struct xprt_style_ops {
2560Sstevel@tonic-gate 	int (*xo_open)();
2570Sstevel@tonic-gate 	int (*xo_close)();
2580Sstevel@tonic-gate 	void (*xo_wput)();
2590Sstevel@tonic-gate 	void (*xo_wsrv)();
2600Sstevel@tonic-gate 	void (*xo_rput)();
2610Sstevel@tonic-gate 	void (*xo_rsrv)();
2620Sstevel@tonic-gate };
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = {
2650Sstevel@tonic-gate 	rpcmodopen,
2660Sstevel@tonic-gate 	rpcmodclose,
2670Sstevel@tonic-gate 	rpcmodwput,
2680Sstevel@tonic-gate 	rpcmodwsrv,
2690Sstevel@tonic-gate 	rpcmodrput,
2700Sstevel@tonic-gate 	NULL
2710Sstevel@tonic-gate };
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = {
2740Sstevel@tonic-gate 	mir_open,
2750Sstevel@tonic-gate 	mir_close,
2760Sstevel@tonic-gate 	mir_wput,
2770Sstevel@tonic-gate 	mir_wsrv,
2780Sstevel@tonic-gate 	mir_rput,
2790Sstevel@tonic-gate 	mir_rsrv
2800Sstevel@tonic-gate };
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate  * Per rpcmod "slot" data structure. q->q_ptr points to one of these.
2840Sstevel@tonic-gate  */
2850Sstevel@tonic-gate struct rpcm {
2860Sstevel@tonic-gate 	void		*rm_krpc_cell;	/* Reserved for use by KRPC */
2870Sstevel@tonic-gate 	struct		xprt_style_ops	*rm_ops;
2880Sstevel@tonic-gate 	int		rm_type;	/* Client or server side stream */
2890Sstevel@tonic-gate #define	RM_CLOSING	0x1		/* somebody is trying to close slot */
2900Sstevel@tonic-gate 	uint_t		rm_state;	/* state of the slot. see above */
2910Sstevel@tonic-gate 	uint_t		rm_ref;		/* cnt of external references to slot */
2920Sstevel@tonic-gate 	kmutex_t	rm_lock;	/* mutex protecting above fields */
2930Sstevel@tonic-gate 	kcondvar_t	rm_cwait;	/* condition for closing */
2940Sstevel@tonic-gate 	zoneid_t	rm_zoneid;	/* zone which pushed rpcmod */
2950Sstevel@tonic-gate };
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate struct temp_slot {
2980Sstevel@tonic-gate 	void *cell;
2990Sstevel@tonic-gate 	struct xprt_style_ops *ops;
3000Sstevel@tonic-gate 	int type;
3010Sstevel@tonic-gate 	mblk_t *info_ack;
3020Sstevel@tonic-gate 	kmutex_t lock;
3030Sstevel@tonic-gate 	kcondvar_t wait;
3040Sstevel@tonic-gate };
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate struct xprt_style_ops tmpops = {
3090Sstevel@tonic-gate 	NULL,
3100Sstevel@tonic-gate 	NULL,
3110Sstevel@tonic-gate 	putnext,
3120Sstevel@tonic-gate 	NULL,
3130Sstevel@tonic-gate 	tmp_rput,
3140Sstevel@tonic-gate 	NULL
3150Sstevel@tonic-gate };
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate void
3180Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	struct temp_slot *t = (struct temp_slot *)(q->q_ptr);
3210Sstevel@tonic-gate 	struct T_info_ack *pptr;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
3240Sstevel@tonic-gate 	case M_PCPROTO:
3250Sstevel@tonic-gate 		pptr = (struct T_info_ack *)mp->b_rptr;
3260Sstevel@tonic-gate 		switch (pptr->PRIM_type) {
3270Sstevel@tonic-gate 		case T_INFO_ACK:
3280Sstevel@tonic-gate 			mutex_enter(&t->lock);
3290Sstevel@tonic-gate 			t->info_ack = mp;
3300Sstevel@tonic-gate 			cv_signal(&t->wait);
3310Sstevel@tonic-gate 			mutex_exit(&t->lock);
3320Sstevel@tonic-gate 			return;
3330Sstevel@tonic-gate 		default:
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 	default:
3370Sstevel@tonic-gate 		break;
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/*
3410Sstevel@tonic-gate 	 * Not an info-ack, so free it. This is ok because we should
3420Sstevel@tonic-gate 	 * not be receiving data until the open finishes: rpcmod
3430Sstevel@tonic-gate 	 * is pushed well before the end-point is bound to an address.
3440Sstevel@tonic-gate 	 */
3450Sstevel@tonic-gate 	freemsg(mp);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate int
3490Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	mblk_t *bp;
3520Sstevel@tonic-gate 	struct temp_slot ts, *t;
3530Sstevel@tonic-gate 	struct T_info_ack *pptr;
3540Sstevel@tonic-gate 	int error = 0;
3550Sstevel@tonic-gate 	int procson = 0;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	ASSERT(q != NULL);
3580Sstevel@tonic-gate 	/*
3590Sstevel@tonic-gate 	 * Check for re-opens.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	if (q->q_ptr) {
3620Sstevel@tonic-gate 		TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END,
3630Sstevel@tonic-gate 		    "rpcmodopen_end:(%s)", "q->qptr");
3640Sstevel@tonic-gate 		return (0);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	t = &ts;
3680Sstevel@tonic-gate 	bzero(t, sizeof (*t));
3690Sstevel@tonic-gate 	q->q_ptr = (void *)t;
3700Sstevel@tonic-gate 	/* WR(q)->q_ptr = (void *)t; */
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	/*
3730Sstevel@tonic-gate 	 * Allocate the required messages upfront.
3740Sstevel@tonic-gate 	 */
3750Sstevel@tonic-gate 	if ((bp = allocb(sizeof (struct T_info_req) +
3760Sstevel@tonic-gate 	    sizeof (struct T_info_ack), BPRI_LO)) == (mblk_t *)NULL) {
3770Sstevel@tonic-gate 		return (ENOBUFS);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL);
3810Sstevel@tonic-gate 	cv_init(&t->wait, NULL, CV_DEFAULT, NULL);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	t->ops = &tmpops;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	qprocson(q);
3860Sstevel@tonic-gate 	procson = 1;
3870Sstevel@tonic-gate 	bp->b_datap->db_type = M_PCPROTO;
3880Sstevel@tonic-gate 	*(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ;
3890Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct T_info_req);
3900Sstevel@tonic-gate 	putnext(WR(q), bp);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	mutex_enter(&t->lock);
3930Sstevel@tonic-gate 	while ((bp = t->info_ack) == NULL) {
3940Sstevel@tonic-gate 		if (cv_wait_sig(&t->wait, &t->lock) == 0) {
3950Sstevel@tonic-gate 			error = EINTR;
3960Sstevel@tonic-gate 			break;
3970Sstevel@tonic-gate 		}
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 	mutex_exit(&t->lock);
4000Sstevel@tonic-gate 	mutex_destroy(&t->lock);
4010Sstevel@tonic-gate 	cv_destroy(&t->wait);
4020Sstevel@tonic-gate 	if (error)
4030Sstevel@tonic-gate 		goto out;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	pptr = (struct T_info_ack *)t->info_ack->b_rptr;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (pptr->SERV_type == T_CLTS) {
4080Sstevel@tonic-gate 		error = rpcmodopen(q, devp, flag, sflag, crp);
4090Sstevel@tonic-gate 		if (error == 0) {
4100Sstevel@tonic-gate 			t = (struct temp_slot *)q->q_ptr;
4110Sstevel@tonic-gate 			t->ops = &xprt_clts_ops;
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 	} else {
4140Sstevel@tonic-gate 		error = mir_open(q, devp, flag, sflag, crp);
4150Sstevel@tonic-gate 		if (error == 0) {
4160Sstevel@tonic-gate 			t = (struct temp_slot *)q->q_ptr;
4170Sstevel@tonic-gate 			t->ops = &xprt_cots_ops;
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate out:
4220Sstevel@tonic-gate 	freemsg(bp);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (error && procson)
4250Sstevel@tonic-gate 		qprocsoff(q);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	return (error);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate void
4310Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t  *mp)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate void
4370Sstevel@tonic-gate rmm_rsrv(queue_t *q)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate void
4430Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate void
4490Sstevel@tonic-gate rmm_wsrv(queue_t *q)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate int
4550Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp));
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * rpcmodopen -	open routine gets called when the module gets pushed
4620Sstevel@tonic-gate  *		onto the stream.
4630Sstevel@tonic-gate  */
4640Sstevel@tonic-gate /*ARGSUSED*/
4650Sstevel@tonic-gate int
4660Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
4670Sstevel@tonic-gate {
4680Sstevel@tonic-gate 	struct rpcm *rmp;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	extern void (*rpc_rele)(queue_t *, mblk_t *);
4710Sstevel@tonic-gate 	static void rpcmod_release(queue_t *, mblk_t *);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:");
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/*
4760Sstevel@tonic-gate 	 * Initialize entry points to release a rpcmod slot (and an input
4770Sstevel@tonic-gate 	 * message if supplied) and to send an output message to the module
4780Sstevel@tonic-gate 	 * below rpcmod.
4790Sstevel@tonic-gate 	 */
4800Sstevel@tonic-gate 	if (rpc_rele == NULL)
4810Sstevel@tonic-gate 		rpc_rele = rpcmod_release;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	/*
4840Sstevel@tonic-gate 	 * Only sufficiently privileged users can use this module, and it
4850Sstevel@tonic-gate 	 * is assumed that they will use this module properly, and NOT send
4860Sstevel@tonic-gate 	 * bulk data from downstream.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	if (secpolicy_rpcmod_open(crp) != 0)
4890Sstevel@tonic-gate 		return (EPERM);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * Allocate slot data structure.
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL);
4970Sstevel@tonic-gate 	cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL);
498766Scarlsonj 	rmp->rm_zoneid = rpc_zoneid();
4990Sstevel@tonic-gate 	/*
5000Sstevel@tonic-gate 	 * slot type will be set by kRPC client and server ioctl's
5010Sstevel@tonic-gate 	 */
5020Sstevel@tonic-gate 	rmp->rm_type = 0;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	q->q_ptr = (void *)rmp;
5050Sstevel@tonic-gate 	WR(q)->q_ptr = (void *)rmp;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end");
5080Sstevel@tonic-gate 	return (0);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate  * rpcmodclose - This routine gets called when the module gets popped
5130Sstevel@tonic-gate  * off of the stream.
5140Sstevel@tonic-gate  */
5150Sstevel@tonic-gate /*ARGSUSED*/
5160Sstevel@tonic-gate int
5170Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	struct rpcm *rmp;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	ASSERT(q != NULL);
5220Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/*
5250Sstevel@tonic-gate 	 * Mark our state as closing.
5260Sstevel@tonic-gate 	 */
5270Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
5280Sstevel@tonic-gate 	rmp->rm_state |= RM_CLOSING;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * Check and see if there are any messages on the queue.  If so, send
5320Sstevel@tonic-gate 	 * the messages, regardless whether the downstream module is ready to
5330Sstevel@tonic-gate 	 * accept data.
5340Sstevel@tonic-gate 	 */
5350Sstevel@tonic-gate 	if (rmp->rm_type == RPC_SERVER) {
5360Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 		qenable(WR(q));
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		if (rmp->rm_ref) {
5410Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
5420Sstevel@tonic-gate 			/*
5430Sstevel@tonic-gate 			 * call into SVC to clean the queue
5440Sstevel@tonic-gate 			 */
5450Sstevel@tonic-gate 			svc_queueclean(q);
5460Sstevel@tonic-gate 			mutex_enter(&rmp->rm_lock);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 			/*
5490Sstevel@tonic-gate 			 * Block while there are kRPC threads with a reference
5500Sstevel@tonic-gate 			 * to this message.
5510Sstevel@tonic-gate 			 */
5520Sstevel@tonic-gate 			while (rmp->rm_ref)
5530Sstevel@tonic-gate 				cv_wait(&rmp->rm_cwait, &rmp->rm_lock);
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		/*
5590Sstevel@tonic-gate 		 * It is now safe to remove this queue from the stream. No kRPC
5600Sstevel@tonic-gate 		 * threads have a reference to the stream, and none ever will,
5610Sstevel@tonic-gate 		 * because RM_CLOSING is set.
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		qprocsoff(q);
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		/* Notify kRPC that this stream is going away. */
5660Sstevel@tonic-gate 		svc_queueclose(q);
5670Sstevel@tonic-gate 	} else {
5680Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
5690Sstevel@tonic-gate 		qprocsoff(q);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	q->q_ptr = NULL;
5730Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
5740Sstevel@tonic-gate 	mutex_destroy(&rmp->rm_lock);
5750Sstevel@tonic-gate 	cv_destroy(&rmp->rm_cwait);
5760Sstevel@tonic-gate 	kmem_free(rmp, sizeof (*rmp));
5770Sstevel@tonic-gate 	return (0);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate #ifdef	DEBUG
5810Sstevel@tonic-gate int	rpcmod_send_msg_up = 0;
5820Sstevel@tonic-gate int	rpcmod_send_uderr = 0;
5830Sstevel@tonic-gate int	rpcmod_send_dup = 0;
5840Sstevel@tonic-gate int	rpcmod_send_dup_cnt = 0;
5850Sstevel@tonic-gate #endif
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate /*
5880Sstevel@tonic-gate  * rpcmodrput -	Module read put procedure.  This is called from
5890Sstevel@tonic-gate  *		the module, driver, or stream head downstream.
5900Sstevel@tonic-gate  */
5910Sstevel@tonic-gate void
5920Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate 	struct rpcm *rmp;
5950Sstevel@tonic-gate 	union T_primitives *pptr;
5960Sstevel@tonic-gate 	int hdrsz;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:");
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	ASSERT(q != NULL);
6010Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (rmp->rm_type == 0) {
6040Sstevel@tonic-gate 		freemsg(mp);
6050Sstevel@tonic-gate 		return;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate #ifdef DEBUG
6090Sstevel@tonic-gate 	if (rpcmod_send_msg_up > 0) {
6100Sstevel@tonic-gate 		mblk_t *nmp = copymsg(mp);
6110Sstevel@tonic-gate 		if (nmp) {
6120Sstevel@tonic-gate 			putnext(q, nmp);
6130Sstevel@tonic-gate 			rpcmod_send_msg_up--;
6140Sstevel@tonic-gate 		}
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 	if ((rpcmod_send_uderr > 0) && mp->b_datap->db_type == M_PROTO) {
6170Sstevel@tonic-gate 		mblk_t *nmp;
6180Sstevel@tonic-gate 		struct T_unitdata_ind *data;
6190Sstevel@tonic-gate 		struct T_uderror_ind *ud;
6200Sstevel@tonic-gate 		int d;
6210Sstevel@tonic-gate 		data = (struct T_unitdata_ind *)mp->b_rptr;
6220Sstevel@tonic-gate 		if (data->PRIM_type == T_UNITDATA_IND) {
6230Sstevel@tonic-gate 			d = sizeof (*ud) - sizeof (*data);
6240Sstevel@tonic-gate 			nmp = allocb(mp->b_wptr - mp->b_rptr + d, BPRI_HI);
6250Sstevel@tonic-gate 			if (nmp) {
6260Sstevel@tonic-gate 				ud = (struct T_uderror_ind *)nmp->b_rptr;
6270Sstevel@tonic-gate 				ud->PRIM_type = T_UDERROR_IND;
6280Sstevel@tonic-gate 				ud->DEST_length = data->SRC_length;
6290Sstevel@tonic-gate 				ud->DEST_offset = data->SRC_offset + d;
6300Sstevel@tonic-gate 				ud->OPT_length = data->OPT_length;
6310Sstevel@tonic-gate 				ud->OPT_offset = data->OPT_offset + d;
6320Sstevel@tonic-gate 				ud->ERROR_type = ENETDOWN;
6330Sstevel@tonic-gate 				if (data->SRC_length) {
6340Sstevel@tonic-gate 					bcopy(mp->b_rptr +
6350Sstevel@tonic-gate 					    data->SRC_offset,
6360Sstevel@tonic-gate 					    nmp->b_rptr +
6370Sstevel@tonic-gate 					    ud->DEST_offset,
6380Sstevel@tonic-gate 					    data->SRC_length);
6390Sstevel@tonic-gate 				}
6400Sstevel@tonic-gate 				if (data->OPT_length) {
6410Sstevel@tonic-gate 					bcopy(mp->b_rptr +
6420Sstevel@tonic-gate 					    data->OPT_offset,
6430Sstevel@tonic-gate 					    nmp->b_rptr +
6440Sstevel@tonic-gate 					    ud->OPT_offset,
6450Sstevel@tonic-gate 					    data->OPT_length);
6460Sstevel@tonic-gate 				}
6470Sstevel@tonic-gate 				nmp->b_wptr += d;
6480Sstevel@tonic-gate 				nmp->b_wptr += (mp->b_wptr - mp->b_rptr);
6490Sstevel@tonic-gate 				nmp->b_datap->db_type = M_PROTO;
6500Sstevel@tonic-gate 				putnext(q, nmp);
6510Sstevel@tonic-gate 				rpcmod_send_uderr--;
6520Sstevel@tonic-gate 			}
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate #endif
6560Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
6570Sstevel@tonic-gate 	default:
6580Sstevel@tonic-gate 		putnext(q, mp);
6590Sstevel@tonic-gate 		break;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	case M_PROTO:
6620Sstevel@tonic-gate 	case M_PCPROTO:
6630Sstevel@tonic-gate 		ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t));
6640Sstevel@tonic-gate 		pptr = (union T_primitives *)mp->b_rptr;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		/*
6670Sstevel@tonic-gate 		 * Forward this message to krpc if it is data.
6680Sstevel@tonic-gate 		 */
6690Sstevel@tonic-gate 		if (pptr->type == T_UNITDATA_IND) {
6700Sstevel@tonic-gate 		    mblk_t *nmp;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 		/*
6730Sstevel@tonic-gate 		 * Check if the module is being popped.
6740Sstevel@tonic-gate 		 */
6750Sstevel@tonic-gate 		    mutex_enter(&rmp->rm_lock);
6760Sstevel@tonic-gate 		    if (rmp->rm_state & RM_CLOSING) {
6770Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
6780Sstevel@tonic-gate 			putnext(q, mp);
6790Sstevel@tonic-gate 			break;
6800Sstevel@tonic-gate 		    }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 		    switch (rmp->rm_type) {
6830Sstevel@tonic-gate 		    case RPC_CLIENT:
6840Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
6850Sstevel@tonic-gate 			hdrsz = mp->b_wptr - mp->b_rptr;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 			/*
6880Sstevel@tonic-gate 			 * Make sure the header is sane.
6890Sstevel@tonic-gate 			 */
6900Sstevel@tonic-gate 			if (hdrsz < TUNITDATAINDSZ ||
6910Sstevel@tonic-gate 				hdrsz < (pptr->unitdata_ind.OPT_length +
6920Sstevel@tonic-gate 					pptr->unitdata_ind.OPT_offset) ||
6930Sstevel@tonic-gate 				hdrsz < (pptr->unitdata_ind.SRC_length +
6940Sstevel@tonic-gate 					pptr->unitdata_ind.SRC_offset)) {
6950Sstevel@tonic-gate 					freemsg(mp);
6960Sstevel@tonic-gate 					return;
6970Sstevel@tonic-gate 			}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 			/*
7000Sstevel@tonic-gate 			 * Call clnt_clts_dispatch_notify, so that it can
7010Sstevel@tonic-gate 			 * pass the message to the proper caller.  Don't
7020Sstevel@tonic-gate 			 * discard the header just yet since the client may
7030Sstevel@tonic-gate 			 * need the sender's address.
7040Sstevel@tonic-gate 			 */
7050Sstevel@tonic-gate 			clnt_clts_dispatch_notify(mp, hdrsz, rmp->rm_zoneid);
7060Sstevel@tonic-gate 			return;
7070Sstevel@tonic-gate 		    case RPC_SERVER:
7080Sstevel@tonic-gate 			/*
7090Sstevel@tonic-gate 			 * rm_krpc_cell is exclusively used by the kRPC
7100Sstevel@tonic-gate 			 * CLTS server
7110Sstevel@tonic-gate 			 */
7120Sstevel@tonic-gate 			if (rmp->rm_krpc_cell) {
7130Sstevel@tonic-gate #ifdef DEBUG
7140Sstevel@tonic-gate 				/*
7150Sstevel@tonic-gate 				 * Test duplicate request cache and
7160Sstevel@tonic-gate 				 * rm_ref count handling by sending a
7170Sstevel@tonic-gate 				 * duplicate every so often, if
7180Sstevel@tonic-gate 				 * desired.
7190Sstevel@tonic-gate 				 */
7200Sstevel@tonic-gate 				if (rpcmod_send_dup &&
7210Sstevel@tonic-gate 				    rpcmod_send_dup_cnt++ %
7220Sstevel@tonic-gate 				    rpcmod_send_dup)
7230Sstevel@tonic-gate 					nmp = copymsg(mp);
7240Sstevel@tonic-gate 				else
7250Sstevel@tonic-gate 					nmp = NULL;
7260Sstevel@tonic-gate #endif
7270Sstevel@tonic-gate 				/*
7280Sstevel@tonic-gate 				 * Raise the reference count on this
7290Sstevel@tonic-gate 				 * module to prevent it from being
7300Sstevel@tonic-gate 				 * popped before krpc generates the
7310Sstevel@tonic-gate 				 * reply.
7320Sstevel@tonic-gate 				 */
7330Sstevel@tonic-gate 				rmp->rm_ref++;
7340Sstevel@tonic-gate 				mutex_exit(&rmp->rm_lock);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 				/*
7370Sstevel@tonic-gate 				 * Submit the message to krpc.
7380Sstevel@tonic-gate 				 */
7390Sstevel@tonic-gate 				svc_queuereq(q, mp);
7400Sstevel@tonic-gate #ifdef DEBUG
7410Sstevel@tonic-gate 				/*
7420Sstevel@tonic-gate 				 * Send duplicate if we created one.
7430Sstevel@tonic-gate 				 */
7440Sstevel@tonic-gate 				if (nmp) {
7450Sstevel@tonic-gate 					mutex_enter(&rmp->rm_lock);
7460Sstevel@tonic-gate 					rmp->rm_ref++;
7470Sstevel@tonic-gate 					mutex_exit(&rmp->rm_lock);
7480Sstevel@tonic-gate 					svc_queuereq(q, nmp);
7490Sstevel@tonic-gate 				}
7500Sstevel@tonic-gate #endif
7510Sstevel@tonic-gate 			} else {
7520Sstevel@tonic-gate 				mutex_exit(&rmp->rm_lock);
7530Sstevel@tonic-gate 				freemsg(mp);
7540Sstevel@tonic-gate 			}
7550Sstevel@tonic-gate 			return;
7560Sstevel@tonic-gate 		    default:
7570Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
7580Sstevel@tonic-gate 			freemsg(mp);
7590Sstevel@tonic-gate 			return;
7600Sstevel@tonic-gate 		    } /* end switch(rmp->rm_type) */
7610Sstevel@tonic-gate 		} else if (pptr->type == T_UDERROR_IND) {
7620Sstevel@tonic-gate 		    mutex_enter(&rmp->rm_lock);
7630Sstevel@tonic-gate 		    hdrsz = mp->b_wptr - mp->b_rptr;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		/*
7660Sstevel@tonic-gate 		 * Make sure the header is sane
7670Sstevel@tonic-gate 		 */
7680Sstevel@tonic-gate 		    if (hdrsz < TUDERRORINDSZ ||
7690Sstevel@tonic-gate 			hdrsz < (pptr->uderror_ind.OPT_length +
7700Sstevel@tonic-gate 				pptr->uderror_ind.OPT_offset) ||
7710Sstevel@tonic-gate 			hdrsz < (pptr->uderror_ind.DEST_length +
7720Sstevel@tonic-gate 				pptr->uderror_ind.DEST_offset)) {
7730Sstevel@tonic-gate 			    mutex_exit(&rmp->rm_lock);
7740Sstevel@tonic-gate 			    freemsg(mp);
7750Sstevel@tonic-gate 			    return;
7760Sstevel@tonic-gate 		    }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 		/*
7790Sstevel@tonic-gate 		 * In the case where a unit data error has been
7800Sstevel@tonic-gate 		 * received, all we need to do is clear the message from
7810Sstevel@tonic-gate 		 * the queue.
7820Sstevel@tonic-gate 		 */
7830Sstevel@tonic-gate 		    mutex_exit(&rmp->rm_lock);
7840Sstevel@tonic-gate 		    freemsg(mp);
7850Sstevel@tonic-gate 		    RPCLOG(32, "rpcmodrput: unitdata error received at "
7860Sstevel@tonic-gate 				"%ld\n", gethrestime_sec());
7870Sstevel@tonic-gate 		    return;
7880Sstevel@tonic-gate 		} /* end else if (pptr->type == T_UDERROR_IND) */
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		putnext(q, mp);
7910Sstevel@tonic-gate 		break;
7920Sstevel@tonic-gate 	} /* end switch (mp->b_datap->db_type) */
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END,
7950Sstevel@tonic-gate 		"rpcmodrput_end:");
7960Sstevel@tonic-gate 	/*
7970Sstevel@tonic-gate 	 * Return codes are not looked at by the STREAMS framework.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate /*
8020Sstevel@tonic-gate  * write put procedure
8030Sstevel@tonic-gate  */
8040Sstevel@tonic-gate void
8050Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	struct rpcm	*rmp;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	ASSERT(q != NULL);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
8120Sstevel@tonic-gate 	    case M_PROTO:
8130Sstevel@tonic-gate 	    case M_PCPROTO:
8140Sstevel@tonic-gate 		    break;
8150Sstevel@tonic-gate 	    default:
8160Sstevel@tonic-gate 		    rpcmodwput_other(q, mp);
8170Sstevel@tonic-gate 		    return;
8180Sstevel@tonic-gate 	}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Check to see if we can send the message downstream.
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	if (canputnext(q)) {
8240Sstevel@tonic-gate 		putnext(q, mp);
8250Sstevel@tonic-gate 		return;
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
8290Sstevel@tonic-gate 	ASSERT(rmp != NULL);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	/*
8320Sstevel@tonic-gate 	 * The first canputnext failed.  Try again except this time with the
8330Sstevel@tonic-gate 	 * lock held, so that we can check the state of the stream to see if
8340Sstevel@tonic-gate 	 * it is closing.  If either of these conditions evaluate to true
8350Sstevel@tonic-gate 	 * then send the meesage.
8360Sstevel@tonic-gate 	 */
8370Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
8380Sstevel@tonic-gate 	if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) {
8390Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
8400Sstevel@tonic-gate 		putnext(q, mp);
8410Sstevel@tonic-gate 	} else {
8420Sstevel@tonic-gate 		/*
8430Sstevel@tonic-gate 		 * canputnext failed again and the stream is not closing.
8440Sstevel@tonic-gate 		 * Place the message on the queue and let the service
8450Sstevel@tonic-gate 		 * procedure handle the message.
8460Sstevel@tonic-gate 		 */
8470Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
8480Sstevel@tonic-gate 		(void) putq(q, mp);
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate static void
8530Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate 	struct rpcm	*rmp;
8560Sstevel@tonic-gate 	struct iocblk	*iocp;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
8590Sstevel@tonic-gate 	ASSERT(rmp != NULL);
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
8620Sstevel@tonic-gate 		case M_IOCTL:
8630Sstevel@tonic-gate 			iocp = (struct iocblk *)mp->b_rptr;
8640Sstevel@tonic-gate 			ASSERT(iocp != NULL);
8650Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
8660Sstevel@tonic-gate 			    case RPC_CLIENT:
8670Sstevel@tonic-gate 			    case RPC_SERVER:
8680Sstevel@tonic-gate 				    mutex_enter(&rmp->rm_lock);
8690Sstevel@tonic-gate 				    rmp->rm_type = iocp->ioc_cmd;
8700Sstevel@tonic-gate 				    mutex_exit(&rmp->rm_lock);
8710Sstevel@tonic-gate 				    mp->b_datap->db_type = M_IOCACK;
8720Sstevel@tonic-gate 				    qreply(q, mp);
8730Sstevel@tonic-gate 				    return;
8740Sstevel@tonic-gate 			    default:
8750Sstevel@tonic-gate 				/*
8760Sstevel@tonic-gate 				 * pass the ioctl downstream and hope someone
8770Sstevel@tonic-gate 				 * down there knows how to handle it.
8780Sstevel@tonic-gate 				 */
8790Sstevel@tonic-gate 				    putnext(q, mp);
8800Sstevel@tonic-gate 				    return;
8810Sstevel@tonic-gate 			}
8820Sstevel@tonic-gate 		default:
8830Sstevel@tonic-gate 			break;
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * This is something we definitely do not know how to handle, just
8870Sstevel@tonic-gate 	 * pass the message downstream
8880Sstevel@tonic-gate 	 */
8890Sstevel@tonic-gate 	putnext(q, mp);
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate  * Module write service procedure. This is called by downstream modules
8940Sstevel@tonic-gate  * for back enabling during flow control.
8950Sstevel@tonic-gate  */
8960Sstevel@tonic-gate void
8970Sstevel@tonic-gate rpcmodwsrv(queue_t *q)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	struct rpcm	*rmp;
9000Sstevel@tonic-gate 	mblk_t		*mp = NULL;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
9030Sstevel@tonic-gate 	ASSERT(rmp != NULL);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	/*
9060Sstevel@tonic-gate 	 * Get messages that may be queued and send them down stream
9070Sstevel@tonic-gate 	 */
9080Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
9090Sstevel@tonic-gate 		/*
9100Sstevel@tonic-gate 		 * Optimize the service procedure for the server-side, by
9110Sstevel@tonic-gate 		 * avoiding a call to canputnext().
9120Sstevel@tonic-gate 		 */
9130Sstevel@tonic-gate 		if (rmp->rm_type == RPC_SERVER || canputnext(q)) {
9140Sstevel@tonic-gate 			putnext(q, mp);
9150Sstevel@tonic-gate 			continue;
9160Sstevel@tonic-gate 		}
9170Sstevel@tonic-gate 		(void) putbq(q, mp);
9180Sstevel@tonic-gate 		return;
9190Sstevel@tonic-gate 	}
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate static void
9230Sstevel@tonic-gate rpcmod_release(queue_t *q, mblk_t *bp)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate 	struct rpcm *rmp;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/*
9280Sstevel@tonic-gate 	 * For now, just free the message.
9290Sstevel@tonic-gate 	 */
9300Sstevel@tonic-gate 	if (bp)
9310Sstevel@tonic-gate 		freemsg(bp);
9320Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
9350Sstevel@tonic-gate 	rmp->rm_ref--;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) {
9380Sstevel@tonic-gate 		cv_broadcast(&rmp->rm_cwait);
9390Sstevel@tonic-gate 	}
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	mutex_exit(&rmp->rm_lock);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate /*
9450Sstevel@tonic-gate  * This part of rpcmod is pushed on a connection-oriented transport for use
9460Sstevel@tonic-gate  * by RPC.  It serves to bypass the Stream head, implements
9470Sstevel@tonic-gate  * the record marking protocol, and dispatches incoming RPC messages.
9480Sstevel@tonic-gate  */
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate /* Default idle timer values */
9510Sstevel@tonic-gate #define	MIR_CLNT_IDLE_TIMEOUT	(5 * (60 * 1000L))	/* 5 minutes */
9520Sstevel@tonic-gate #define	MIR_SVC_IDLE_TIMEOUT	(6 * (60 * 1000L))	/* 6 minutes */
9530Sstevel@tonic-gate #define	MIR_SVC_ORDREL_TIMEOUT	(10 * (60 * 1000L))	/* 10 minutes */
9540Sstevel@tonic-gate #define	MIR_LASTFRAG	0x80000000	/* Record marker */
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate #define	DLEN(mp) (mp->b_cont ? msgdsize(mp) : (mp->b_wptr - mp->b_rptr))
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate typedef struct mir_s {
9590Sstevel@tonic-gate 	void	*mir_krpc_cell;	/* Reserved for KRPC use. This field */
9600Sstevel@tonic-gate 					/* must be first in the structure. */
9610Sstevel@tonic-gate 	struct xprt_style_ops	*rm_ops;
9620Sstevel@tonic-gate 	int	mir_type;		/* Client or server side stream */
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	mblk_t	*mir_head_mp;		/* RPC msg in progress */
9650Sstevel@tonic-gate 		/*
9660Sstevel@tonic-gate 		 * mir_head_mp points the first mblk being collected in
9670Sstevel@tonic-gate 		 * the current RPC message.  Record headers are removed
9680Sstevel@tonic-gate 		 * before data is linked into mir_head_mp.
9690Sstevel@tonic-gate 		 */
9700Sstevel@tonic-gate 	mblk_t	*mir_tail_mp;		/* Last mblk in mir_head_mp */
9710Sstevel@tonic-gate 		/*
9720Sstevel@tonic-gate 		 * mir_tail_mp points to the last mblk in the message
9730Sstevel@tonic-gate 		 * chain starting at mir_head_mp.  It is only valid
9740Sstevel@tonic-gate 		 * if mir_head_mp is non-NULL and is used to add new
9750Sstevel@tonic-gate 		 * data blocks to the end of chain quickly.
9760Sstevel@tonic-gate 		 */
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	int32_t	mir_frag_len;		/* Bytes seen in the current frag */
9790Sstevel@tonic-gate 		/*
9800Sstevel@tonic-gate 		 * mir_frag_len starts at -4 for beginning of each fragment.
9810Sstevel@tonic-gate 		 * When this length is negative, it indicates the number of
9820Sstevel@tonic-gate 		 * bytes that rpcmod needs to complete the record marker
9830Sstevel@tonic-gate 		 * header.  When it is positive or zero, it holds the number
9840Sstevel@tonic-gate 		 * of bytes that have arrived for the current fragment and
9850Sstevel@tonic-gate 		 * are held in mir_header_mp.
9860Sstevel@tonic-gate 		 */
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	int32_t	mir_frag_header;
9890Sstevel@tonic-gate 		/*
9900Sstevel@tonic-gate 		 * Fragment header as collected for the current fragment.
9910Sstevel@tonic-gate 		 * It holds the last-fragment indicator and the number
9920Sstevel@tonic-gate 		 * of bytes in the fragment.
9930Sstevel@tonic-gate 		 */
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	unsigned int
9960Sstevel@tonic-gate 		mir_ordrel_pending : 1,	/* Sent T_ORDREL_REQ */
9970Sstevel@tonic-gate 		mir_hold_inbound : 1,	/* Hold inbound messages on server */
9980Sstevel@tonic-gate 					/* side until outbound flow control */
9990Sstevel@tonic-gate 					/* is relieved. */
10000Sstevel@tonic-gate 		mir_closing : 1,	/* The stream is being closed */
10010Sstevel@tonic-gate 		mir_inrservice : 1,	/* data queued or rd srv proc running */
10020Sstevel@tonic-gate 		mir_inwservice : 1,	/* data queued or wr srv proc running */
10030Sstevel@tonic-gate 		mir_inwflushdata : 1,	/* flush M_DATAs when srv runs */
10040Sstevel@tonic-gate 		/*
10050Sstevel@tonic-gate 		 * On client streams, mir_clntreq is 0 or 1; it is set
10060Sstevel@tonic-gate 		 * to 1 whenever a new request is sent out (mir_wput)
10070Sstevel@tonic-gate 		 * and cleared when the timer fires (mir_timer).  If
10080Sstevel@tonic-gate 		 * the timer fires with this value equal to 0, then the
10090Sstevel@tonic-gate 		 * stream is considered idle and KRPC is notified.
10100Sstevel@tonic-gate 		 */
10110Sstevel@tonic-gate 		mir_clntreq : 1,
10120Sstevel@tonic-gate 		/*
10130Sstevel@tonic-gate 		 * On server streams, stop accepting messages
10140Sstevel@tonic-gate 		 */
10150Sstevel@tonic-gate 		mir_svc_no_more_msgs : 1,
10160Sstevel@tonic-gate 		mir_listen_stream : 1,	/* listen end point */
10172470Sgt29601 		mir_unused : 1,	/* no longer used */
10180Sstevel@tonic-gate 		mir_timer_call : 1,
10190Sstevel@tonic-gate 		mir_junk_fill_thru_bit_31 : 21;
10200Sstevel@tonic-gate 
10212470Sgt29601 	int	mir_setup_complete;	/* server has initialized everything */
10220Sstevel@tonic-gate 	timeout_id_t mir_timer_id;	/* Timer for idle checks */
10230Sstevel@tonic-gate 	clock_t	mir_idle_timeout;	/* Allowed idle time before shutdown */
10240Sstevel@tonic-gate 		/*
10250Sstevel@tonic-gate 		 * This value is copied from clnt_idle_timeout or
10260Sstevel@tonic-gate 		 * svc_idle_timeout during the appropriate ioctl.
10270Sstevel@tonic-gate 		 * Kept in milliseconds
10280Sstevel@tonic-gate 		 */
10290Sstevel@tonic-gate 	clock_t	mir_use_timestamp;	/* updated on client with each use */
10300Sstevel@tonic-gate 		/*
10310Sstevel@tonic-gate 		 * This value is set to lbolt
10320Sstevel@tonic-gate 		 * every time a client stream sends or receives data.
10330Sstevel@tonic-gate 		 * Even if the timer message arrives, we don't shutdown
10340Sstevel@tonic-gate 		 * client unless:
10350Sstevel@tonic-gate 		 *    lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp.
10360Sstevel@tonic-gate 		 * This value is kept in HZ.
10370Sstevel@tonic-gate 		 */
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	uint_t	*mir_max_msg_sizep;	/* Reference to sanity check size */
10400Sstevel@tonic-gate 		/*
10410Sstevel@tonic-gate 		 * This pointer is set to &clnt_max_msg_size or
10420Sstevel@tonic-gate 		 * &svc_max_msg_size during the appropriate ioctl.
10430Sstevel@tonic-gate 		 */
10440Sstevel@tonic-gate 	zoneid_t mir_zoneid;	/* zone which pushed rpcmod */
10450Sstevel@tonic-gate 	/* Server-side fields. */
10460Sstevel@tonic-gate 	int	mir_ref_cnt;		/* Reference count: server side only */
10470Sstevel@tonic-gate 					/* counts the number of references */
10480Sstevel@tonic-gate 					/* that a kernel RPC server thread */
10490Sstevel@tonic-gate 					/* (see svc_run()) has on this rpcmod */
10500Sstevel@tonic-gate 					/* slot. Effectively, it is the */
10510Sstevel@tonic-gate 					/* number * of unprocessed messages */
10520Sstevel@tonic-gate 					/* that have been passed up to the */
10530Sstevel@tonic-gate 					/* KRPC layer */
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	mblk_t	*mir_svc_pend_mp;	/* Pending T_ORDREL_IND or */
10560Sstevel@tonic-gate 					/* T_DISCON_IND */
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	/*
10590Sstevel@tonic-gate 	 * these fields are for both client and server, but for debugging,
10600Sstevel@tonic-gate 	 * it is easier to have these last in the structure.
10610Sstevel@tonic-gate 	 */
10620Sstevel@tonic-gate 	kmutex_t	mir_mutex;	/* Mutex and condvar for close */
10630Sstevel@tonic-gate 	kcondvar_t	mir_condvar;	/* synchronization. */
10640Sstevel@tonic-gate 	kcondvar_t	mir_timer_cv;	/* Timer routine sync. */
10650Sstevel@tonic-gate } mir_t;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate #define	MIR_SVC_QUIESCED(mir)	\
10680Sstevel@tonic-gate 	(mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0)
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate #define	MIR_CLEAR_INRSRV(mir_ptr)	{	\
10710Sstevel@tonic-gate 	(mir_ptr)->mir_inrservice = 0;	\
10720Sstevel@tonic-gate 	if ((mir_ptr)->mir_type == RPC_SERVER &&	\
10730Sstevel@tonic-gate 		(mir_ptr)->mir_closing)	\
10740Sstevel@tonic-gate 		cv_signal(&(mir_ptr)->mir_condvar);	\
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate  * Don't block service procedure (and mir_close) if
10790Sstevel@tonic-gate  * we are in the process of closing.
10800Sstevel@tonic-gate  */
10810Sstevel@tonic-gate #define	MIR_WCANPUTNEXT(mir_ptr, write_q)	\
10820Sstevel@tonic-gate 	(canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1))
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate static int	mir_clnt_dup_request(queue_t *q, mblk_t *mp);
10850Sstevel@tonic-gate static void	mir_rput_proto(queue_t *q, mblk_t *mp);
10860Sstevel@tonic-gate static int	mir_svc_policy_notify(queue_t *q, int event);
10870Sstevel@tonic-gate static void	mir_svc_release(queue_t *wq, mblk_t *mp);
10880Sstevel@tonic-gate static void	mir_svc_start(queue_t *wq);
10890Sstevel@tonic-gate static void	mir_svc_idle_start(queue_t *, mir_t *);
10900Sstevel@tonic-gate static void	mir_svc_idle_stop(queue_t *, mir_t *);
10910Sstevel@tonic-gate static void	mir_svc_start_close(queue_t *, mir_t *);
10920Sstevel@tonic-gate static void	mir_clnt_idle_do_stop(queue_t *);
10930Sstevel@tonic-gate static void	mir_clnt_idle_stop(queue_t *, mir_t *);
10940Sstevel@tonic-gate static void	mir_clnt_idle_start(queue_t *, mir_t *);
10950Sstevel@tonic-gate static void	mir_wput(queue_t *q, mblk_t *mp);
10960Sstevel@tonic-gate static void	mir_wput_other(queue_t *q, mblk_t *mp);
10970Sstevel@tonic-gate static void	mir_wsrv(queue_t *q);
10980Sstevel@tonic-gate static	void	mir_disconnect(queue_t *, mir_t *ir);
10990Sstevel@tonic-gate static	int	mir_check_len(queue_t *, int32_t, mblk_t *);
11000Sstevel@tonic-gate static	void	mir_timer(void *);
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate extern void	(*mir_rele)(queue_t *, mblk_t *);
11030Sstevel@tonic-gate extern void	(*mir_start)(queue_t *);
11040Sstevel@tonic-gate extern void	(*clnt_stop_idle)(queue_t *);
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate clock_t	clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT;
11070Sstevel@tonic-gate clock_t	svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate /*
11100Sstevel@tonic-gate  * Timeout for subsequent notifications of idle connection.  This is
11110Sstevel@tonic-gate  * typically used to clean up after a wedged orderly release.
11120Sstevel@tonic-gate  */
11130Sstevel@tonic-gate clock_t	svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate extern	uint_t	*clnt_max_msg_sizep;
11160Sstevel@tonic-gate extern	uint_t	*svc_max_msg_sizep;
11170Sstevel@tonic-gate uint_t	clnt_max_msg_size = RPC_MAXDATASIZE;
11180Sstevel@tonic-gate uint_t	svc_max_msg_size = RPC_MAXDATASIZE;
11190Sstevel@tonic-gate uint_t	mir_krpc_cell_null;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate static void
11220Sstevel@tonic-gate mir_timer_stop(mir_t *mir)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	timeout_id_t tid;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	/*
11290Sstevel@tonic-gate 	 * Since the mir_mutex lock needs to be released to call
11300Sstevel@tonic-gate 	 * untimeout(), we need to make sure that no other thread
11310Sstevel@tonic-gate 	 * can start/stop the timer (changing mir_timer_id) during
11320Sstevel@tonic-gate 	 * that time.  The mir_timer_call bit and the mir_timer_cv
11330Sstevel@tonic-gate 	 * condition variable are used to synchronize this.  Setting
11340Sstevel@tonic-gate 	 * mir_timer_call also tells mir_timer() (refer to the comments
11350Sstevel@tonic-gate 	 * in mir_timer()) that it does not need to do anything.
11360Sstevel@tonic-gate 	 */
11370Sstevel@tonic-gate 	while (mir->mir_timer_call)
11380Sstevel@tonic-gate 		cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
11390Sstevel@tonic-gate 	mir->mir_timer_call = B_TRUE;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	if ((tid = mir->mir_timer_id) != 0) {
11420Sstevel@tonic-gate 		mir->mir_timer_id = 0;
11430Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
11440Sstevel@tonic-gate 		(void) untimeout(tid);
11450Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 	mir->mir_timer_call = B_FALSE;
11480Sstevel@tonic-gate 	cv_broadcast(&mir->mir_timer_cv);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate static void
11520Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	timeout_id_t tid;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	while (mir->mir_timer_call)
11590Sstevel@tonic-gate 		cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
11600Sstevel@tonic-gate 	mir->mir_timer_call = B_TRUE;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	if ((tid = mir->mir_timer_id) != 0) {
11630Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
11640Sstevel@tonic-gate 		(void) untimeout(tid);
11650Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 	/* Only start the timer when it is not closing. */
11680Sstevel@tonic-gate 	if (!mir->mir_closing) {
11690Sstevel@tonic-gate 		mir->mir_timer_id = timeout(mir_timer, q,
11700Sstevel@tonic-gate 		    MSEC_TO_TICK(intrvl));
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 	mir->mir_timer_call = B_FALSE;
11730Sstevel@tonic-gate 	cv_broadcast(&mir->mir_timer_cv);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate static int
11770Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp)
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate 	mblk_t  *mp1;
11800Sstevel@tonic-gate 	uint32_t  new_xid;
11810Sstevel@tonic-gate 	uint32_t  old_xid;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex));
11840Sstevel@tonic-gate 	new_xid = BE32_TO_U32(&mp->b_rptr[4]);
11850Sstevel@tonic-gate 	/*
11860Sstevel@tonic-gate 	 * This loop is a bit tacky -- it walks the STREAMS list of
11870Sstevel@tonic-gate 	 * flow-controlled messages.
11880Sstevel@tonic-gate 	 */
11890Sstevel@tonic-gate 	if ((mp1 = q->q_first) != NULL) {
11900Sstevel@tonic-gate 		do {
11910Sstevel@tonic-gate 			old_xid = BE32_TO_U32(&mp1->b_rptr[4]);
11920Sstevel@tonic-gate 			if (new_xid == old_xid)
11930Sstevel@tonic-gate 				return (1);
11940Sstevel@tonic-gate 		} while ((mp1 = mp1->b_next) != NULL);
11950Sstevel@tonic-gate 	}
11960Sstevel@tonic-gate 	return (0);
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate static int
12000Sstevel@tonic-gate mir_close(queue_t *q)
12010Sstevel@tonic-gate {
12020Sstevel@tonic-gate 	mir_t	*mir;
12030Sstevel@tonic-gate 	mblk_t	*mp;
12040Sstevel@tonic-gate 	bool_t queue_cleaned = FALSE;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q);
12070Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
12080Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
12090Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
12100Sstevel@tonic-gate 	if ((mp = mir->mir_head_mp) != NULL) {
12110Sstevel@tonic-gate 		mir->mir_head_mp = (mblk_t *)0;
12120Sstevel@tonic-gate 		freemsg(mp);
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 	/*
12150Sstevel@tonic-gate 	 * Set mir_closing so we get notified when MIR_SVC_QUIESCED()
12160Sstevel@tonic-gate 	 * is TRUE.  And mir_timer_start() won't start the timer again.
12170Sstevel@tonic-gate 	 */
12180Sstevel@tonic-gate 	mir->mir_closing = B_TRUE;
12190Sstevel@tonic-gate 	mir_timer_stop(mir);
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	if (mir->mir_type == RPC_SERVER) {
12220Sstevel@tonic-gate 		flushq(q, FLUSHDATA);	/* Ditch anything waiting on read q */
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 		/*
12250Sstevel@tonic-gate 		 * This will prevent more requests from arriving and
12260Sstevel@tonic-gate 		 * will force rpcmod to ignore flow control.
12270Sstevel@tonic-gate 		 */
12280Sstevel@tonic-gate 		mir_svc_start_close(WR(q), mir);
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) {
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 			if (mir->mir_ref_cnt && !mir->mir_inrservice &&
12330Sstevel@tonic-gate 					(queue_cleaned == FALSE)) {
12340Sstevel@tonic-gate 				/*
12350Sstevel@tonic-gate 				 * call into SVC to clean the queue
12360Sstevel@tonic-gate 				 */
12370Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
12380Sstevel@tonic-gate 				svc_queueclean(q);
12390Sstevel@tonic-gate 				queue_cleaned = TRUE;
12400Sstevel@tonic-gate 				mutex_enter(&mir->mir_mutex);
12410Sstevel@tonic-gate 				continue;
12420Sstevel@tonic-gate 			}
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 			/*
12450Sstevel@tonic-gate 			 * Bugid 1253810 - Force the write service
12460Sstevel@tonic-gate 			 * procedure to send its messages, regardless
12470Sstevel@tonic-gate 			 * whether the downstream  module is ready
12480Sstevel@tonic-gate 			 * to accept data.
12490Sstevel@tonic-gate 			 */
12500Sstevel@tonic-gate 			if (mir->mir_inwservice == 1)
12510Sstevel@tonic-gate 				qenable(WR(q));
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 			cv_wait(&mir->mir_condvar, &mir->mir_mutex);
12540Sstevel@tonic-gate 		}
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
12570Sstevel@tonic-gate 		qprocsoff(q);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 		/* Notify KRPC that this stream is going away. */
12600Sstevel@tonic-gate 		svc_queueclose(q);
12610Sstevel@tonic-gate 	} else {
12620Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
12630Sstevel@tonic-gate 		qprocsoff(q);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	mutex_destroy(&mir->mir_mutex);
12670Sstevel@tonic-gate 	cv_destroy(&mir->mir_condvar);
12680Sstevel@tonic-gate 	cv_destroy(&mir->mir_timer_cv);
12690Sstevel@tonic-gate 	kmem_free(mir, sizeof (mir_t));
12700Sstevel@tonic-gate 	return (0);
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate  * This is server side only (RPC_SERVER).
12750Sstevel@tonic-gate  *
12760Sstevel@tonic-gate  * Exit idle mode.
12770Sstevel@tonic-gate  */
12780Sstevel@tonic-gate static void
12790Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
12820Sstevel@tonic-gate 	ASSERT((q->q_flag & QREADR) == 0);
12830Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
12840Sstevel@tonic-gate 	RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q);
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	mir_timer_stop(mir);
12870Sstevel@tonic-gate }
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate /*
12900Sstevel@tonic-gate  * This is server side only (RPC_SERVER).
12910Sstevel@tonic-gate  *
12920Sstevel@tonic-gate  * Start idle processing, which will include setting idle timer if the
12930Sstevel@tonic-gate  * stream is not being closed.
12940Sstevel@tonic-gate  */
12950Sstevel@tonic-gate static void
12960Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
12990Sstevel@tonic-gate 	ASSERT((q->q_flag & QREADR) == 0);
13000Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
13010Sstevel@tonic-gate 	RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q);
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	/*
13040Sstevel@tonic-gate 	 * Don't re-start idle timer if we are closing queues.
13050Sstevel@tonic-gate 	 */
13060Sstevel@tonic-gate 	if (mir->mir_closing) {
13070Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n",
13080Sstevel@tonic-gate 			(void *)q);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 		/*
13110Sstevel@tonic-gate 		 * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED()
13120Sstevel@tonic-gate 		 * is true.  When it is true, and we are in the process of
13130Sstevel@tonic-gate 		 * closing the stream, signal any thread waiting in
13140Sstevel@tonic-gate 		 * mir_close().
13150Sstevel@tonic-gate 		 */
13160Sstevel@tonic-gate 		if (mir->mir_inwservice == 0)
13170Sstevel@tonic-gate 			cv_signal(&mir->mir_condvar);
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	} else {
13200Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_idle_start - reset %s timer\n",
13210Sstevel@tonic-gate 			mir->mir_ordrel_pending ? "ordrel" : "normal");
13220Sstevel@tonic-gate 		/*
13230Sstevel@tonic-gate 		 * Normal condition, start the idle timer.  If an orderly
13240Sstevel@tonic-gate 		 * release has been sent, set the timeout to wait for the
13250Sstevel@tonic-gate 		 * client to close its side of the connection.  Otherwise,
13260Sstevel@tonic-gate 		 * use the normal idle timeout.
13270Sstevel@tonic-gate 		 */
13280Sstevel@tonic-gate 		mir_timer_start(q, mir, mir->mir_ordrel_pending ?
13290Sstevel@tonic-gate 		    svc_ordrel_timeout : mir->mir_idle_timeout);
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate /* ARGSUSED */
13340Sstevel@tonic-gate static int
13350Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
13360Sstevel@tonic-gate {
13370Sstevel@tonic-gate 	mir_t	*mir;
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 	RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q);
13400Sstevel@tonic-gate 	/* Set variables used directly by KRPC. */
13410Sstevel@tonic-gate 	if (!mir_rele)
13420Sstevel@tonic-gate 		mir_rele = mir_svc_release;
13430Sstevel@tonic-gate 	if (!mir_start)
13440Sstevel@tonic-gate 		mir_start = mir_svc_start;
13450Sstevel@tonic-gate 	if (!clnt_stop_idle)
13460Sstevel@tonic-gate 		clnt_stop_idle = mir_clnt_idle_do_stop;
13470Sstevel@tonic-gate 	if (!clnt_max_msg_sizep)
13480Sstevel@tonic-gate 		clnt_max_msg_sizep = &clnt_max_msg_size;
13490Sstevel@tonic-gate 	if (!svc_max_msg_sizep)
13500Sstevel@tonic-gate 		svc_max_msg_sizep = &svc_max_msg_size;
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	/* Allocate a zero'ed out mir structure for this stream. */
13530Sstevel@tonic-gate 	mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/*
13560Sstevel@tonic-gate 	 * We set hold inbound here so that incoming messages will
13570Sstevel@tonic-gate 	 * be held on the read-side queue until the stream is completely
13580Sstevel@tonic-gate 	 * initialized with a RPC_CLIENT or RPC_SERVER ioctl.  During
13590Sstevel@tonic-gate 	 * the ioctl processing, the flag is cleared and any messages that
13600Sstevel@tonic-gate 	 * arrived between the open and the ioctl are delivered to KRPC.
13610Sstevel@tonic-gate 	 *
13620Sstevel@tonic-gate 	 * Early data should never arrive on a client stream since
13630Sstevel@tonic-gate 	 * servers only respond to our requests and we do not send any.
13640Sstevel@tonic-gate 	 * until after the stream is initialized.  Early data is
13650Sstevel@tonic-gate 	 * very common on a server stream where the client will start
13660Sstevel@tonic-gate 	 * sending data as soon as the connection is made (and this
13670Sstevel@tonic-gate 	 * is especially true with TCP where the protocol accepts the
13680Sstevel@tonic-gate 	 * connection before nfsd or KRPC is notified about it).
13690Sstevel@tonic-gate 	 */
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	mir->mir_hold_inbound = 1;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	/*
13740Sstevel@tonic-gate 	 * Start the record marker looking for a 4-byte header.  When
13750Sstevel@tonic-gate 	 * this length is negative, it indicates that rpcmod is looking
13760Sstevel@tonic-gate 	 * for bytes to consume for the record marker header.  When it
13770Sstevel@tonic-gate 	 * is positive, it holds the number of bytes that have arrived
13780Sstevel@tonic-gate 	 * for the current fragment and are being held in mir_header_mp.
13790Sstevel@tonic-gate 	 */
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
13820Sstevel@tonic-gate 
1383766Scarlsonj 	mir->mir_zoneid = rpc_zoneid();
13840Sstevel@tonic-gate 	mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL);
13850Sstevel@tonic-gate 	cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL);
13860Sstevel@tonic-gate 	cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	q->q_ptr = (char *)mir;
13890Sstevel@tonic-gate 	WR(q)->q_ptr = (char *)mir;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	/*
13920Sstevel@tonic-gate 	 * We noenable the read-side queue because we don't want it
13930Sstevel@tonic-gate 	 * automatically enabled by putq.  We enable it explicitly
13940Sstevel@tonic-gate 	 * in mir_wsrv when appropriate. (See additional comments on
13950Sstevel@tonic-gate 	 * flow control at the beginning of mir_rsrv.)
13960Sstevel@tonic-gate 	 */
13970Sstevel@tonic-gate 	noenable(q);
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	qprocson(q);
14000Sstevel@tonic-gate 	return (0);
14010Sstevel@tonic-gate }
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate /*
14040Sstevel@tonic-gate  * Read-side put routine for both the client and server side.  Does the
14050Sstevel@tonic-gate  * record marking for incoming RPC messages, and when complete, dispatches
14060Sstevel@tonic-gate  * the message to either the client or server.
14070Sstevel@tonic-gate  */
14080Sstevel@tonic-gate static void
14090Sstevel@tonic-gate mir_do_rput(queue_t *q, mblk_t *mp, int srv)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate 	mblk_t	*cont_mp;
14120Sstevel@tonic-gate 	int	excess;
14130Sstevel@tonic-gate 	int32_t	frag_len;
14140Sstevel@tonic-gate 	int32_t	frag_header;
14150Sstevel@tonic-gate 	mblk_t	*head_mp;
14160Sstevel@tonic-gate 	int	len;
14170Sstevel@tonic-gate 	mir_t	*mir;
14180Sstevel@tonic-gate 	mblk_t	*mp1;
14190Sstevel@tonic-gate 	unsigned char	*rptr;
14200Sstevel@tonic-gate 	mblk_t	*tail_mp;
14210Sstevel@tonic-gate 	unsigned char	*wptr;
14220Sstevel@tonic-gate 	boolean_t	stop_timer = B_FALSE;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
14250Sstevel@tonic-gate 	ASSERT(mir != NULL);
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	/*
14280Sstevel@tonic-gate 	 * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER
14290Sstevel@tonic-gate 	 * with the corresponding ioctl, then don't accept
14300Sstevel@tonic-gate 	 * any inbound data.  This should never happen for streams
14310Sstevel@tonic-gate 	 * created by nfsd or client-side KRPC because they are careful
14320Sstevel@tonic-gate 	 * to set the mode of the stream before doing anything else.
14330Sstevel@tonic-gate 	 */
14340Sstevel@tonic-gate 	if (mir->mir_type == 0) {
14350Sstevel@tonic-gate 		freemsg(mp);
14360Sstevel@tonic-gate 		return;
14370Sstevel@tonic-gate 	}
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
14420Sstevel@tonic-gate 	case M_DATA:
14430Sstevel@tonic-gate 		break;
14440Sstevel@tonic-gate 	case M_PROTO:
14450Sstevel@tonic-gate 	case M_PCPROTO:
14460Sstevel@tonic-gate 		rptr = mp->b_rptr;
14470Sstevel@tonic-gate 		if (mp->b_wptr - rptr < sizeof (uint32_t)) {
14480Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n",
14490Sstevel@tonic-gate 			    (int)(mp->b_wptr - rptr));
14500Sstevel@tonic-gate 			freemsg(mp);
14510Sstevel@tonic-gate 			return;
14520Sstevel@tonic-gate 		}
14530Sstevel@tonic-gate 		if (((union T_primitives *)rptr)->type != T_DATA_IND) {
14540Sstevel@tonic-gate 			mir_rput_proto(q, mp);
14550Sstevel@tonic-gate 			return;
14560Sstevel@tonic-gate 		}
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 		/* Throw away the T_DATA_IND block and continue with data. */
14590Sstevel@tonic-gate 		mp1 = mp;
14600Sstevel@tonic-gate 		mp = mp->b_cont;
14610Sstevel@tonic-gate 		freeb(mp1);
14620Sstevel@tonic-gate 		break;
14630Sstevel@tonic-gate 	case M_SETOPTS:
14640Sstevel@tonic-gate 		/*
14650Sstevel@tonic-gate 		 * If a module on the stream is trying set the Stream head's
14660Sstevel@tonic-gate 		 * high water mark, then set our hiwater to the requested
14670Sstevel@tonic-gate 		 * value.  We are the "stream head" for all inbound
14680Sstevel@tonic-gate 		 * data messages since messages are passed directly to KRPC.
14690Sstevel@tonic-gate 		 */
14700Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) >= sizeof (struct stroptions)) {
14710Sstevel@tonic-gate 			struct stroptions	*stropts;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 			stropts = (struct stroptions *)mp->b_rptr;
14740Sstevel@tonic-gate 			if ((stropts->so_flags & SO_HIWAT) &&
14750Sstevel@tonic-gate 				!(stropts->so_flags & SO_BAND)) {
14760Sstevel@tonic-gate 				(void) strqset(q, QHIWAT, 0, stropts->so_hiwat);
14770Sstevel@tonic-gate 			}
14780Sstevel@tonic-gate 		}
14790Sstevel@tonic-gate 		putnext(q, mp);
14800Sstevel@tonic-gate 		return;
14810Sstevel@tonic-gate 	case M_FLUSH:
14820Sstevel@tonic-gate 		RPCLOG(32, "mir_do_rput: ignoring M_FLUSH on q 0x%p. ",
14830Sstevel@tonic-gate 		    (void *)q);
14840Sstevel@tonic-gate 		RPCLOG(32, "M_FLUSH is %x\n", (uint_t)*mp->b_rptr);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 		putnext(q, mp);
14870Sstevel@tonic-gate 		return;
14880Sstevel@tonic-gate 	default:
14890Sstevel@tonic-gate 		putnext(q, mp);
14900Sstevel@tonic-gate 		return;
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	/*
14960Sstevel@tonic-gate 	 * If this connection is closing, don't accept any new messages.
14970Sstevel@tonic-gate 	 */
14980Sstevel@tonic-gate 	if (mir->mir_svc_no_more_msgs) {
14990Sstevel@tonic-gate 		ASSERT(mir->mir_type == RPC_SERVER);
15000Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
15010Sstevel@tonic-gate 		freemsg(mp);
15020Sstevel@tonic-gate 		return;
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	/* Get local copies for quicker access. */
15060Sstevel@tonic-gate 	frag_len = mir->mir_frag_len;
15070Sstevel@tonic-gate 	frag_header = mir->mir_frag_header;
15080Sstevel@tonic-gate 	head_mp = mir->mir_head_mp;
15090Sstevel@tonic-gate 	tail_mp = mir->mir_tail_mp;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	/* Loop, processing each message block in the mp chain separately. */
15120Sstevel@tonic-gate 	do {
15130Sstevel@tonic-gate 		/*
15140Sstevel@tonic-gate 		 * cont_mp is used in the do/while condition below to
15150Sstevel@tonic-gate 		 * walk to the next block in the STREAMS message.
15160Sstevel@tonic-gate 		 * mp->b_cont may be nil'ed during processing so we
15170Sstevel@tonic-gate 		 * can't rely on it to find the next block.
15180Sstevel@tonic-gate 		 */
15190Sstevel@tonic-gate 		cont_mp = mp->b_cont;
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 		/*
15220Sstevel@tonic-gate 		 * Get local copies of rptr and wptr for our processing.
15230Sstevel@tonic-gate 		 * These always point into "mp" (the current block being
15240Sstevel@tonic-gate 		 * processed), but rptr is updated as we consume any
15250Sstevel@tonic-gate 		 * record header in this message, and wptr is updated to
15260Sstevel@tonic-gate 		 * point to the end of the data for the current fragment,
15270Sstevel@tonic-gate 		 * if it ends in this block.  The main point is that
15280Sstevel@tonic-gate 		 * they are not always the same as b_rptr and b_wptr.
15290Sstevel@tonic-gate 		 * b_rptr and b_wptr will be updated when appropriate.
15300Sstevel@tonic-gate 		 */
15310Sstevel@tonic-gate 		rptr = mp->b_rptr;
15320Sstevel@tonic-gate 		wptr = mp->b_wptr;
15330Sstevel@tonic-gate same_mblk:;
15340Sstevel@tonic-gate 		len = (int)(wptr - rptr);
15350Sstevel@tonic-gate 		if (len <= 0) {
15360Sstevel@tonic-gate 			/*
15370Sstevel@tonic-gate 			 * If we have processed all of the data in the message
15380Sstevel@tonic-gate 			 * or the block is empty to begin with, then we're
15390Sstevel@tonic-gate 			 * done with this block and can go on to cont_mp,
15400Sstevel@tonic-gate 			 * if there is one.
15410Sstevel@tonic-gate 			 *
15420Sstevel@tonic-gate 			 * First, we check to see if the current block is
15430Sstevel@tonic-gate 			 * now zero-length and, if so, we free it.
15440Sstevel@tonic-gate 			 * This happens when either the block was empty
15450Sstevel@tonic-gate 			 * to begin with or we consumed all of the data
15460Sstevel@tonic-gate 			 * for the record marking header.
15470Sstevel@tonic-gate 			 */
15480Sstevel@tonic-gate 			if (rptr <= mp->b_rptr) {
15490Sstevel@tonic-gate 				/*
15500Sstevel@tonic-gate 				 * If head_mp is non-NULL, add cont_mp to the
15510Sstevel@tonic-gate 				 * mblk list. XXX But there is a possibility
15520Sstevel@tonic-gate 				 * that tail_mp = mp or even head_mp = mp XXX
15530Sstevel@tonic-gate 				 */
15540Sstevel@tonic-gate 				if (head_mp) {
15550Sstevel@tonic-gate 					if (head_mp == mp)
15560Sstevel@tonic-gate 						head_mp = NULL;
15570Sstevel@tonic-gate 					else if (tail_mp != mp) {
15580Sstevel@tonic-gate 		ASSERT((tail_mp->b_cont == NULL) || (tail_mp->b_cont == mp));
15590Sstevel@tonic-gate 						tail_mp->b_cont = cont_mp;
15600Sstevel@tonic-gate 						/*
15610Sstevel@tonic-gate 						 * It's possible that, because
15620Sstevel@tonic-gate 						 * of a very short mblk (0-3
15630Sstevel@tonic-gate 						 * bytes), we've ended up here
15640Sstevel@tonic-gate 						 * and that cont_mp could be
15650Sstevel@tonic-gate 						 * NULL (if we're at the end
15660Sstevel@tonic-gate 						 * of an mblk chain). If so,
15670Sstevel@tonic-gate 						 * don't set tail_mp to
15680Sstevel@tonic-gate 						 * cont_mp, because the next
15690Sstevel@tonic-gate 						 * time we access it, we'll
15700Sstevel@tonic-gate 						 * dereference a NULL pointer
15710Sstevel@tonic-gate 						 * and crash. Just leave
15720Sstevel@tonic-gate 						 * tail_mp pointing at the
15730Sstevel@tonic-gate 						 * current end of chain.
15740Sstevel@tonic-gate 						 */
15750Sstevel@tonic-gate 						if (cont_mp)
15760Sstevel@tonic-gate 							tail_mp = cont_mp;
15770Sstevel@tonic-gate 					} else {
15780Sstevel@tonic-gate 						mblk_t *smp = head_mp;
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 						while ((smp->b_cont != NULL) &&
15810Sstevel@tonic-gate 							(smp->b_cont != mp))
15820Sstevel@tonic-gate 							smp = smp->b_cont;
15830Sstevel@tonic-gate 						smp->b_cont = cont_mp;
15840Sstevel@tonic-gate 						/*
15850Sstevel@tonic-gate 						 * Don't set tail_mp to cont_mp
15860Sstevel@tonic-gate 						 * if it's NULL. Instead, set
15870Sstevel@tonic-gate 						 * tail_mp to smp, which is the
15880Sstevel@tonic-gate 						 * end of the chain starting
15890Sstevel@tonic-gate 						 * at head_mp.
15900Sstevel@tonic-gate 						 */
15910Sstevel@tonic-gate 						if (cont_mp)
15920Sstevel@tonic-gate 							tail_mp = cont_mp;
15930Sstevel@tonic-gate 						else
15940Sstevel@tonic-gate 							tail_mp = smp;
15950Sstevel@tonic-gate 					}
15960Sstevel@tonic-gate 				}
15970Sstevel@tonic-gate 				freeb(mp);
15980Sstevel@tonic-gate 			}
15990Sstevel@tonic-gate 			continue;
16000Sstevel@tonic-gate 		}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 		/*
16030Sstevel@tonic-gate 		 * frag_len starts at -4 and is incremented past the record
16040Sstevel@tonic-gate 		 * marking header to 0, and then becomes positive as real data
16050Sstevel@tonic-gate 		 * bytes are received for the message.  While frag_len is less
16060Sstevel@tonic-gate 		 * than zero, we need more bytes for the record marking
16070Sstevel@tonic-gate 		 * header.
16080Sstevel@tonic-gate 		 */
16090Sstevel@tonic-gate 		if (frag_len < 0) {
16100Sstevel@tonic-gate 			uchar_t	*up = rptr;
16110Sstevel@tonic-gate 			/*
16120Sstevel@tonic-gate 			 * Collect as many bytes as we need for the record
16130Sstevel@tonic-gate 			 * marking header and that are available in this block.
16140Sstevel@tonic-gate 			 */
16150Sstevel@tonic-gate 			do {
16160Sstevel@tonic-gate 				--len;
16170Sstevel@tonic-gate 				frag_len++;
16180Sstevel@tonic-gate 				frag_header <<= 8;
16190Sstevel@tonic-gate 				frag_header += (*up++ & 0xFF);
16200Sstevel@tonic-gate 			} while (len > 0 && frag_len < 0);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 			if (rptr == mp->b_rptr) {
16230Sstevel@tonic-gate 				/*
16240Sstevel@tonic-gate 				 * The record header is located at the
16250Sstevel@tonic-gate 				 * beginning of the block, so just walk
16260Sstevel@tonic-gate 				 * b_rptr past it.
16270Sstevel@tonic-gate 				 */
16280Sstevel@tonic-gate 				mp->b_rptr = rptr = up;
16290Sstevel@tonic-gate 			} else {
16300Sstevel@tonic-gate 				/*
16310Sstevel@tonic-gate 				 * The record header is located in the middle
16320Sstevel@tonic-gate 				 * of a block, so copy any remaining data up.
16330Sstevel@tonic-gate 				 * This happens when an RPC message is
16340Sstevel@tonic-gate 				 * fragmented into multiple pieces and
16350Sstevel@tonic-gate 				 * a middle (or end) fragment immediately
16360Sstevel@tonic-gate 				 * follows a previous fragment in the same
16370Sstevel@tonic-gate 				 * message block.
16380Sstevel@tonic-gate 				 */
16390Sstevel@tonic-gate 				wptr = &rptr[len];
16400Sstevel@tonic-gate 				mp->b_wptr = wptr;
16410Sstevel@tonic-gate 				if (len) {
16420Sstevel@tonic-gate 					RPCLOG(32, "mir_do_rput: copying %d "
16430Sstevel@tonic-gate 					    "bytes of data up", len);
16440Sstevel@tonic-gate 					RPCLOG(32, " db_ref %d\n",
16450Sstevel@tonic-gate 					    (uint_t)mp->b_datap->db_ref);
16460Sstevel@tonic-gate 					bcopy(up, rptr, len);
16470Sstevel@tonic-gate 				}
16480Sstevel@tonic-gate 			}
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 			/*
16510Sstevel@tonic-gate 			 * If we haven't received the complete record header
16520Sstevel@tonic-gate 			 * yet, then loop around to get the next block in the
16530Sstevel@tonic-gate 			 * STREAMS message. The logic at same_mblk label will
16540Sstevel@tonic-gate 			 * free the current block if it has become empty.
16550Sstevel@tonic-gate 			 */
16560Sstevel@tonic-gate 			if (frag_len < 0) {
16570Sstevel@tonic-gate 				RPCLOG(32, "mir_do_rput: frag_len is still < 0 "
16580Sstevel@tonic-gate 				"(%d)", len);
16590Sstevel@tonic-gate 				goto same_mblk;
16600Sstevel@tonic-gate 			}
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate #ifdef	RPCDEBUG
16630Sstevel@tonic-gate 			if ((frag_header & MIR_LASTFRAG) == 0) {
16640Sstevel@tonic-gate 				RPCLOG0(32, "mir_do_rput: multi-fragment "
16650Sstevel@tonic-gate 				    "record\n");
16660Sstevel@tonic-gate 			}
16670Sstevel@tonic-gate 			{
16680Sstevel@tonic-gate 				uint_t l = frag_header & ~MIR_LASTFRAG;
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 				if (l != 0 && mir->mir_max_msg_sizep &&
16710Sstevel@tonic-gate 				    l >= *mir->mir_max_msg_sizep) {
16720Sstevel@tonic-gate 					RPCLOG(32, "mir_do_rput: fragment size"
16730Sstevel@tonic-gate 					    " (%d) > maximum", l);
16740Sstevel@tonic-gate 					RPCLOG(32, " (%u)\n",
16750Sstevel@tonic-gate 					    *mir->mir_max_msg_sizep);
16760Sstevel@tonic-gate 				}
16770Sstevel@tonic-gate 			}
16780Sstevel@tonic-gate #endif
16790Sstevel@tonic-gate 			/*
16800Sstevel@tonic-gate 			 * At this point we have retrieved the complete record
16810Sstevel@tonic-gate 			 * header for this fragment.  If the current block is
16820Sstevel@tonic-gate 			 * empty, then we need to free it and walk to the next
16830Sstevel@tonic-gate 			 * block.
16840Sstevel@tonic-gate 			 */
16850Sstevel@tonic-gate 			if (mp->b_rptr >= wptr) {
16860Sstevel@tonic-gate 				/*
16870Sstevel@tonic-gate 				 * If this is not the last fragment or if we
16880Sstevel@tonic-gate 				 * have not received all the data for this
16890Sstevel@tonic-gate 				 * RPC message, then loop around to the next
16900Sstevel@tonic-gate 				 * block.
16910Sstevel@tonic-gate 				 */
16920Sstevel@tonic-gate 				if (!(frag_header & MIR_LASTFRAG) ||
16930Sstevel@tonic-gate 					(frag_len -
16940Sstevel@tonic-gate 					(frag_header & ~MIR_LASTFRAG)) ||
16950Sstevel@tonic-gate 					!head_mp)
16960Sstevel@tonic-gate 					goto same_mblk;
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 				/*
16990Sstevel@tonic-gate 				 * Quick walk to next block in the
17000Sstevel@tonic-gate 				 * STREAMS message.
17010Sstevel@tonic-gate 				 */
17020Sstevel@tonic-gate 				freeb(mp);
17030Sstevel@tonic-gate 				continue;
17040Sstevel@tonic-gate 			}
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		/*
17080Sstevel@tonic-gate 		 * We've collected the complete record header.  The data
17090Sstevel@tonic-gate 		 * in the current block is added to the end of the RPC
17100Sstevel@tonic-gate 		 * message.  Note that tail_mp is the same as mp after
17110Sstevel@tonic-gate 		 * this linkage.
17120Sstevel@tonic-gate 		 */
17130Sstevel@tonic-gate 		if (!head_mp)
17140Sstevel@tonic-gate 			head_mp = mp;
17150Sstevel@tonic-gate 		else if (tail_mp != mp) {
17160Sstevel@tonic-gate 			ASSERT((tail_mp->b_cont == NULL) ||
17170Sstevel@tonic-gate 			    (tail_mp->b_cont == mp));
17180Sstevel@tonic-gate 			tail_mp->b_cont = mp;
17190Sstevel@tonic-gate 		}
17200Sstevel@tonic-gate 		tail_mp = mp;
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 		/*
17230Sstevel@tonic-gate 		 * Add the length of this block to the accumulated
17240Sstevel@tonic-gate 		 * fragment length.
17250Sstevel@tonic-gate 		 */
17260Sstevel@tonic-gate 		frag_len += len;
17270Sstevel@tonic-gate 		excess = frag_len - (frag_header & ~MIR_LASTFRAG);
17280Sstevel@tonic-gate 		/*
17290Sstevel@tonic-gate 		 * If we have not received all the data for this fragment,
17300Sstevel@tonic-gate 		 * then walk to the next block.
17310Sstevel@tonic-gate 		 */
17320Sstevel@tonic-gate 		if (excess < 0)
17330Sstevel@tonic-gate 			continue;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 		/*
17360Sstevel@tonic-gate 		 * We've received a complete fragment, so reset frag_len
17370Sstevel@tonic-gate 		 * for the next one.
17380Sstevel@tonic-gate 		 */
17390Sstevel@tonic-gate 		frag_len = -(int32_t)sizeof (uint32_t);
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate 		/*
17420Sstevel@tonic-gate 		 * Update rptr to point to the beginning of the next
17430Sstevel@tonic-gate 		 * fragment in this block.  If there are no more bytes
17440Sstevel@tonic-gate 		 * in the block (excess is 0), then rptr will be equal
17450Sstevel@tonic-gate 		 * to wptr.
17460Sstevel@tonic-gate 		 */
17470Sstevel@tonic-gate 		rptr = wptr - excess;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 		/*
17500Sstevel@tonic-gate 		 * Now we check to see if this fragment is the last one in
17510Sstevel@tonic-gate 		 * the RPC message.
17520Sstevel@tonic-gate 		 */
17530Sstevel@tonic-gate 		if (!(frag_header & MIR_LASTFRAG)) {
17540Sstevel@tonic-gate 			/*
17550Sstevel@tonic-gate 			 * This isn't the last one, so start processing the
17560Sstevel@tonic-gate 			 * next fragment.
17570Sstevel@tonic-gate 			 */
17580Sstevel@tonic-gate 			frag_header = 0;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 			/*
17610Sstevel@tonic-gate 			 * If excess is 0, the next fragment
17620Sstevel@tonic-gate 			 * starts at the beginning of the next block --
17630Sstevel@tonic-gate 			 * we "continue" to the end of the while loop and
17640Sstevel@tonic-gate 			 * walk to cont_mp.
17650Sstevel@tonic-gate 			 */
17660Sstevel@tonic-gate 			if (excess == 0)
17670Sstevel@tonic-gate 				continue;
17680Sstevel@tonic-gate 			RPCLOG0(32, "mir_do_rput: multi-fragment message with "
17690Sstevel@tonic-gate 			    "two or more fragments in one mblk\n");
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 			/*
17720Sstevel@tonic-gate 			 * If excess is non-0, then the next fragment starts
17730Sstevel@tonic-gate 			 * in this block.  rptr points to the beginning
17740Sstevel@tonic-gate 			 * of the next fragment and we "goto same_mblk"
17750Sstevel@tonic-gate 			 * to continue processing.
17760Sstevel@tonic-gate 			 */
17770Sstevel@tonic-gate 			goto same_mblk;
17780Sstevel@tonic-gate 		}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 		/*
17810Sstevel@tonic-gate 		 * We've got a complete RPC message.  Before passing it
17820Sstevel@tonic-gate 		 * upstream, check to see if there is extra data in this
17830Sstevel@tonic-gate 		 * message block. If so, then we separate the excess
17840Sstevel@tonic-gate 		 * from the complete message. The excess data is processed
17850Sstevel@tonic-gate 		 * after the current message goes upstream.
17860Sstevel@tonic-gate 		 */
17870Sstevel@tonic-gate 		if (excess > 0) {
17880Sstevel@tonic-gate 			RPCLOG(32, "mir_do_rput: end of record, but excess "
17890Sstevel@tonic-gate 			    "data (%d bytes) in this mblk. dupb/copyb "
17900Sstevel@tonic-gate 			    "needed\n", excess);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 			/* Duplicate only the overlapping block. */
17930Sstevel@tonic-gate 			mp1 = dupb(tail_mp);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 			/*
17960Sstevel@tonic-gate 			 * dupb() might have failed due to ref count wrap around
17970Sstevel@tonic-gate 			 * so try a copyb().
17980Sstevel@tonic-gate 			 */
17990Sstevel@tonic-gate 			if (mp1 == NULL)
18000Sstevel@tonic-gate 				mp1 = copyb(tail_mp);
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 			/*
18030Sstevel@tonic-gate 			 * Do not use bufcall() to schedule a "buffer
18040Sstevel@tonic-gate 			 * availability event."  The reason is that
18050Sstevel@tonic-gate 			 * bufcall() has problems.  For example, if memory
18060Sstevel@tonic-gate 			 * runs out, bufcall() itself will fail since it
18070Sstevel@tonic-gate 			 * needs to allocate memory.  The most appropriate
18080Sstevel@tonic-gate 			 * action right now is to disconnect this connection
18090Sstevel@tonic-gate 			 * as the system is under stress.  We should try to
18100Sstevel@tonic-gate 			 * free up resources.
18110Sstevel@tonic-gate 			 */
18120Sstevel@tonic-gate 			if (mp1 == NULL) {
18130Sstevel@tonic-gate 				freemsg(head_mp);
18140Sstevel@tonic-gate 				RPCLOG0(1, "mir_do_rput: dupb/copyb failed\n");
18150Sstevel@tonic-gate 				mir->mir_frag_header = 0;
18160Sstevel@tonic-gate 				mir->mir_frag_len = -(int)sizeof (uint32_t);
18170Sstevel@tonic-gate 				mir->mir_head_mp = NULL;
18180Sstevel@tonic-gate 				mir->mir_tail_mp = NULL;
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 				mir_disconnect(q, mir);
18210Sstevel@tonic-gate 				return;
18220Sstevel@tonic-gate 			}
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 			/*
18250Sstevel@tonic-gate 			 * The new message block is linked with the
18260Sstevel@tonic-gate 			 * continuation block in cont_mp.  We then point
18270Sstevel@tonic-gate 			 * cont_mp to the new block so that we will
18280Sstevel@tonic-gate 			 * process it next.
18290Sstevel@tonic-gate 			 */
18300Sstevel@tonic-gate 			mp1->b_cont = cont_mp;
18310Sstevel@tonic-gate 			cont_mp = mp1;
18320Sstevel@tonic-gate 			/*
18330Sstevel@tonic-gate 			 * Data in the new block begins at the
18340Sstevel@tonic-gate 			 * next fragment (rptr).
18350Sstevel@tonic-gate 			 */
18360Sstevel@tonic-gate 			cont_mp->b_rptr += (rptr - tail_mp->b_rptr);
18370Sstevel@tonic-gate 			ASSERT(cont_mp->b_rptr >= cont_mp->b_datap->db_base);
18380Sstevel@tonic-gate 			ASSERT(cont_mp->b_rptr <= cont_mp->b_wptr);
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 			/* Data in the current fragment ends at rptr. */
18410Sstevel@tonic-gate 			tail_mp->b_wptr = rptr;
18420Sstevel@tonic-gate 			ASSERT(tail_mp->b_wptr <= tail_mp->b_datap->db_lim);
18430Sstevel@tonic-gate 			ASSERT(tail_mp->b_wptr >= tail_mp->b_rptr);
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 		}
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 		/* tail_mp is the last block with data for this RPC message. */
18480Sstevel@tonic-gate 		tail_mp->b_cont = NULL;
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 		/* Pass the RPC message to the current consumer. */
18510Sstevel@tonic-gate 		switch (mir->mir_type) {
18520Sstevel@tonic-gate 		case RPC_CLIENT:
18530Sstevel@tonic-gate 			if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) {
18540Sstevel@tonic-gate 				/*
18550Sstevel@tonic-gate 				 * Mark this stream as active.  This marker
18560Sstevel@tonic-gate 				 * is used in mir_timer().
18570Sstevel@tonic-gate 				 */
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 				mir->mir_clntreq = 1;
18600Sstevel@tonic-gate 				mir->mir_use_timestamp = lbolt;
18610Sstevel@tonic-gate 			} else
18620Sstevel@tonic-gate 				freemsg(head_mp);
18630Sstevel@tonic-gate 			break;
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		case RPC_SERVER:
18660Sstevel@tonic-gate 			/*
18670Sstevel@tonic-gate 			 * Check for flow control before passing the
18680Sstevel@tonic-gate 			 * message to KRPC.
18690Sstevel@tonic-gate 			 */
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 			if (!mir->mir_hold_inbound) {
18720Sstevel@tonic-gate 			    if (mir->mir_krpc_cell) {
18730Sstevel@tonic-gate 				/*
18740Sstevel@tonic-gate 				 * If the reference count is 0
18750Sstevel@tonic-gate 				 * (not including this request),
18760Sstevel@tonic-gate 				 * then the stream is transitioning
18770Sstevel@tonic-gate 				 * from idle to non-idle.  In this case,
18780Sstevel@tonic-gate 				 * we cancel the idle timer.
18790Sstevel@tonic-gate 				 */
18800Sstevel@tonic-gate 				if (mir->mir_ref_cnt++ == 0)
18810Sstevel@tonic-gate 					stop_timer = B_TRUE;
18820Sstevel@tonic-gate 				if (mir_check_len(q,
18830Sstevel@tonic-gate 					(int32_t)msgdsize(mp), mp))
18840Sstevel@tonic-gate 						return;
18850Sstevel@tonic-gate 				svc_queuereq(q, head_mp); /* to KRPC */
18860Sstevel@tonic-gate 			    } else {
18870Sstevel@tonic-gate 				/*
18880Sstevel@tonic-gate 				 * Count # of times this happens. Should be
18890Sstevel@tonic-gate 				 * never, but experience shows otherwise.
18900Sstevel@tonic-gate 				 */
18910Sstevel@tonic-gate 				mir_krpc_cell_null++;
18920Sstevel@tonic-gate 				freemsg(head_mp);
18930Sstevel@tonic-gate 			    }
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 			} else {
18960Sstevel@tonic-gate 				/*
18970Sstevel@tonic-gate 				 * If the outbound side of the stream is
18980Sstevel@tonic-gate 				 * flow controlled, then hold this message
18990Sstevel@tonic-gate 				 * until client catches up. mir_hold_inbound
19000Sstevel@tonic-gate 				 * is set in mir_wput and cleared in mir_wsrv.
19010Sstevel@tonic-gate 				 */
19020Sstevel@tonic-gate 				if (srv)
19030Sstevel@tonic-gate 					(void) putbq(q, head_mp);
19040Sstevel@tonic-gate 				else
19050Sstevel@tonic-gate 					(void) putq(q, head_mp);
19060Sstevel@tonic-gate 				mir->mir_inrservice = B_TRUE;
19070Sstevel@tonic-gate 			}
19080Sstevel@tonic-gate 			break;
19090Sstevel@tonic-gate 		default:
19100Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: unknown mir_type %d\n",
19110Sstevel@tonic-gate 				mir->mir_type);
19120Sstevel@tonic-gate 			freemsg(head_mp);
19130Sstevel@tonic-gate 			break;
19140Sstevel@tonic-gate 		}
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 		/*
19170Sstevel@tonic-gate 		 * Reset head_mp and frag_header since we're starting on a
19180Sstevel@tonic-gate 		 * new RPC fragment and message.
19190Sstevel@tonic-gate 		 */
19200Sstevel@tonic-gate 		head_mp = NULL;
19210Sstevel@tonic-gate 		tail_mp = NULL;
19220Sstevel@tonic-gate 		frag_header = 0;
19230Sstevel@tonic-gate 	} while ((mp = cont_mp) != NULL);
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	/*
19260Sstevel@tonic-gate 	 * Do a sanity check on the message length.  If this message is
19270Sstevel@tonic-gate 	 * getting excessively large, shut down the connection.
19280Sstevel@tonic-gate 	 */
19290Sstevel@tonic-gate 	if (head_mp != NULL && mir->mir_setup_complete &&
19300Sstevel@tonic-gate 		mir_check_len(q, frag_len, head_mp))
19310Sstevel@tonic-gate 		return;
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	/* Save our local copies back in the mir structure. */
19340Sstevel@tonic-gate 	mir->mir_frag_header = frag_header;
19350Sstevel@tonic-gate 	mir->mir_frag_len = frag_len;
19360Sstevel@tonic-gate 	mir->mir_head_mp = head_mp;
19370Sstevel@tonic-gate 	mir->mir_tail_mp = tail_mp;
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	/*
19400Sstevel@tonic-gate 	 * The timer is stopped after the whole message chain is processed.
19410Sstevel@tonic-gate 	 * The reason is that stopping the timer releases the mir_mutex
19420Sstevel@tonic-gate 	 * lock temporarily.  This means that the request can be serviced
19430Sstevel@tonic-gate 	 * while we are still processing the message chain.  This is not
19440Sstevel@tonic-gate 	 * good.  So we stop the timer here instead.
19450Sstevel@tonic-gate 	 *
19460Sstevel@tonic-gate 	 * Note that if the timer fires before we stop it, it will not
19470Sstevel@tonic-gate 	 * do any harm as MIR_SVC_QUIESCED() is false and mir_timer()
19480Sstevel@tonic-gate 	 * will just return;
19490Sstevel@tonic-gate 	 */
19500Sstevel@tonic-gate 	if (stop_timer) {
19510Sstevel@tonic-gate 		RPCLOG(16, "mir_do_rput stopping idle timer on 0x%p because "
19520Sstevel@tonic-gate 		    "ref cnt going to non zero\n", (void *) WR(q));
19530Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
19540Sstevel@tonic-gate 	}
19550Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate static void
19590Sstevel@tonic-gate mir_rput(queue_t *q, mblk_t *mp)
19600Sstevel@tonic-gate {
19610Sstevel@tonic-gate 	mir_do_rput(q, mp, 0);
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate static void
19650Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
19680Sstevel@tonic-gate 	uint32_t	type;
19690Sstevel@tonic-gate 	uint32_t reason = 0;
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	type = ((union T_primitives *)mp->b_rptr)->type;
19740Sstevel@tonic-gate 	switch (mir->mir_type) {
19750Sstevel@tonic-gate 	case RPC_CLIENT:
19760Sstevel@tonic-gate 		switch (type) {
19770Sstevel@tonic-gate 		case T_DISCON_IND:
19780Sstevel@tonic-gate 		    reason =
19790Sstevel@tonic-gate 			((struct T_discon_ind *)(mp->b_rptr))->DISCON_reason;
19800Sstevel@tonic-gate 		    /*FALLTHROUGH*/
19810Sstevel@tonic-gate 		case T_ORDREL_IND:
19820Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
19830Sstevel@tonic-gate 			if (mir->mir_head_mp) {
19840Sstevel@tonic-gate 				freemsg(mir->mir_head_mp);
19850Sstevel@tonic-gate 				mir->mir_head_mp = (mblk_t *)0;
19860Sstevel@tonic-gate 				mir->mir_tail_mp = (mblk_t *)0;
19870Sstevel@tonic-gate 			}
19880Sstevel@tonic-gate 			/*
19890Sstevel@tonic-gate 			 * We are disconnecting, but not necessarily
19900Sstevel@tonic-gate 			 * closing. By not closing, we will fail to
19910Sstevel@tonic-gate 			 * pick up a possibly changed global timeout value,
19920Sstevel@tonic-gate 			 * unless we store it now.
19930Sstevel@tonic-gate 			 */
19940Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
19950Sstevel@tonic-gate 			mir_clnt_idle_stop(WR(q), mir);
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 			/*
19980Sstevel@tonic-gate 			 * Even though we are unconnected, we still
19990Sstevel@tonic-gate 			 * leave the idle timer going on the client. The
20000Sstevel@tonic-gate 			 * reason for is that if we've disconnected due
20010Sstevel@tonic-gate 			 * to a server-side disconnect, reset, or connection
20020Sstevel@tonic-gate 			 * timeout, there is a possibility the client may
20030Sstevel@tonic-gate 			 * retry the RPC request. This retry needs to done on
20040Sstevel@tonic-gate 			 * the same bound address for the server to interpret
20050Sstevel@tonic-gate 			 * it as such. However, we don't want
20060Sstevel@tonic-gate 			 * to wait forever for that possibility. If the
20070Sstevel@tonic-gate 			 * end-point stays unconnected for mir_idle_timeout
20080Sstevel@tonic-gate 			 * units of time, then that is a signal to the
20090Sstevel@tonic-gate 			 * connection manager to give up waiting for the
20100Sstevel@tonic-gate 			 * application (eg. NFS) to send a retry.
20110Sstevel@tonic-gate 			 */
20120Sstevel@tonic-gate 			mir_clnt_idle_start(WR(q), mir);
20130Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
20140Sstevel@tonic-gate 			clnt_dispatch_notifyall(WR(q), type, reason);
20150Sstevel@tonic-gate 			freemsg(mp);
20160Sstevel@tonic-gate 			return;
20170Sstevel@tonic-gate 		case T_ERROR_ACK:
20180Sstevel@tonic-gate 		{
20190Sstevel@tonic-gate 			struct T_error_ack	*terror;
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 			terror = (struct T_error_ack *)mp->b_rptr;
20220Sstevel@tonic-gate 			RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p",
20230Sstevel@tonic-gate 				(void *)q);
20240Sstevel@tonic-gate 			RPCLOG(1, " ERROR_prim: %s,",
20250Sstevel@tonic-gate 				rpc_tpiprim2name(terror->ERROR_prim));
20260Sstevel@tonic-gate 			RPCLOG(1, " TLI_error: %s,",
20270Sstevel@tonic-gate 				rpc_tpierr2name(terror->TLI_error));
20280Sstevel@tonic-gate 			RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error);
20290Sstevel@tonic-gate 			if (terror->ERROR_prim == T_DISCON_REQ)  {
20300Sstevel@tonic-gate 				clnt_dispatch_notifyall(WR(q), type, reason);
20310Sstevel@tonic-gate 				freemsg(mp);
20320Sstevel@tonic-gate 				return;
20330Sstevel@tonic-gate 			} else {
20340Sstevel@tonic-gate 				if (clnt_dispatch_notifyconn(WR(q), mp))
20350Sstevel@tonic-gate 					return;
20360Sstevel@tonic-gate 			}
20370Sstevel@tonic-gate 			break;
20380Sstevel@tonic-gate 		}
20390Sstevel@tonic-gate 		case T_OK_ACK:
20400Sstevel@tonic-gate 		{
20410Sstevel@tonic-gate 			struct T_ok_ack	*tok = (struct T_ok_ack *)mp->b_rptr;
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 			if (tok->CORRECT_prim == T_DISCON_REQ) {
20440Sstevel@tonic-gate 				clnt_dispatch_notifyall(WR(q), type, reason);
20450Sstevel@tonic-gate 				freemsg(mp);
20460Sstevel@tonic-gate 				return;
20470Sstevel@tonic-gate 			} else {
20480Sstevel@tonic-gate 				if (clnt_dispatch_notifyconn(WR(q), mp))
20490Sstevel@tonic-gate 					return;
20500Sstevel@tonic-gate 			}
20510Sstevel@tonic-gate 			break;
20520Sstevel@tonic-gate 		}
20530Sstevel@tonic-gate 		case T_CONN_CON:
20540Sstevel@tonic-gate 		case T_INFO_ACK:
20550Sstevel@tonic-gate 		case T_OPTMGMT_ACK:
20560Sstevel@tonic-gate 			if (clnt_dispatch_notifyconn(WR(q), mp))
20570Sstevel@tonic-gate 				return;
20580Sstevel@tonic-gate 			break;
20590Sstevel@tonic-gate 		case T_BIND_ACK:
20600Sstevel@tonic-gate 			break;
20610Sstevel@tonic-gate 		default:
20620Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: unexpected message %d "
20630Sstevel@tonic-gate 			    "for KRPC client\n",
20640Sstevel@tonic-gate 			    ((union T_primitives *)mp->b_rptr)->type);
20650Sstevel@tonic-gate 			break;
20660Sstevel@tonic-gate 		}
20670Sstevel@tonic-gate 		break;
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	case RPC_SERVER:
20700Sstevel@tonic-gate 		switch (type) {
20710Sstevel@tonic-gate 		case T_BIND_ACK:
20720Sstevel@tonic-gate 		{
20730Sstevel@tonic-gate 			struct T_bind_ack	*tbind;
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 			/*
20760Sstevel@tonic-gate 			 * If this is a listening stream, then shut
20770Sstevel@tonic-gate 			 * off the idle timer.
20780Sstevel@tonic-gate 			 */
20790Sstevel@tonic-gate 			tbind = (struct T_bind_ack *)mp->b_rptr;
20800Sstevel@tonic-gate 			if (tbind->CONIND_number > 0) {
20810Sstevel@tonic-gate 				mutex_enter(&mir->mir_mutex);
20820Sstevel@tonic-gate 				mir_svc_idle_stop(WR(q), mir);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 				/*
20850Sstevel@tonic-gate 				 * mark this as a listen endpoint
20860Sstevel@tonic-gate 				 * for special handling.
20870Sstevel@tonic-gate 				 */
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 				mir->mir_listen_stream = 1;
20900Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
20910Sstevel@tonic-gate 			}
20920Sstevel@tonic-gate 			break;
20930Sstevel@tonic-gate 		}
20940Sstevel@tonic-gate 		case T_DISCON_IND:
20950Sstevel@tonic-gate 		case T_ORDREL_IND:
20960Sstevel@tonic-gate 			RPCLOG(16, "mir_rput_proto: got %s indication\n",
20970Sstevel@tonic-gate 				type == T_DISCON_IND ? "disconnect"
20980Sstevel@tonic-gate 				: "orderly release");
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 			/*
21010Sstevel@tonic-gate 			 * For listen endpoint just pass
21020Sstevel@tonic-gate 			 * on the message.
21030Sstevel@tonic-gate 			 */
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 			if (mir->mir_listen_stream)
21060Sstevel@tonic-gate 				break;
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 			/*
21110Sstevel@tonic-gate 			 * If client wants to break off connection, record
21120Sstevel@tonic-gate 			 * that fact.
21130Sstevel@tonic-gate 			 */
21140Sstevel@tonic-gate 			mir_svc_start_close(WR(q), mir);
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 			/*
21170Sstevel@tonic-gate 			 * If we are idle, then send the orderly release
21180Sstevel@tonic-gate 			 * or disconnect indication to nfsd.
21190Sstevel@tonic-gate 			 */
21200Sstevel@tonic-gate 			if (MIR_SVC_QUIESCED(mir)) {
21210Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
21220Sstevel@tonic-gate 				break;
21230Sstevel@tonic-gate 			}
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 			RPCLOG(16, "mir_rput_proto: not idle, so "
21260Sstevel@tonic-gate 				"disconnect/ord rel indication not passed "
21270Sstevel@tonic-gate 				"upstream on 0x%p\n", (void *)q);
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 			/*
21300Sstevel@tonic-gate 			 * Hold the indication until we get idle
21310Sstevel@tonic-gate 			 * If there already is an indication stored,
21320Sstevel@tonic-gate 			 * replace it if the new one is a disconnect. The
21330Sstevel@tonic-gate 			 * reasoning is that disconnection takes less time
21340Sstevel@tonic-gate 			 * to process, and once a client decides to
21350Sstevel@tonic-gate 			 * disconnect, we should do that.
21360Sstevel@tonic-gate 			 */
21370Sstevel@tonic-gate 			if (mir->mir_svc_pend_mp) {
21380Sstevel@tonic-gate 				if (type == T_DISCON_IND) {
21390Sstevel@tonic-gate 					RPCLOG(16, "mir_rput_proto: replacing"
21400Sstevel@tonic-gate 					    " held disconnect/ord rel"
21410Sstevel@tonic-gate 					    " indication with disconnect on"
21420Sstevel@tonic-gate 					    " 0x%p\n", (void *)q);
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate 					freemsg(mir->mir_svc_pend_mp);
21450Sstevel@tonic-gate 					mir->mir_svc_pend_mp = mp;
21460Sstevel@tonic-gate 				} else {
21470Sstevel@tonic-gate 					RPCLOG(16, "mir_rput_proto: already "
21480Sstevel@tonic-gate 					    "held a disconnect/ord rel "
21490Sstevel@tonic-gate 					    "indication. freeing ord rel "
21500Sstevel@tonic-gate 					    "ind on 0x%p\n", (void *)q);
21510Sstevel@tonic-gate 					freemsg(mp);
21520Sstevel@tonic-gate 				}
21530Sstevel@tonic-gate 			} else
21540Sstevel@tonic-gate 				mir->mir_svc_pend_mp = mp;
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
21570Sstevel@tonic-gate 			return;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 		default:
21600Sstevel@tonic-gate 			/* nfsd handles server-side non-data messages. */
21610Sstevel@tonic-gate 			break;
21620Sstevel@tonic-gate 		}
21630Sstevel@tonic-gate 		break;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	default:
21660Sstevel@tonic-gate 		break;
21670Sstevel@tonic-gate 	}
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	putnext(q, mp);
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate /*
21730Sstevel@tonic-gate  * The server-side read queues are used to hold inbound messages while
21740Sstevel@tonic-gate  * outbound flow control is exerted.  When outbound flow control is
21750Sstevel@tonic-gate  * relieved, mir_wsrv qenables the read-side queue.  Read-side queues
21760Sstevel@tonic-gate  * are not enabled by STREAMS and are explicitly noenable'ed in mir_open.
21770Sstevel@tonic-gate  *
21780Sstevel@tonic-gate  * For the server side,  we have two types of messages queued. The first type
21790Sstevel@tonic-gate  * are messages that are ready to be XDR decoded and and then sent to the
21800Sstevel@tonic-gate  * RPC program's dispatch routine. The second type are "raw" messages that
21810Sstevel@tonic-gate  * haven't been processed, i.e. assembled from rpc record fragements into
21820Sstevel@tonic-gate  * full requests. The only time we will see the second type of message
21830Sstevel@tonic-gate  * queued is if we have a memory allocation failure while processing a
21840Sstevel@tonic-gate  * a raw message. The field mir_first_non_processed_mblk will mark the
21850Sstevel@tonic-gate  * first such raw message. So the flow for server side is:
21860Sstevel@tonic-gate  *
21870Sstevel@tonic-gate  *	- send processed queued messages to kRPC until we run out or find
21880Sstevel@tonic-gate  *	  one that needs additional processing because we were short on memory
21890Sstevel@tonic-gate  *	  earlier
21900Sstevel@tonic-gate  *	- process a message that was deferred because of lack of
21910Sstevel@tonic-gate  *	  memory
21920Sstevel@tonic-gate  *	- continue processing messages until the queue empties or we
21930Sstevel@tonic-gate  *	  have to stop because of lack of memory
21940Sstevel@tonic-gate  *	- during each of the above phase, if the queue is empty and
21950Sstevel@tonic-gate  *	  there are no pending messages that were passed to the RPC
21960Sstevel@tonic-gate  *	  layer, send upstream the pending disconnect/ordrel indication if
21970Sstevel@tonic-gate  *	  there is one
21980Sstevel@tonic-gate  *
21990Sstevel@tonic-gate  * The read-side queue is also enabled by a bufcall callback if dupmsg
22000Sstevel@tonic-gate  * fails in mir_rput.
22010Sstevel@tonic-gate  */
22020Sstevel@tonic-gate static void
22030Sstevel@tonic-gate mir_rsrv(queue_t *q)
22040Sstevel@tonic-gate {
22050Sstevel@tonic-gate 	mir_t	*mir;
22060Sstevel@tonic-gate 	mblk_t	*mp;
22070Sstevel@tonic-gate 	mblk_t	*cmp = NULL;
22080Sstevel@tonic-gate 	boolean_t stop_timer = B_FALSE;
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
22110Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	mp = NULL;
22140Sstevel@tonic-gate 	switch (mir->mir_type) {
22150Sstevel@tonic-gate 	case RPC_SERVER:
22160Sstevel@tonic-gate 		if (mir->mir_ref_cnt == 0)
22170Sstevel@tonic-gate 			mir->mir_hold_inbound = 0;
22180Sstevel@tonic-gate 		if (mir->mir_hold_inbound) {
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 			ASSERT(cmp == NULL);
22210Sstevel@tonic-gate 			if (q->q_first == NULL) {
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 				MIR_CLEAR_INRSRV(mir);
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 				if (MIR_SVC_QUIESCED(mir)) {
22260Sstevel@tonic-gate 					cmp = mir->mir_svc_pend_mp;
22270Sstevel@tonic-gate 					mir->mir_svc_pend_mp = NULL;
22280Sstevel@tonic-gate 				}
22290Sstevel@tonic-gate 			}
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 			if (cmp != NULL) {
22340Sstevel@tonic-gate 				RPCLOG(16, "mir_rsrv: line %d: sending a held "
22350Sstevel@tonic-gate 				    "disconnect/ord rel indication upstream\n",
22360Sstevel@tonic-gate 				    __LINE__);
22370Sstevel@tonic-gate 				putnext(q, cmp);
22380Sstevel@tonic-gate 			}
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 			return;
22410Sstevel@tonic-gate 		}
22420Sstevel@tonic-gate 		while (mp = getq(q)) {
22430Sstevel@tonic-gate 			if (mir->mir_krpc_cell) {
22440Sstevel@tonic-gate 				/*
22450Sstevel@tonic-gate 				 * If we were idle, turn off idle timer since
22460Sstevel@tonic-gate 				 * we aren't idle any more.
22470Sstevel@tonic-gate 				 */
22480Sstevel@tonic-gate 				if (mir->mir_ref_cnt++ == 0)
22490Sstevel@tonic-gate 					stop_timer = B_TRUE;
22500Sstevel@tonic-gate 				if (mir_check_len(q,
22510Sstevel@tonic-gate 					(int32_t)msgdsize(mp), mp))
22520Sstevel@tonic-gate 						return;
22530Sstevel@tonic-gate 				svc_queuereq(q, mp);
22540Sstevel@tonic-gate 			} else {
22550Sstevel@tonic-gate 				/*
22560Sstevel@tonic-gate 				 * Count # of times this happens. Should be
22570Sstevel@tonic-gate 				 * never, but experience shows otherwise.
22580Sstevel@tonic-gate 				 */
22590Sstevel@tonic-gate 				mir_krpc_cell_null++;
22600Sstevel@tonic-gate 				freemsg(mp);
22610Sstevel@tonic-gate 			}
22620Sstevel@tonic-gate 		}
22630Sstevel@tonic-gate 		break;
22640Sstevel@tonic-gate 	case RPC_CLIENT:
22650Sstevel@tonic-gate 		break;
22660Sstevel@tonic-gate 	default:
22670Sstevel@tonic-gate 		RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type);
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 		if (q->q_first == NULL)
22700Sstevel@tonic-gate 			MIR_CLEAR_INRSRV(mir);
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 		return;
22750Sstevel@tonic-gate 	}
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 	/*
22780Sstevel@tonic-gate 	 * The timer is stopped after all the messages are processed.
22790Sstevel@tonic-gate 	 * The reason is that stopping the timer releases the mir_mutex
22800Sstevel@tonic-gate 	 * lock temporarily.  This means that the request can be serviced
22810Sstevel@tonic-gate 	 * while we are still processing the message queue.  This is not
22820Sstevel@tonic-gate 	 * good.  So we stop the timer here instead.
22830Sstevel@tonic-gate 	 */
22840Sstevel@tonic-gate 	if (stop_timer)  {
22850Sstevel@tonic-gate 		RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref "
22860Sstevel@tonic-gate 		    "cnt going to non zero\n", (void *)WR(q));
22870Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
22880Sstevel@tonic-gate 	}
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate 	if (q->q_first == NULL) {
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate 		MIR_CLEAR_INRSRV(mir);
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 		ASSERT(cmp == NULL);
22950Sstevel@tonic-gate 		if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) {
22960Sstevel@tonic-gate 			cmp = mir->mir_svc_pend_mp;
22970Sstevel@tonic-gate 			mir->mir_svc_pend_mp = NULL;
22980Sstevel@tonic-gate 		}
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 		if (cmp != NULL) {
23030Sstevel@tonic-gate 			RPCLOG(16, "mir_rsrv: line %d: sending a held "
23040Sstevel@tonic-gate 				"disconnect/ord rel indication upstream\n",
23050Sstevel@tonic-gate 				__LINE__);
23060Sstevel@tonic-gate 			putnext(q, cmp);
23070Sstevel@tonic-gate 		}
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 		return;
23100Sstevel@tonic-gate 	}
23110Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
23120Sstevel@tonic-gate }
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate static int mir_svc_policy_fails;
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate /*
23170Sstevel@tonic-gate  * Called to send an event code to nfsd/lockd so that it initiates
23180Sstevel@tonic-gate  * connection close.
23190Sstevel@tonic-gate  */
23200Sstevel@tonic-gate static int
23210Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event)
23220Sstevel@tonic-gate {
23230Sstevel@tonic-gate 	mblk_t	*mp;
23240Sstevel@tonic-gate #ifdef DEBUG
23250Sstevel@tonic-gate 	mir_t *mir = (mir_t *)q->q_ptr;
23260Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
23270Sstevel@tonic-gate #endif
23280Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
23290Sstevel@tonic-gate 
23300Sstevel@tonic-gate 	/*
23310Sstevel@tonic-gate 	 * Create an M_DATA message with the event code and pass it to the
23320Sstevel@tonic-gate 	 * Stream head (nfsd or whoever created the stream will consume it).
23330Sstevel@tonic-gate 	 */
23340Sstevel@tonic-gate 	mp = allocb(sizeof (int), BPRI_HI);
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	if (!mp) {
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 		mir_svc_policy_fails++;
23390Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_policy_notify: could not allocate event "
23400Sstevel@tonic-gate 			"%d\n", event);
23410Sstevel@tonic-gate 		return (ENOMEM);
23420Sstevel@tonic-gate 	}
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 	U32_TO_BE32(event, mp->b_rptr);
23450Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + sizeof (int);
23460Sstevel@tonic-gate 	putnext(q, mp);
23470Sstevel@tonic-gate 	return (0);
23480Sstevel@tonic-gate }
23490Sstevel@tonic-gate 
23500Sstevel@tonic-gate /*
23510Sstevel@tonic-gate  * Server side: start the close phase. We want to get this rpcmod slot in an
23520Sstevel@tonic-gate  * idle state before mir_close() is called.
23530Sstevel@tonic-gate  */
23540Sstevel@tonic-gate static void
23550Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir)
23560Sstevel@tonic-gate {
23570Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
23580Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
23590Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
23600Sstevel@tonic-gate 
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	/*
23630Sstevel@tonic-gate 	 * Do not accept any more messages.
23640Sstevel@tonic-gate 	 */
23650Sstevel@tonic-gate 	mir->mir_svc_no_more_msgs = 1;
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	/*
23680Sstevel@tonic-gate 	 * Next two statements will make the read service procedure invoke
23690Sstevel@tonic-gate 	 * svc_queuereq() on everything stuck in the streams read queue.
23700Sstevel@tonic-gate 	 * It's not necessary because enabling the write queue will
23710Sstevel@tonic-gate 	 * have the same effect, but why not speed the process along?
23720Sstevel@tonic-gate 	 */
23730Sstevel@tonic-gate 	mir->mir_hold_inbound = 0;
23740Sstevel@tonic-gate 	qenable(RD(wq));
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	/*
23770Sstevel@tonic-gate 	 * Meanwhile force the write service procedure to send the
23780Sstevel@tonic-gate 	 * responses downstream, regardless of flow control.
23790Sstevel@tonic-gate 	 */
23800Sstevel@tonic-gate 	qenable(wq);
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate /*
23840Sstevel@tonic-gate  * This routine is called directly by KRPC after a request is completed,
23850Sstevel@tonic-gate  * whether a reply was sent or the request was dropped.
23860Sstevel@tonic-gate  */
23870Sstevel@tonic-gate static void
23880Sstevel@tonic-gate mir_svc_release(queue_t *wq, mblk_t *mp)
23890Sstevel@tonic-gate {
23900Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
23910Sstevel@tonic-gate 	mblk_t	*cmp = NULL;
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
23940Sstevel@tonic-gate 	if (mp)
23950Sstevel@tonic-gate 		freemsg(mp);
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	/*
24000Sstevel@tonic-gate 	 * Start idle processing if this is the last reference.
24010Sstevel@tonic-gate 	 */
2402*2610Smaheshvs 	if ((mir->mir_ref_cnt == 1) && (mir->mir_inrservice == 0)) {
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_release starting idle timer on 0x%p "
24050Sstevel@tonic-gate 		    "because ref cnt is zero\n", (void *) wq);
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 		cmp = mir->mir_svc_pend_mp;
24080Sstevel@tonic-gate 		mir->mir_svc_pend_mp = NULL;
24090Sstevel@tonic-gate 		mir_svc_idle_start(wq, mir);
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate 
2412*2610Smaheshvs 	mir->mir_ref_cnt--;
2413*2610Smaheshvs 	ASSERT(mir->mir_ref_cnt >= 0);
2414*2610Smaheshvs 
2415*2610Smaheshvs 	/*
2416*2610Smaheshvs 	 * Wake up the thread waiting to close.
2417*2610Smaheshvs 	 */
2418*2610Smaheshvs 
2419*2610Smaheshvs 	if ((mir->mir_ref_cnt == 0) && mir->mir_closing)
2420*2610Smaheshvs 		cv_signal(&mir->mir_condvar);
2421*2610Smaheshvs 
24220Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	if (cmp) {
24250Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_release: sending a held "
24260Sstevel@tonic-gate 		    "disconnect/ord rel indication upstream on queue 0x%p\n",
24270Sstevel@tonic-gate 		    (void *)RD(wq));
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate 		putnext(RD(wq), cmp);
24300Sstevel@tonic-gate 	}
24310Sstevel@tonic-gate }
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate /*
24340Sstevel@tonic-gate  * This routine is called by server-side KRPC when it is ready to
24350Sstevel@tonic-gate  * handle inbound messages on the stream.
24360Sstevel@tonic-gate  */
24370Sstevel@tonic-gate static void
24380Sstevel@tonic-gate mir_svc_start(queue_t *wq)
24390Sstevel@tonic-gate {
24400Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
24410Sstevel@tonic-gate 
24422470Sgt29601 	/*
24432470Sgt29601 	 * no longer need to take the mir_mutex because the
24442470Sgt29601 	 * mir_setup_complete field has been moved out of
24452470Sgt29601 	 * the binary field protected by the mir_mutex.
24462470Sgt29601 	 */
24472470Sgt29601 
24480Sstevel@tonic-gate 	mir->mir_setup_complete = 1;
24490Sstevel@tonic-gate 	qenable(RD(wq));
24500Sstevel@tonic-gate }
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate /*
24530Sstevel@tonic-gate  * client side wrapper for stopping timer with normal idle timeout.
24540Sstevel@tonic-gate  */
24550Sstevel@tonic-gate static void
24560Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir)
24570Sstevel@tonic-gate {
24580Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
24590Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
24600Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_CLIENT);
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	mir_timer_stop(mir);
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate /*
24660Sstevel@tonic-gate  * client side wrapper for stopping timer with normal idle timeout.
24670Sstevel@tonic-gate  */
24680Sstevel@tonic-gate static void
24690Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir)
24700Sstevel@tonic-gate {
24710Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
24720Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
24730Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_CLIENT);
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	mir_timer_start(wq, mir, mir->mir_idle_timeout);
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate /*
24790Sstevel@tonic-gate  * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on
24800Sstevel@tonic-gate  * end-points that aren't connected.
24810Sstevel@tonic-gate  */
24820Sstevel@tonic-gate static void
24830Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq)
24840Sstevel@tonic-gate {
24850Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq);
24880Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
24890Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
24900Sstevel@tonic-gate 	mir_clnt_idle_stop(wq, mir);
24910Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate /*
24950Sstevel@tonic-gate  * Timer handler.  It handles idle timeout and memory shortage problem.
24960Sstevel@tonic-gate  */
24970Sstevel@tonic-gate static void
24980Sstevel@tonic-gate mir_timer(void *arg)
24990Sstevel@tonic-gate {
25000Sstevel@tonic-gate 	queue_t *wq = (queue_t *)arg;
25010Sstevel@tonic-gate 	mir_t *mir = (mir_t *)wq->q_ptr;
25020Sstevel@tonic-gate 	boolean_t notify;
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 	/*
25070Sstevel@tonic-gate 	 * mir_timer_call is set only when either mir_timer_[start|stop]
25080Sstevel@tonic-gate 	 * is progressing.  And mir_timer() can only be run while they
25090Sstevel@tonic-gate 	 * are progressing if the timer is being stopped.  So just
25100Sstevel@tonic-gate 	 * return.
25110Sstevel@tonic-gate 	 */
25120Sstevel@tonic-gate 	if (mir->mir_timer_call) {
25130Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
25140Sstevel@tonic-gate 		return;
25150Sstevel@tonic-gate 	}
25160Sstevel@tonic-gate 	mir->mir_timer_id = 0;
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 	switch (mir->mir_type) {
25190Sstevel@tonic-gate 	case RPC_CLIENT:
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 		/*
25220Sstevel@tonic-gate 		 * For clients, the timer fires at clnt_idle_timeout
25230Sstevel@tonic-gate 		 * intervals.  If the activity marker (mir_clntreq) is
25240Sstevel@tonic-gate 		 * zero, then the stream has been idle since the last
25250Sstevel@tonic-gate 		 * timer event and we notify KRPC.  If mir_clntreq is
25260Sstevel@tonic-gate 		 * non-zero, then the stream is active and we just
25270Sstevel@tonic-gate 		 * restart the timer for another interval.  mir_clntreq
25280Sstevel@tonic-gate 		 * is set to 1 in mir_wput for every request passed
25290Sstevel@tonic-gate 		 * downstream.
25300Sstevel@tonic-gate 		 *
25310Sstevel@tonic-gate 		 * If this was a memory shortage timer reset the idle
25320Sstevel@tonic-gate 		 * timeout regardless; the mir_clntreq will not be a
25330Sstevel@tonic-gate 		 * valid indicator.
25340Sstevel@tonic-gate 		 *
25350Sstevel@tonic-gate 		 * The timer is initially started in mir_wput during
25360Sstevel@tonic-gate 		 * RPC_CLIENT ioctl processing.
25370Sstevel@tonic-gate 		 *
25380Sstevel@tonic-gate 		 * The timer interval can be changed for individual
25390Sstevel@tonic-gate 		 * streams with the ND variable "mir_idle_timeout".
25400Sstevel@tonic-gate 		 */
25410Sstevel@tonic-gate 		if (mir->mir_clntreq > 0 && mir->mir_use_timestamp +
25420Sstevel@tonic-gate 		    MSEC_TO_TICK(mir->mir_idle_timeout) - lbolt >= 0) {
25430Sstevel@tonic-gate 			clock_t tout;
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 			tout = mir->mir_idle_timeout -
25460Sstevel@tonic-gate 				TICK_TO_MSEC(lbolt - mir->mir_use_timestamp);
25470Sstevel@tonic-gate 			if (tout < 0)
25480Sstevel@tonic-gate 				tout = 1000;
25490Sstevel@tonic-gate #if 0
25500Sstevel@tonic-gate printf("mir_timer[%d < %d + %d]: reset client timer to %d (ms)\n",
25510Sstevel@tonic-gate TICK_TO_MSEC(lbolt), TICK_TO_MSEC(mir->mir_use_timestamp),
25520Sstevel@tonic-gate mir->mir_idle_timeout, tout);
25530Sstevel@tonic-gate #endif
25540Sstevel@tonic-gate 			mir->mir_clntreq = 0;
25550Sstevel@tonic-gate 			mir_timer_start(wq, mir, tout);
25560Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
25570Sstevel@tonic-gate 			return;
25580Sstevel@tonic-gate 		}
25590Sstevel@tonic-gate #if 0
25600Sstevel@tonic-gate printf("mir_timer[%d]: doing client timeout\n", lbolt / hz);
25610Sstevel@tonic-gate #endif
25620Sstevel@tonic-gate 		/*
25630Sstevel@tonic-gate 		 * We are disconnecting, but not necessarily
25640Sstevel@tonic-gate 		 * closing. By not closing, we will fail to
25650Sstevel@tonic-gate 		 * pick up a possibly changed global timeout value,
25660Sstevel@tonic-gate 		 * unless we store it now.
25670Sstevel@tonic-gate 		 */
25680Sstevel@tonic-gate 		mir->mir_idle_timeout = clnt_idle_timeout;
25690Sstevel@tonic-gate 		mir_clnt_idle_start(wq, mir);
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
25720Sstevel@tonic-gate 		/*
25730Sstevel@tonic-gate 		 * We pass T_ORDREL_REQ as an integer value
25740Sstevel@tonic-gate 		 * to KRPC as the indication that the stream
25750Sstevel@tonic-gate 		 * is idle.  This is not a T_ORDREL_REQ message,
25760Sstevel@tonic-gate 		 * it is just a convenient value since we call
25770Sstevel@tonic-gate 		 * the same KRPC routine for T_ORDREL_INDs and
25780Sstevel@tonic-gate 		 * T_DISCON_INDs.
25790Sstevel@tonic-gate 		 */
25800Sstevel@tonic-gate 		clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0);
25810Sstevel@tonic-gate 		return;
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 	case RPC_SERVER:
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 		/*
25860Sstevel@tonic-gate 		 * For servers, the timer is only running when the stream
25870Sstevel@tonic-gate 		 * is really idle or memory is short.  The timer is started
25880Sstevel@tonic-gate 		 * by mir_wput when mir_type is set to RPC_SERVER and
25890Sstevel@tonic-gate 		 * by mir_svc_idle_start whenever the stream goes idle
25900Sstevel@tonic-gate 		 * (mir_ref_cnt == 0).  The timer is cancelled in
25910Sstevel@tonic-gate 		 * mir_rput whenever a new inbound request is passed to KRPC
25920Sstevel@tonic-gate 		 * and the stream was previously idle.
25930Sstevel@tonic-gate 		 *
25940Sstevel@tonic-gate 		 * The timer interval can be changed for individual
25950Sstevel@tonic-gate 		 * streams with the ND variable "mir_idle_timeout".
25960Sstevel@tonic-gate 		 *
25970Sstevel@tonic-gate 		 * If the stream is not idle do nothing.
25980Sstevel@tonic-gate 		 */
25990Sstevel@tonic-gate 		if (!MIR_SVC_QUIESCED(mir)) {
26000Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
26010Sstevel@tonic-gate 			return;
26020Sstevel@tonic-gate 		}
26030Sstevel@tonic-gate 
26040Sstevel@tonic-gate 		notify = !mir->mir_inrservice;
26050Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 		/*
26080Sstevel@tonic-gate 		 * If there is no packet queued up in read queue, the stream
26090Sstevel@tonic-gate 		 * is really idle so notify nfsd to close it.
26100Sstevel@tonic-gate 		 */
26110Sstevel@tonic-gate 		if (notify) {
26120Sstevel@tonic-gate 			RPCLOG(16, "mir_timer: telling stream head listener "
26130Sstevel@tonic-gate 			    "to close stream (0x%p)\n", (void *) RD(wq));
26140Sstevel@tonic-gate 			(void) mir_svc_policy_notify(RD(wq), 1);
26150Sstevel@tonic-gate 		}
26160Sstevel@tonic-gate 		return;
26170Sstevel@tonic-gate 	default:
26180Sstevel@tonic-gate 		RPCLOG(1, "mir_timer: unexpected mir_type %d\n",
26190Sstevel@tonic-gate 			mir->mir_type);
26200Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
26210Sstevel@tonic-gate 		return;
26220Sstevel@tonic-gate 	}
26230Sstevel@tonic-gate }
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate /*
26260Sstevel@tonic-gate  * Called by the RPC package to send either a call or a return, or a
26270Sstevel@tonic-gate  * transport connection request.  Adds the record marking header.
26280Sstevel@tonic-gate  */
26290Sstevel@tonic-gate static void
26300Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp)
26310Sstevel@tonic-gate {
26320Sstevel@tonic-gate 	uint_t	frag_header;
26330Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
26340Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
26350Sstevel@tonic-gate 
26360Sstevel@tonic-gate 	if (!mir) {
26370Sstevel@tonic-gate 		freemsg(mp);
26380Sstevel@tonic-gate 		return;
26390Sstevel@tonic-gate 	}
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_DATA) {
26420Sstevel@tonic-gate 		mir_wput_other(q, mp);
26430Sstevel@tonic-gate 		return;
26440Sstevel@tonic-gate 	}
26450Sstevel@tonic-gate 
26460Sstevel@tonic-gate 	if (mir->mir_ordrel_pending == 1) {
26470Sstevel@tonic-gate 		freemsg(mp);
26480Sstevel@tonic-gate 		RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n",
26490Sstevel@tonic-gate 			(void *)q);
26500Sstevel@tonic-gate 		return;
26510Sstevel@tonic-gate 	}
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 	frag_header = (uint_t)DLEN(mp);
26540Sstevel@tonic-gate 	frag_header |= MIR_LASTFRAG;
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	/* Stick in the 4 byte record marking header. */
26570Sstevel@tonic-gate 	if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) ||
26580Sstevel@tonic-gate 	    !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
26590Sstevel@tonic-gate 		/*
26600Sstevel@tonic-gate 		 * Since we know that M_DATA messages are created exclusively
26610Sstevel@tonic-gate 		 * by KRPC, we expect that KRPC will leave room for our header
26620Sstevel@tonic-gate 		 * and 4 byte align which is normal for XDR.
26630Sstevel@tonic-gate 		 * If KRPC (or someone else) does not cooperate, then we
26640Sstevel@tonic-gate 		 * just throw away the message.
26650Sstevel@tonic-gate 		 */
26660Sstevel@tonic-gate 		RPCLOG(1, "mir_wput: KRPC did not leave space for record "
26670Sstevel@tonic-gate 		    "fragment header (%d bytes left)\n",
26680Sstevel@tonic-gate 		    (int)(rptr - mp->b_datap->db_base));
26690Sstevel@tonic-gate 		freemsg(mp);
26700Sstevel@tonic-gate 		return;
26710Sstevel@tonic-gate 	}
26720Sstevel@tonic-gate 	rptr -= sizeof (uint32_t);
26730Sstevel@tonic-gate 	*(uint32_t *)rptr = htonl(frag_header);
26740Sstevel@tonic-gate 	mp->b_rptr = rptr;
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
26770Sstevel@tonic-gate 	if (mir->mir_type == RPC_CLIENT) {
26780Sstevel@tonic-gate 		/*
26790Sstevel@tonic-gate 		 * For the client, set mir_clntreq to indicate that the
26800Sstevel@tonic-gate 		 * connection is active.
26810Sstevel@tonic-gate 		 */
26820Sstevel@tonic-gate 		mir->mir_clntreq = 1;
26830Sstevel@tonic-gate 		mir->mir_use_timestamp = lbolt;
26840Sstevel@tonic-gate 	}
26850Sstevel@tonic-gate 
26860Sstevel@tonic-gate 	/*
26870Sstevel@tonic-gate 	 * If we haven't already queued some data and the downstream module
26880Sstevel@tonic-gate 	 * can accept more data, send it on, otherwise we queue the message
26890Sstevel@tonic-gate 	 * and take other actions depending on mir_type.
26900Sstevel@tonic-gate 	 */
26910Sstevel@tonic-gate 	if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) {
26920Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 		/*
26950Sstevel@tonic-gate 		 * Now we pass the RPC message downstream.
26960Sstevel@tonic-gate 		 */
26970Sstevel@tonic-gate 		putnext(q, mp);
26980Sstevel@tonic-gate 		return;
26990Sstevel@tonic-gate 	}
27000Sstevel@tonic-gate 
27010Sstevel@tonic-gate 	switch (mir->mir_type) {
27020Sstevel@tonic-gate 	case RPC_CLIENT:
27030Sstevel@tonic-gate 		/*
27040Sstevel@tonic-gate 		 * Check for a previous duplicate request on the
27050Sstevel@tonic-gate 		 * queue.  If there is one, then we throw away
27060Sstevel@tonic-gate 		 * the current message and let the previous one
27070Sstevel@tonic-gate 		 * go through.  If we can't find a duplicate, then
27080Sstevel@tonic-gate 		 * send this one.  This tap dance is an effort
27090Sstevel@tonic-gate 		 * to reduce traffic and processing requirements
27100Sstevel@tonic-gate 		 * under load conditions.
27110Sstevel@tonic-gate 		 */
27120Sstevel@tonic-gate 		if (mir_clnt_dup_request(q, mp)) {
27130Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
27140Sstevel@tonic-gate 			freemsg(mp);
27150Sstevel@tonic-gate 			return;
27160Sstevel@tonic-gate 		}
27170Sstevel@tonic-gate 		break;
27180Sstevel@tonic-gate 	case RPC_SERVER:
27190Sstevel@tonic-gate 		/*
27200Sstevel@tonic-gate 		 * Set mir_hold_inbound so that new inbound RPC
27210Sstevel@tonic-gate 		 * messages will be held until the client catches
27220Sstevel@tonic-gate 		 * up on the earlier replies.  This flag is cleared
27230Sstevel@tonic-gate 		 * in mir_wsrv after flow control is relieved;
27240Sstevel@tonic-gate 		 * the read-side queue is also enabled at that time.
27250Sstevel@tonic-gate 		 */
27260Sstevel@tonic-gate 		mir->mir_hold_inbound = 1;
27270Sstevel@tonic-gate 		break;
27280Sstevel@tonic-gate 	default:
27290Sstevel@tonic-gate 		RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type);
27300Sstevel@tonic-gate 		break;
27310Sstevel@tonic-gate 	}
27320Sstevel@tonic-gate 	mir->mir_inwservice = 1;
27330Sstevel@tonic-gate 	(void) putq(q, mp);
27340Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
27350Sstevel@tonic-gate }
27360Sstevel@tonic-gate 
27370Sstevel@tonic-gate static void
27380Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp)
27390Sstevel@tonic-gate {
27400Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
27410Sstevel@tonic-gate 	struct iocblk	*iocp;
27420Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
27430Sstevel@tonic-gate 	bool_t	flush_in_svc = FALSE;
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
27460Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
27470Sstevel@tonic-gate 	case M_IOCTL:
27480Sstevel@tonic-gate 		iocp = (struct iocblk *)rptr;
27490Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
27500Sstevel@tonic-gate 		case RPC_CLIENT:
27510Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
27520Sstevel@tonic-gate 			if (mir->mir_type != 0 &&
27530Sstevel@tonic-gate 			    mir->mir_type != iocp->ioc_cmd) {
27540Sstevel@tonic-gate ioc_eperm:
27550Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
27560Sstevel@tonic-gate 				iocp->ioc_error = EPERM;
27570Sstevel@tonic-gate 				iocp->ioc_count = 0;
27580Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCACK;
27590Sstevel@tonic-gate 				qreply(q, mp);
27600Sstevel@tonic-gate 				return;
27610Sstevel@tonic-gate 			}
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 			mir->mir_type = iocp->ioc_cmd;
27640Sstevel@tonic-gate 
27650Sstevel@tonic-gate 			/*
27660Sstevel@tonic-gate 			 * Clear mir_hold_inbound which was set to 1 by
27670Sstevel@tonic-gate 			 * mir_open.  This flag is not used on client
27680Sstevel@tonic-gate 			 * streams.
27690Sstevel@tonic-gate 			 */
27700Sstevel@tonic-gate 			mir->mir_hold_inbound = 0;
27710Sstevel@tonic-gate 			mir->mir_max_msg_sizep = &clnt_max_msg_size;
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 			/*
27740Sstevel@tonic-gate 			 * Start the idle timer.  See mir_timer() for more
27750Sstevel@tonic-gate 			 * information on how client timers work.
27760Sstevel@tonic-gate 			 */
27770Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
27780Sstevel@tonic-gate 			mir_clnt_idle_start(q, mir);
27790Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
27800Sstevel@tonic-gate 
27810Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
27820Sstevel@tonic-gate 			qreply(q, mp);
27830Sstevel@tonic-gate 			return;
27840Sstevel@tonic-gate 		case RPC_SERVER:
27850Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
27860Sstevel@tonic-gate 			if (mir->mir_type != 0 &&
27870Sstevel@tonic-gate 			    mir->mir_type != iocp->ioc_cmd)
27880Sstevel@tonic-gate 				goto ioc_eperm;
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate 			/*
27910Sstevel@tonic-gate 			 * We don't clear mir_hold_inbound here because
27920Sstevel@tonic-gate 			 * mir_hold_inbound is used in the flow control
27930Sstevel@tonic-gate 			 * model. If we cleared it here, then we'd commit
27940Sstevel@tonic-gate 			 * a small violation to the model where the transport
27950Sstevel@tonic-gate 			 * might immediately block downstream flow.
27960Sstevel@tonic-gate 			 */
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 			mir->mir_type = iocp->ioc_cmd;
27990Sstevel@tonic-gate 			mir->mir_max_msg_sizep = &svc_max_msg_size;
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 			/*
28020Sstevel@tonic-gate 			 * Start the idle timer.  See mir_timer() for more
28030Sstevel@tonic-gate 			 * information on how server timers work.
28040Sstevel@tonic-gate 			 *
28050Sstevel@tonic-gate 			 * Note that it is important to start the idle timer
28060Sstevel@tonic-gate 			 * here so that connections time out even if we
28070Sstevel@tonic-gate 			 * never receive any data on them.
28080Sstevel@tonic-gate 			 */
28090Sstevel@tonic-gate 			mir->mir_idle_timeout = svc_idle_timeout;
28100Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other starting idle timer on 0x%p "
28110Sstevel@tonic-gate 			    "because we got RPC_SERVER ioctl\n", (void *)q);
28120Sstevel@tonic-gate 			mir_svc_idle_start(q, mir);
28130Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
28160Sstevel@tonic-gate 			qreply(q, mp);
28170Sstevel@tonic-gate 			return;
28180Sstevel@tonic-gate 		default:
28190Sstevel@tonic-gate 			break;
28200Sstevel@tonic-gate 		}
28210Sstevel@tonic-gate 		break;
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	case M_PROTO:
28240Sstevel@tonic-gate 		if (mir->mir_type == RPC_CLIENT) {
28250Sstevel@tonic-gate 			/*
28260Sstevel@tonic-gate 			 * We are likely being called from the context of a
28270Sstevel@tonic-gate 			 * service procedure. So we need to enqueue. However
28280Sstevel@tonic-gate 			 * enqueing may put our message behind data messages.
28290Sstevel@tonic-gate 			 * So flush the data first.
28300Sstevel@tonic-gate 			 */
28310Sstevel@tonic-gate 			flush_in_svc = TRUE;
28320Sstevel@tonic-gate 		}
28330Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) < sizeof (uint32_t) ||
28340Sstevel@tonic-gate 				!IS_P2ALIGNED(rptr, sizeof (uint32_t)))
28350Sstevel@tonic-gate 			break;
28360Sstevel@tonic-gate 
28370Sstevel@tonic-gate 		switch (((union T_primitives *)rptr)->type) {
28380Sstevel@tonic-gate 		case T_DATA_REQ:
28390Sstevel@tonic-gate 			/* Don't pass T_DATA_REQ messages downstream. */
28400Sstevel@tonic-gate 			freemsg(mp);
28410Sstevel@tonic-gate 			return;
28420Sstevel@tonic-gate 		case T_ORDREL_REQ:
28430Sstevel@tonic-gate 			RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n",
28440Sstevel@tonic-gate 			    (void *)q);
28450Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
28460Sstevel@tonic-gate 			if (mir->mir_type != RPC_SERVER) {
28470Sstevel@tonic-gate 				/*
28480Sstevel@tonic-gate 				 * We are likely being called from
28490Sstevel@tonic-gate 				 * clnt_dispatch_notifyall(). Sending
28500Sstevel@tonic-gate 				 * a T_ORDREL_REQ will result in
28510Sstevel@tonic-gate 				 * a some kind of _IND message being sent,
28520Sstevel@tonic-gate 				 * will be another call to
28530Sstevel@tonic-gate 				 * clnt_dispatch_notifyall(). To keep the stack
28540Sstevel@tonic-gate 				 * lean, queue this message.
28550Sstevel@tonic-gate 				 */
28560Sstevel@tonic-gate 				mir->mir_inwservice = 1;
28570Sstevel@tonic-gate 				(void) putq(q, mp);
28580Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
28590Sstevel@tonic-gate 				return;
28600Sstevel@tonic-gate 			}
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 			/*
28630Sstevel@tonic-gate 			 * Mark the structure such that we don't accept any
28640Sstevel@tonic-gate 			 * more requests from client. We could defer this
28650Sstevel@tonic-gate 			 * until we actually send the orderly release
28660Sstevel@tonic-gate 			 * request downstream, but all that does is delay
28670Sstevel@tonic-gate 			 * the closing of this stream.
28680Sstevel@tonic-gate 			 */
28690Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ "
28700Sstevel@tonic-gate 			    " so calling mir_svc_start_close\n", (void *)q);
28710Sstevel@tonic-gate 
28720Sstevel@tonic-gate 			mir_svc_start_close(q, mir);
28730Sstevel@tonic-gate 
28740Sstevel@tonic-gate 			/*
28750Sstevel@tonic-gate 			 * If we have sent down a T_ORDREL_REQ, don't send
28760Sstevel@tonic-gate 			 * any more.
28770Sstevel@tonic-gate 			 */
28780Sstevel@tonic-gate 			if (mir->mir_ordrel_pending) {
28790Sstevel@tonic-gate 				freemsg(mp);
28800Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
28810Sstevel@tonic-gate 				return;
28820Sstevel@tonic-gate 			}
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 			/*
28850Sstevel@tonic-gate 			 * If the stream is not idle, then we hold the
28860Sstevel@tonic-gate 			 * orderly release until it becomes idle.  This
28870Sstevel@tonic-gate 			 * ensures that KRPC will be able to reply to
28880Sstevel@tonic-gate 			 * all requests that we have passed to it.
28890Sstevel@tonic-gate 			 *
28900Sstevel@tonic-gate 			 * We also queue the request if there is data already
28910Sstevel@tonic-gate 			 * queued, because we cannot allow the T_ORDREL_REQ
28920Sstevel@tonic-gate 			 * to go before data. When we had a separate reply
28930Sstevel@tonic-gate 			 * count, this was not a problem, because the
28940Sstevel@tonic-gate 			 * reply count was reconciled when mir_wsrv()
28950Sstevel@tonic-gate 			 * completed.
28960Sstevel@tonic-gate 			 */
28970Sstevel@tonic-gate 			if (!MIR_SVC_QUIESCED(mir) ||
28980Sstevel@tonic-gate 			    mir->mir_inwservice == 1) {
28990Sstevel@tonic-gate 				mir->mir_inwservice = 1;
29000Sstevel@tonic-gate 				(void) putq(q, mp);
29010Sstevel@tonic-gate 
29020Sstevel@tonic-gate 				RPCLOG(16, "mir_wput_other: queuing "
29030Sstevel@tonic-gate 				    "T_ORDREL_REQ on 0x%p\n", (void *)q);
29040Sstevel@tonic-gate 
29050Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
29060Sstevel@tonic-gate 				return;
29070Sstevel@tonic-gate 			}
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate 			/*
29100Sstevel@tonic-gate 			 * Mark the structure so that we know we sent
29110Sstevel@tonic-gate 			 * an orderly release request, and reset the idle timer.
29120Sstevel@tonic-gate 			 */
29130Sstevel@tonic-gate 			mir->mir_ordrel_pending = 1;
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start"
29160Sstevel@tonic-gate 			    " on 0x%p because we got T_ORDREL_REQ\n",
29170Sstevel@tonic-gate 			    (void *)q);
29180Sstevel@tonic-gate 
29190Sstevel@tonic-gate 			mir_svc_idle_start(q, mir);
29200Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
29210Sstevel@tonic-gate 
29220Sstevel@tonic-gate 			/*
29230Sstevel@tonic-gate 			 * When we break, we will putnext the T_ORDREL_REQ.
29240Sstevel@tonic-gate 			 */
29250Sstevel@tonic-gate 			break;
29260Sstevel@tonic-gate 
29270Sstevel@tonic-gate 		case T_CONN_REQ:
29280Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
29290Sstevel@tonic-gate 			if (mir->mir_head_mp != NULL) {
29300Sstevel@tonic-gate 				freemsg(mir->mir_head_mp);
29310Sstevel@tonic-gate 				mir->mir_head_mp = NULL;
29320Sstevel@tonic-gate 				mir->mir_tail_mp = NULL;
29330Sstevel@tonic-gate 			}
29340Sstevel@tonic-gate 			mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
29350Sstevel@tonic-gate 			/*
29360Sstevel@tonic-gate 			 * Restart timer in case mir_clnt_idle_do_stop() was
29370Sstevel@tonic-gate 			 * called.
29380Sstevel@tonic-gate 			 */
29390Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
29400Sstevel@tonic-gate 			mir_clnt_idle_stop(q, mir);
29410Sstevel@tonic-gate 			mir_clnt_idle_start(q, mir);
29420Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
29430Sstevel@tonic-gate 			break;
29440Sstevel@tonic-gate 
29450Sstevel@tonic-gate 		default:
29460Sstevel@tonic-gate 			/*
29470Sstevel@tonic-gate 			 * T_DISCON_REQ is one of the interesting default
29480Sstevel@tonic-gate 			 * cases here. Ideally, an M_FLUSH is done before
29490Sstevel@tonic-gate 			 * T_DISCON_REQ is done. However, that is somewhat
29500Sstevel@tonic-gate 			 * cumbersome for clnt_cots.c to do. So we queue
29510Sstevel@tonic-gate 			 * T_DISCON_REQ, and let the service procedure
29520Sstevel@tonic-gate 			 * flush all M_DATA.
29530Sstevel@tonic-gate 			 */
29540Sstevel@tonic-gate 			break;
29550Sstevel@tonic-gate 		}
29560Sstevel@tonic-gate 		/* fallthru */;
29570Sstevel@tonic-gate 	default:
29580Sstevel@tonic-gate 		if (mp->b_datap->db_type >= QPCTL) {
29590Sstevel@tonic-gate 			if (mp->b_datap->db_type == M_FLUSH) {
29600Sstevel@tonic-gate 				if (mir->mir_type == RPC_CLIENT &&
29610Sstevel@tonic-gate 				    *mp->b_rptr & FLUSHW) {
29620Sstevel@tonic-gate 					RPCLOG(32, "mir_wput_other: flushing "
29630Sstevel@tonic-gate 					    "wq 0x%p\n", (void *)q);
29640Sstevel@tonic-gate 					if (*mp->b_rptr & FLUSHBAND) {
29650Sstevel@tonic-gate 						flushband(q, *(mp->b_rptr + 1),
29660Sstevel@tonic-gate 							FLUSHDATA);
29670Sstevel@tonic-gate 					} else {
29680Sstevel@tonic-gate 						flushq(q, FLUSHDATA);
29690Sstevel@tonic-gate 					}
29700Sstevel@tonic-gate 				} else {
29710Sstevel@tonic-gate 					RPCLOG(32, "mir_wput_other: ignoring "
29720Sstevel@tonic-gate 					    "M_FLUSH on wq 0x%p\n", (void *)q);
29730Sstevel@tonic-gate 				}
29740Sstevel@tonic-gate 			}
29750Sstevel@tonic-gate 			break;
29760Sstevel@tonic-gate 		}
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
29790Sstevel@tonic-gate 		if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) {
29800Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
29810Sstevel@tonic-gate 			break;
29820Sstevel@tonic-gate 		}
29830Sstevel@tonic-gate 		mir->mir_inwservice = 1;
29840Sstevel@tonic-gate 		mir->mir_inwflushdata = flush_in_svc;
29850Sstevel@tonic-gate 		(void) putq(q, mp);
29860Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
29870Sstevel@tonic-gate 		qenable(q);
29880Sstevel@tonic-gate 
29890Sstevel@tonic-gate 		return;
29900Sstevel@tonic-gate 	}
29910Sstevel@tonic-gate 	putnext(q, mp);
29920Sstevel@tonic-gate }
29930Sstevel@tonic-gate 
29940Sstevel@tonic-gate static void
29950Sstevel@tonic-gate mir_wsrv(queue_t *q)
29960Sstevel@tonic-gate {
29970Sstevel@tonic-gate 	mblk_t	*mp;
29980Sstevel@tonic-gate 	mir_t	*mir;
29990Sstevel@tonic-gate 	bool_t flushdata;
30000Sstevel@tonic-gate 
30010Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
30020Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	flushdata = mir->mir_inwflushdata;
30050Sstevel@tonic-gate 	mir->mir_inwflushdata = 0;
30060Sstevel@tonic-gate 
30070Sstevel@tonic-gate 	while (mp = getq(q)) {
30080Sstevel@tonic-gate 		if (mp->b_datap->db_type == M_DATA) {
30090Sstevel@tonic-gate 			/*
30100Sstevel@tonic-gate 			 * Do not send any more data if we have sent
30110Sstevel@tonic-gate 			 * a T_ORDREL_REQ.
30120Sstevel@tonic-gate 			 */
30130Sstevel@tonic-gate 			if (flushdata || mir->mir_ordrel_pending == 1) {
30140Sstevel@tonic-gate 				freemsg(mp);
30150Sstevel@tonic-gate 				continue;
30160Sstevel@tonic-gate 			}
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate 			/*
30190Sstevel@tonic-gate 			 * Make sure that the stream can really handle more
30200Sstevel@tonic-gate 			 * data.
30210Sstevel@tonic-gate 			 */
30220Sstevel@tonic-gate 			if (!MIR_WCANPUTNEXT(mir, q)) {
30230Sstevel@tonic-gate 				(void) putbq(q, mp);
30240Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
30250Sstevel@tonic-gate 				return;
30260Sstevel@tonic-gate 			}
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate 			/*
30290Sstevel@tonic-gate 			 * Now we pass the RPC message downstream.
30300Sstevel@tonic-gate 			 */
30310Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
30320Sstevel@tonic-gate 			putnext(q, mp);
30330Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
30340Sstevel@tonic-gate 			continue;
30350Sstevel@tonic-gate 		}
30360Sstevel@tonic-gate 
30370Sstevel@tonic-gate 		/*
30380Sstevel@tonic-gate 		 * This is not an RPC message, pass it downstream
30390Sstevel@tonic-gate 		 * (ignoring flow control) if the server side is not sending a
30400Sstevel@tonic-gate 		 * T_ORDREL_REQ downstream.
30410Sstevel@tonic-gate 		 */
30420Sstevel@tonic-gate 		if (mir->mir_type != RPC_SERVER ||
30430Sstevel@tonic-gate 			    ((union T_primitives *)mp->b_rptr)->type !=
30440Sstevel@tonic-gate 			    T_ORDREL_REQ) {
30450Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
30460Sstevel@tonic-gate 			putnext(q, mp);
30470Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
30480Sstevel@tonic-gate 			continue;
30490Sstevel@tonic-gate 		}
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 		if (mir->mir_ordrel_pending == 1) {
30520Sstevel@tonic-gate 			/*
30530Sstevel@tonic-gate 			 * Don't send two T_ORDRELs
30540Sstevel@tonic-gate 			 */
30550Sstevel@tonic-gate 			freemsg(mp);
30560Sstevel@tonic-gate 			continue;
30570Sstevel@tonic-gate 		}
30580Sstevel@tonic-gate 
30590Sstevel@tonic-gate 		/*
30600Sstevel@tonic-gate 		 * Mark the structure so that we know we sent an orderly
30610Sstevel@tonic-gate 		 * release request.  We will check to see slot is idle at the
30620Sstevel@tonic-gate 		 * end of this routine, and if so, reset the idle timer to
30630Sstevel@tonic-gate 		 * handle orderly release timeouts.
30640Sstevel@tonic-gate 		 */
30650Sstevel@tonic-gate 		mir->mir_ordrel_pending = 1;
30660Sstevel@tonic-gate 		RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n",
30670Sstevel@tonic-gate 								(void *)q);
30680Sstevel@tonic-gate 		/*
30690Sstevel@tonic-gate 		 * Send the orderly release downstream. If there are other
30700Sstevel@tonic-gate 		 * pending replies we won't be able to send them.  However,
30710Sstevel@tonic-gate 		 * the only reason we should send the orderly release is if
30720Sstevel@tonic-gate 		 * we were idle, or if an unusual event occurred.
30730Sstevel@tonic-gate 		 */
30740Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
30750Sstevel@tonic-gate 		putnext(q, mp);
30760Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
30770Sstevel@tonic-gate 	}
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate 	if (q->q_first == NULL)
30800Sstevel@tonic-gate 		/*
30810Sstevel@tonic-gate 		 * If we call mir_svc_idle_start() below, then
30820Sstevel@tonic-gate 		 * clearing mir_inwservice here will also result in
30830Sstevel@tonic-gate 		 * any thread waiting in mir_close() to be signaled.
30840Sstevel@tonic-gate 		 */
30850Sstevel@tonic-gate 		mir->mir_inwservice = 0;
30860Sstevel@tonic-gate 
30870Sstevel@tonic-gate 	if (mir->mir_type != RPC_SERVER) {
30880Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
30890Sstevel@tonic-gate 		return;
30900Sstevel@tonic-gate 	}
30910Sstevel@tonic-gate 
30920Sstevel@tonic-gate 	/*
30930Sstevel@tonic-gate 	 * If idle we call mir_svc_idle_start to start the timer (or wakeup
30940Sstevel@tonic-gate 	 * a close). Also make sure not to start the idle timer on the
30950Sstevel@tonic-gate 	 * listener stream. This can cause nfsd to send an orderly release
30960Sstevel@tonic-gate 	 * command on the listener stream.
30970Sstevel@tonic-gate 	 */
30980Sstevel@tonic-gate 	if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) {
30990Sstevel@tonic-gate 		RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p "
31000Sstevel@tonic-gate 		    "because mir slot is idle\n", (void *)q);
31010Sstevel@tonic-gate 		mir_svc_idle_start(q, mir);
31020Sstevel@tonic-gate 	}
31030Sstevel@tonic-gate 
31040Sstevel@tonic-gate 	/*
31050Sstevel@tonic-gate 	 * If outbound flow control has been relieved, then allow new
31060Sstevel@tonic-gate 	 * inbound requests to be processed.
31070Sstevel@tonic-gate 	 */
31080Sstevel@tonic-gate 	if (mir->mir_hold_inbound) {
31090Sstevel@tonic-gate 		mir->mir_hold_inbound = 0;
31100Sstevel@tonic-gate 		qenable(RD(q));
31110Sstevel@tonic-gate 	}
31120Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
31130Sstevel@tonic-gate }
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate static void
31160Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir)
31170Sstevel@tonic-gate {
31180Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
31190Sstevel@tonic-gate 
31200Sstevel@tonic-gate 	switch (mir->mir_type) {
31210Sstevel@tonic-gate 	case RPC_CLIENT:
31220Sstevel@tonic-gate 		/*
31230Sstevel@tonic-gate 		 * We are disconnecting, but not necessarily
31240Sstevel@tonic-gate 		 * closing. By not closing, we will fail to
31250Sstevel@tonic-gate 		 * pick up a possibly changed global timeout value,
31260Sstevel@tonic-gate 		 * unless we store it now.
31270Sstevel@tonic-gate 		 */
31280Sstevel@tonic-gate 		mir->mir_idle_timeout = clnt_idle_timeout;
31290Sstevel@tonic-gate 		mir_clnt_idle_start(WR(q), mir);
31300Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
31310Sstevel@tonic-gate 
31320Sstevel@tonic-gate 		/*
31330Sstevel@tonic-gate 		 * T_DISCON_REQ is passed to KRPC as an integer value
31340Sstevel@tonic-gate 		 * (this is not a TPI message).  It is used as a
31350Sstevel@tonic-gate 		 * convenient value to indicate a sanity check
31360Sstevel@tonic-gate 		 * failure -- the same KRPC routine is also called
31370Sstevel@tonic-gate 		 * for T_DISCON_INDs and T_ORDREL_INDs.
31380Sstevel@tonic-gate 		 */
31390Sstevel@tonic-gate 		clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0);
31400Sstevel@tonic-gate 		break;
31410Sstevel@tonic-gate 
31420Sstevel@tonic-gate 	case RPC_SERVER:
31430Sstevel@tonic-gate 		mir->mir_svc_no_more_msgs = 1;
31440Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
31450Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
31460Sstevel@tonic-gate 		RPCLOG(16, "mir_disconnect: telling "
31470Sstevel@tonic-gate 			"stream head listener to disconnect stream "
31480Sstevel@tonic-gate 			"(0x%p)\n", (void *) q);
31490Sstevel@tonic-gate 		(void) mir_svc_policy_notify(q, 2);
31500Sstevel@tonic-gate 		break;
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 	default:
31530Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
31540Sstevel@tonic-gate 		break;
31550Sstevel@tonic-gate 	}
31560Sstevel@tonic-gate }
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate /*
31590Sstevel@tonic-gate  * do a sanity check on the length of the fragment.
31600Sstevel@tonic-gate  * returns 1 if bad else 0.
31610Sstevel@tonic-gate  */
31620Sstevel@tonic-gate static int
31630Sstevel@tonic-gate mir_check_len(queue_t *q, int32_t frag_len,
31640Sstevel@tonic-gate     mblk_t *head_mp)
31650Sstevel@tonic-gate {
31660Sstevel@tonic-gate 	mir_t   *mir;
31670Sstevel@tonic-gate 
31680Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
31690Sstevel@tonic-gate 
31700Sstevel@tonic-gate 	/*
31710Sstevel@tonic-gate 	 * Do a sanity check on the message length.  If this message is
31720Sstevel@tonic-gate 	 * getting excessively large, shut down the connection.
31730Sstevel@tonic-gate 	 */
31740Sstevel@tonic-gate 
31750Sstevel@tonic-gate 	if ((frag_len <= 0) || (mir->mir_max_msg_sizep == NULL) ||
31760Sstevel@tonic-gate 		(frag_len <= *mir->mir_max_msg_sizep)) {
31770Sstevel@tonic-gate 		return (0);
31780Sstevel@tonic-gate 	}
31790Sstevel@tonic-gate 
31800Sstevel@tonic-gate 	freemsg(head_mp);
31810Sstevel@tonic-gate 	mir->mir_head_mp = (mblk_t *)0;
31820Sstevel@tonic-gate 	mir->mir_frag_len = -(int)sizeof (uint32_t);
31830Sstevel@tonic-gate 	if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) {
31840Sstevel@tonic-gate 		cmn_err(CE_NOTE,
31850Sstevel@tonic-gate 		"KRPC: record fragment from %s of size(%d) exceeds "
31860Sstevel@tonic-gate 		"maximum (%u). Disconnecting",
31870Sstevel@tonic-gate 		(mir->mir_type == RPC_CLIENT) ? "server" :
31880Sstevel@tonic-gate 		(mir->mir_type == RPC_SERVER) ? "client" :
31890Sstevel@tonic-gate 		"test tool",
31900Sstevel@tonic-gate 		frag_len, *mir->mir_max_msg_sizep);
31910Sstevel@tonic-gate 	}
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	mir_disconnect(q, mir);
31940Sstevel@tonic-gate 	return (1);
31950Sstevel@tonic-gate }
3196