xref: /titanic_50/usr/src/uts/common/rpc/rpcmod.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate /*
35*7c478bd9Sstevel@tonic-gate  * Kernel RPC filtering module
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/timod.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/inline.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
64*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_com.h>
65*7c478bd9Sstevel@tonic-gate #include <inet/common.h>
66*7c478bd9Sstevel@tonic-gate #include <rpc/types.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
68*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
69*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
70*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
71*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h>
72*7c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
73*7c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
74*7c478bd9Sstevel@tonic-gate #include <rpc/rpcsys.h>
75*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_rdma.h>
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate /*
78*7c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
79*7c478bd9Sstevel@tonic-gate  */
80*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
81*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
82*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate extern struct streamtab rpcinfo;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
87*7c478bd9Sstevel@tonic-gate 	"rpcmod",
88*7c478bd9Sstevel@tonic-gate 	&rpcinfo,
89*7c478bd9Sstevel@tonic-gate 	D_NEW|D_MP,
90*7c478bd9Sstevel@tonic-gate };
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /*
93*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
94*7c478bd9Sstevel@tonic-gate  */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
97*7c478bd9Sstevel@tonic-gate 	&mod_strmodops, "rpc interface str mod", &fsw
98*7c478bd9Sstevel@tonic-gate };
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * For the RPC system call.
102*7c478bd9Sstevel@tonic-gate  */
103*7c478bd9Sstevel@tonic-gate static struct sysent rpcsysent = {
104*7c478bd9Sstevel@tonic-gate 	2,
105*7c478bd9Sstevel@tonic-gate 	SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
106*7c478bd9Sstevel@tonic-gate 	rpcsys
107*7c478bd9Sstevel@tonic-gate };
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
110*7c478bd9Sstevel@tonic-gate 	&mod_syscallops,
111*7c478bd9Sstevel@tonic-gate 	"RPC syscall",
112*7c478bd9Sstevel@tonic-gate 	&rpcsysent
113*7c478bd9Sstevel@tonic-gate };
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
116*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
117*7c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
118*7c478bd9Sstevel@tonic-gate 	"32-bit RPC syscall",
119*7c478bd9Sstevel@tonic-gate 	&rpcsysent
120*7c478bd9Sstevel@tonic-gate };
121*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
124*7c478bd9Sstevel@tonic-gate 	MODREV_1,
125*7c478bd9Sstevel@tonic-gate 	{
126*7c478bd9Sstevel@tonic-gate 		&modlsys,
127*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
128*7c478bd9Sstevel@tonic-gate 		&modlsys32,
129*7c478bd9Sstevel@tonic-gate #endif
130*7c478bd9Sstevel@tonic-gate 		&modlstrmod,
131*7c478bd9Sstevel@tonic-gate 		NULL
132*7c478bd9Sstevel@tonic-gate 	}
133*7c478bd9Sstevel@tonic-gate };
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate int
136*7c478bd9Sstevel@tonic-gate _init(void)
137*7c478bd9Sstevel@tonic-gate {
138*7c478bd9Sstevel@tonic-gate 	int error = 0;
139*7c478bd9Sstevel@tonic-gate 	callb_id_t cid;
140*7c478bd9Sstevel@tonic-gate 	int status;
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	svc_init();
143*7c478bd9Sstevel@tonic-gate 	clnt_init();
144*7c478bd9Sstevel@tonic-gate 	cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc");
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	if (error = mod_install(&modlinkage)) {
147*7c478bd9Sstevel@tonic-gate 		/*
148*7c478bd9Sstevel@tonic-gate 		 * Could not install module, cleanup previous
149*7c478bd9Sstevel@tonic-gate 		 * initialization work.
150*7c478bd9Sstevel@tonic-gate 		 */
151*7c478bd9Sstevel@tonic-gate 		clnt_fini();
152*7c478bd9Sstevel@tonic-gate 		if (cid != NULL)
153*7c478bd9Sstevel@tonic-gate 			(void) callb_delete(cid);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 		return (error);
156*7c478bd9Sstevel@tonic-gate 	}
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/*
159*7c478bd9Sstevel@tonic-gate 	 * Load up the RDMA plugins and initialize the stats. Even if the
160*7c478bd9Sstevel@tonic-gate 	 * plugins loadup fails, but rpcmod was successfully installed the
161*7c478bd9Sstevel@tonic-gate 	 * counters still get initialized.
162*7c478bd9Sstevel@tonic-gate 	 */
163*7c478bd9Sstevel@tonic-gate 	rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL);
164*7c478bd9Sstevel@tonic-gate 	mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL);
165*7c478bd9Sstevel@tonic-gate 	mt_kstat_init();
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/*
168*7c478bd9Sstevel@tonic-gate 	 * Get our identification into ldi.  This is used for loading
169*7c478bd9Sstevel@tonic-gate 	 * other modules, e.g. rpcib.
170*7c478bd9Sstevel@tonic-gate 	 */
171*7c478bd9Sstevel@tonic-gate 	status = ldi_ident_from_mod(&modlinkage, &rpcmod_li);
172*7c478bd9Sstevel@tonic-gate 	if (status != 0) {
173*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status);
174*7c478bd9Sstevel@tonic-gate 		rpcmod_li = NULL;
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	return (error);
178*7c478bd9Sstevel@tonic-gate }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*
181*7c478bd9Sstevel@tonic-gate  * The unload entry point fails, because we advertise entry points into
182*7c478bd9Sstevel@tonic-gate  * rpcmod from the rest of kRPC: rpcmod_release().
183*7c478bd9Sstevel@tonic-gate  */
184*7c478bd9Sstevel@tonic-gate int
185*7c478bd9Sstevel@tonic-gate _fini(void)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
188*7c478bd9Sstevel@tonic-gate }
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate int
191*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
192*7c478bd9Sstevel@tonic-gate {
193*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
194*7c478bd9Sstevel@tonic-gate }
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate extern int nulldev();
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate #define	RPCMOD_ID	2049
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate int rmm_open(), rmm_close();
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate /*
203*7c478bd9Sstevel@tonic-gate  * To save instructions, since STREAMS ignores the return value
204*7c478bd9Sstevel@tonic-gate  * from these functions, they are defined as void here. Kind of icky, but...
205*7c478bd9Sstevel@tonic-gate  */
206*7c478bd9Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *);
207*7c478bd9Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *);
208*7c478bd9Sstevel@tonic-gate void rmm_rsrv(queue_t *);
209*7c478bd9Sstevel@tonic-gate void rmm_wsrv(queue_t *);
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate int rpcmodopen(), rpcmodclose();
212*7c478bd9Sstevel@tonic-gate void rpcmodrput(), rpcmodwput();
213*7c478bd9Sstevel@tonic-gate void rpcmodrsrv(), rpcmodwsrv();
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate static	void	rpcmodwput_other(queue_t *, mblk_t *);
216*7c478bd9Sstevel@tonic-gate static	int	mir_close(queue_t *q);
217*7c478bd9Sstevel@tonic-gate static	int	mir_open(queue_t *q, dev_t *devp, int flag, int sflag,
218*7c478bd9Sstevel@tonic-gate 		    cred_t *credp);
219*7c478bd9Sstevel@tonic-gate static	void	mir_rput(queue_t *q, mblk_t *mp);
220*7c478bd9Sstevel@tonic-gate static	void	mir_rsrv(queue_t *q);
221*7c478bd9Sstevel@tonic-gate static	void	mir_wput(queue_t *q, mblk_t *mp);
222*7c478bd9Sstevel@tonic-gate static	void	mir_wsrv(queue_t *q);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate static struct module_info rpcmod_info =
225*7c478bd9Sstevel@tonic-gate 	{RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024};
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate /*
228*7c478bd9Sstevel@tonic-gate  * Read side has no service procedure.
229*7c478bd9Sstevel@tonic-gate  */
230*7c478bd9Sstevel@tonic-gate static struct qinit rpcmodrinit = {
231*7c478bd9Sstevel@tonic-gate 	(int (*)())rmm_rput,
232*7c478bd9Sstevel@tonic-gate 	(int (*)())rmm_rsrv,
233*7c478bd9Sstevel@tonic-gate 	rmm_open,
234*7c478bd9Sstevel@tonic-gate 	rmm_close,
235*7c478bd9Sstevel@tonic-gate 	nulldev,
236*7c478bd9Sstevel@tonic-gate 	&rpcmod_info,
237*7c478bd9Sstevel@tonic-gate 	NULL
238*7c478bd9Sstevel@tonic-gate };
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate /*
241*7c478bd9Sstevel@tonic-gate  * The write put procedure is simply putnext to conserve stack space.
242*7c478bd9Sstevel@tonic-gate  * The write service procedure is not used to queue data, but instead to
243*7c478bd9Sstevel@tonic-gate  * synchronize with flow control.
244*7c478bd9Sstevel@tonic-gate  */
245*7c478bd9Sstevel@tonic-gate static struct qinit rpcmodwinit = {
246*7c478bd9Sstevel@tonic-gate 	(int (*)())rmm_wput,
247*7c478bd9Sstevel@tonic-gate 	(int (*)())rmm_wsrv,
248*7c478bd9Sstevel@tonic-gate 	rmm_open,
249*7c478bd9Sstevel@tonic-gate 	rmm_close,
250*7c478bd9Sstevel@tonic-gate 	nulldev,
251*7c478bd9Sstevel@tonic-gate 	&rpcmod_info,
252*7c478bd9Sstevel@tonic-gate 	NULL
253*7c478bd9Sstevel@tonic-gate };
254*7c478bd9Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL };
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate struct xprt_style_ops {
257*7c478bd9Sstevel@tonic-gate 	int (*xo_open)();
258*7c478bd9Sstevel@tonic-gate 	int (*xo_close)();
259*7c478bd9Sstevel@tonic-gate 	void (*xo_wput)();
260*7c478bd9Sstevel@tonic-gate 	void (*xo_wsrv)();
261*7c478bd9Sstevel@tonic-gate 	void (*xo_rput)();
262*7c478bd9Sstevel@tonic-gate 	void (*xo_rsrv)();
263*7c478bd9Sstevel@tonic-gate };
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = {
266*7c478bd9Sstevel@tonic-gate 	rpcmodopen,
267*7c478bd9Sstevel@tonic-gate 	rpcmodclose,
268*7c478bd9Sstevel@tonic-gate 	rpcmodwput,
269*7c478bd9Sstevel@tonic-gate 	rpcmodwsrv,
270*7c478bd9Sstevel@tonic-gate 	rpcmodrput,
271*7c478bd9Sstevel@tonic-gate 	NULL
272*7c478bd9Sstevel@tonic-gate };
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = {
275*7c478bd9Sstevel@tonic-gate 	mir_open,
276*7c478bd9Sstevel@tonic-gate 	mir_close,
277*7c478bd9Sstevel@tonic-gate 	mir_wput,
278*7c478bd9Sstevel@tonic-gate 	mir_wsrv,
279*7c478bd9Sstevel@tonic-gate 	mir_rput,
280*7c478bd9Sstevel@tonic-gate 	mir_rsrv
281*7c478bd9Sstevel@tonic-gate };
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate /*
284*7c478bd9Sstevel@tonic-gate  * Per rpcmod "slot" data structure. q->q_ptr points to one of these.
285*7c478bd9Sstevel@tonic-gate  */
286*7c478bd9Sstevel@tonic-gate struct rpcm {
287*7c478bd9Sstevel@tonic-gate 	void		*rm_krpc_cell;	/* Reserved for use by KRPC */
288*7c478bd9Sstevel@tonic-gate 	struct		xprt_style_ops	*rm_ops;
289*7c478bd9Sstevel@tonic-gate 	int		rm_type;	/* Client or server side stream */
290*7c478bd9Sstevel@tonic-gate #define	RM_CLOSING	0x1		/* somebody is trying to close slot */
291*7c478bd9Sstevel@tonic-gate 	uint_t		rm_state;	/* state of the slot. see above */
292*7c478bd9Sstevel@tonic-gate 	uint_t		rm_ref;		/* cnt of external references to slot */
293*7c478bd9Sstevel@tonic-gate 	kmutex_t	rm_lock;	/* mutex protecting above fields */
294*7c478bd9Sstevel@tonic-gate 	kcondvar_t	rm_cwait;	/* condition for closing */
295*7c478bd9Sstevel@tonic-gate 	zoneid_t	rm_zoneid;	/* zone which pushed rpcmod */
296*7c478bd9Sstevel@tonic-gate };
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate struct temp_slot {
299*7c478bd9Sstevel@tonic-gate 	void *cell;
300*7c478bd9Sstevel@tonic-gate 	struct xprt_style_ops *ops;
301*7c478bd9Sstevel@tonic-gate 	int type;
302*7c478bd9Sstevel@tonic-gate 	mblk_t *info_ack;
303*7c478bd9Sstevel@tonic-gate 	kmutex_t lock;
304*7c478bd9Sstevel@tonic-gate 	kcondvar_t wait;
305*7c478bd9Sstevel@tonic-gate };
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate struct xprt_style_ops tmpops = {
310*7c478bd9Sstevel@tonic-gate 	NULL,
311*7c478bd9Sstevel@tonic-gate 	NULL,
312*7c478bd9Sstevel@tonic-gate 	putnext,
313*7c478bd9Sstevel@tonic-gate 	NULL,
314*7c478bd9Sstevel@tonic-gate 	tmp_rput,
315*7c478bd9Sstevel@tonic-gate 	NULL
316*7c478bd9Sstevel@tonic-gate };
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate void
319*7c478bd9Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate 	struct temp_slot *t = (struct temp_slot *)(q->q_ptr);
322*7c478bd9Sstevel@tonic-gate 	struct T_info_ack *pptr;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
325*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
326*7c478bd9Sstevel@tonic-gate 		pptr = (struct T_info_ack *)mp->b_rptr;
327*7c478bd9Sstevel@tonic-gate 		switch (pptr->PRIM_type) {
328*7c478bd9Sstevel@tonic-gate 		case T_INFO_ACK:
329*7c478bd9Sstevel@tonic-gate 			mutex_enter(&t->lock);
330*7c478bd9Sstevel@tonic-gate 			t->info_ack = mp;
331*7c478bd9Sstevel@tonic-gate 			cv_signal(&t->wait);
332*7c478bd9Sstevel@tonic-gate 			mutex_exit(&t->lock);
333*7c478bd9Sstevel@tonic-gate 			return;
334*7c478bd9Sstevel@tonic-gate 		default:
335*7c478bd9Sstevel@tonic-gate 			break;
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 	default:
338*7c478bd9Sstevel@tonic-gate 		break;
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/*
342*7c478bd9Sstevel@tonic-gate 	 * Not an info-ack, so free it. This is ok because we should
343*7c478bd9Sstevel@tonic-gate 	 * not be receiving data until the open finishes: rpcmod
344*7c478bd9Sstevel@tonic-gate 	 * is pushed well before the end-point is bound to an address.
345*7c478bd9Sstevel@tonic-gate 	 */
346*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate int
350*7c478bd9Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
351*7c478bd9Sstevel@tonic-gate {
352*7c478bd9Sstevel@tonic-gate 	mblk_t *bp;
353*7c478bd9Sstevel@tonic-gate 	struct temp_slot ts, *t;
354*7c478bd9Sstevel@tonic-gate 	struct T_info_ack *pptr;
355*7c478bd9Sstevel@tonic-gate 	int error = 0;
356*7c478bd9Sstevel@tonic-gate 	int procson = 0;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
359*7c478bd9Sstevel@tonic-gate 	/*
360*7c478bd9Sstevel@tonic-gate 	 * Check for re-opens.
361*7c478bd9Sstevel@tonic-gate 	 */
362*7c478bd9Sstevel@tonic-gate 	if (q->q_ptr) {
363*7c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END,
364*7c478bd9Sstevel@tonic-gate 		    "rpcmodopen_end:(%s)", "q->qptr");
365*7c478bd9Sstevel@tonic-gate 		return (0);
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	t = &ts;
369*7c478bd9Sstevel@tonic-gate 	bzero(t, sizeof (*t));
370*7c478bd9Sstevel@tonic-gate 	q->q_ptr = (void *)t;
371*7c478bd9Sstevel@tonic-gate 	/* WR(q)->q_ptr = (void *)t; */
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	/*
374*7c478bd9Sstevel@tonic-gate 	 * Allocate the required messages upfront.
375*7c478bd9Sstevel@tonic-gate 	 */
376*7c478bd9Sstevel@tonic-gate 	if ((bp = allocb(sizeof (struct T_info_req) +
377*7c478bd9Sstevel@tonic-gate 	    sizeof (struct T_info_ack), BPRI_LO)) == (mblk_t *)NULL) {
378*7c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL);
382*7c478bd9Sstevel@tonic-gate 	cv_init(&t->wait, NULL, CV_DEFAULT, NULL);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	t->ops = &tmpops;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	qprocson(q);
387*7c478bd9Sstevel@tonic-gate 	procson = 1;
388*7c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_PCPROTO;
389*7c478bd9Sstevel@tonic-gate 	*(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ;
390*7c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct T_info_req);
391*7c478bd9Sstevel@tonic-gate 	putnext(WR(q), bp);
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	mutex_enter(&t->lock);
394*7c478bd9Sstevel@tonic-gate 	while ((bp = t->info_ack) == NULL) {
395*7c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&t->wait, &t->lock) == 0) {
396*7c478bd9Sstevel@tonic-gate 			error = EINTR;
397*7c478bd9Sstevel@tonic-gate 			break;
398*7c478bd9Sstevel@tonic-gate 		}
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 	mutex_exit(&t->lock);
401*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&t->lock);
402*7c478bd9Sstevel@tonic-gate 	cv_destroy(&t->wait);
403*7c478bd9Sstevel@tonic-gate 	if (error)
404*7c478bd9Sstevel@tonic-gate 		goto out;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	pptr = (struct T_info_ack *)t->info_ack->b_rptr;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (pptr->SERV_type == T_CLTS) {
409*7c478bd9Sstevel@tonic-gate 		error = rpcmodopen(q, devp, flag, sflag, crp);
410*7c478bd9Sstevel@tonic-gate 		if (error == 0) {
411*7c478bd9Sstevel@tonic-gate 			t = (struct temp_slot *)q->q_ptr;
412*7c478bd9Sstevel@tonic-gate 			t->ops = &xprt_clts_ops;
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 	} else {
415*7c478bd9Sstevel@tonic-gate 		error = mir_open(q, devp, flag, sflag, crp);
416*7c478bd9Sstevel@tonic-gate 		if (error == 0) {
417*7c478bd9Sstevel@tonic-gate 			t = (struct temp_slot *)q->q_ptr;
418*7c478bd9Sstevel@tonic-gate 			t->ops = &xprt_cots_ops;
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate out:
423*7c478bd9Sstevel@tonic-gate 	freemsg(bp);
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	if (error && procson)
426*7c478bd9Sstevel@tonic-gate 		qprocsoff(q);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	return (error);
429*7c478bd9Sstevel@tonic-gate }
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate void
432*7c478bd9Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t  *mp)
433*7c478bd9Sstevel@tonic-gate {
434*7c478bd9Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp);
435*7c478bd9Sstevel@tonic-gate }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate void
438*7c478bd9Sstevel@tonic-gate rmm_rsrv(queue_t *q)
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q);
441*7c478bd9Sstevel@tonic-gate }
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate void
444*7c478bd9Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp)
445*7c478bd9Sstevel@tonic-gate {
446*7c478bd9Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp);
447*7c478bd9Sstevel@tonic-gate }
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate void
450*7c478bd9Sstevel@tonic-gate rmm_wsrv(queue_t *q)
451*7c478bd9Sstevel@tonic-gate {
452*7c478bd9Sstevel@tonic-gate 	(*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q);
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate int
456*7c478bd9Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp));
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate /*
462*7c478bd9Sstevel@tonic-gate  * rpcmodopen -	open routine gets called when the module gets pushed
463*7c478bd9Sstevel@tonic-gate  *		onto the stream.
464*7c478bd9Sstevel@tonic-gate  */
465*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
466*7c478bd9Sstevel@tonic-gate int
467*7c478bd9Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
468*7c478bd9Sstevel@tonic-gate {
469*7c478bd9Sstevel@tonic-gate 	struct rpcm *rmp;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	extern void (*rpc_rele)(queue_t *, mblk_t *);
472*7c478bd9Sstevel@tonic-gate 	static void rpcmod_release(queue_t *, mblk_t *);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:");
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	/*
477*7c478bd9Sstevel@tonic-gate 	 * Initialize entry points to release a rpcmod slot (and an input
478*7c478bd9Sstevel@tonic-gate 	 * message if supplied) and to send an output message to the module
479*7c478bd9Sstevel@tonic-gate 	 * below rpcmod.
480*7c478bd9Sstevel@tonic-gate 	 */
481*7c478bd9Sstevel@tonic-gate 	if (rpc_rele == NULL)
482*7c478bd9Sstevel@tonic-gate 		rpc_rele = rpcmod_release;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/*
485*7c478bd9Sstevel@tonic-gate 	 * Only sufficiently privileged users can use this module, and it
486*7c478bd9Sstevel@tonic-gate 	 * is assumed that they will use this module properly, and NOT send
487*7c478bd9Sstevel@tonic-gate 	 * bulk data from downstream.
488*7c478bd9Sstevel@tonic-gate 	 */
489*7c478bd9Sstevel@tonic-gate 	if (secpolicy_rpcmod_open(crp) != 0)
490*7c478bd9Sstevel@tonic-gate 		return (EPERM);
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	/*
493*7c478bd9Sstevel@tonic-gate 	 * Allocate slot data structure.
494*7c478bd9Sstevel@tonic-gate 	 */
495*7c478bd9Sstevel@tonic-gate 	rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP);
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL);
498*7c478bd9Sstevel@tonic-gate 	cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL);
499*7c478bd9Sstevel@tonic-gate 	rmp->rm_zoneid = getzoneid();
500*7c478bd9Sstevel@tonic-gate 	/*
501*7c478bd9Sstevel@tonic-gate 	 * slot type will be set by kRPC client and server ioctl's
502*7c478bd9Sstevel@tonic-gate 	 */
503*7c478bd9Sstevel@tonic-gate 	rmp->rm_type = 0;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	q->q_ptr = (void *)rmp;
506*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (void *)rmp;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end");
509*7c478bd9Sstevel@tonic-gate 	return (0);
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate /*
513*7c478bd9Sstevel@tonic-gate  * rpcmodclose - This routine gets called when the module gets popped
514*7c478bd9Sstevel@tonic-gate  * off of the stream.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
517*7c478bd9Sstevel@tonic-gate int
518*7c478bd9Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp)
519*7c478bd9Sstevel@tonic-gate {
520*7c478bd9Sstevel@tonic-gate 	struct rpcm *rmp;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
523*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	/*
526*7c478bd9Sstevel@tonic-gate 	 * Mark our state as closing.
527*7c478bd9Sstevel@tonic-gate 	 */
528*7c478bd9Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
529*7c478bd9Sstevel@tonic-gate 	rmp->rm_state |= RM_CLOSING;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	/*
532*7c478bd9Sstevel@tonic-gate 	 * Check and see if there are any messages on the queue.  If so, send
533*7c478bd9Sstevel@tonic-gate 	 * the messages, regardless whether the downstream module is ready to
534*7c478bd9Sstevel@tonic-gate 	 * accept data.
535*7c478bd9Sstevel@tonic-gate 	 */
536*7c478bd9Sstevel@tonic-gate 	if (rmp->rm_type == RPC_SERVER) {
537*7c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		qenable(WR(q));
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		if (rmp->rm_ref) {
542*7c478bd9Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
543*7c478bd9Sstevel@tonic-gate 			/*
544*7c478bd9Sstevel@tonic-gate 			 * call into SVC to clean the queue
545*7c478bd9Sstevel@tonic-gate 			 */
546*7c478bd9Sstevel@tonic-gate 			svc_queueclean(q);
547*7c478bd9Sstevel@tonic-gate 			mutex_enter(&rmp->rm_lock);
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 			/*
550*7c478bd9Sstevel@tonic-gate 			 * Block while there are kRPC threads with a reference
551*7c478bd9Sstevel@tonic-gate 			 * to this message.
552*7c478bd9Sstevel@tonic-gate 			 */
553*7c478bd9Sstevel@tonic-gate 			while (rmp->rm_ref)
554*7c478bd9Sstevel@tonic-gate 				cv_wait(&rmp->rm_cwait, &rmp->rm_lock);
555*7c478bd9Sstevel@tonic-gate 		}
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		/*
560*7c478bd9Sstevel@tonic-gate 		 * It is now safe to remove this queue from the stream. No kRPC
561*7c478bd9Sstevel@tonic-gate 		 * threads have a reference to the stream, and none ever will,
562*7c478bd9Sstevel@tonic-gate 		 * because RM_CLOSING is set.
563*7c478bd9Sstevel@tonic-gate 		 */
564*7c478bd9Sstevel@tonic-gate 		qprocsoff(q);
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		/* Notify kRPC that this stream is going away. */
567*7c478bd9Sstevel@tonic-gate 		svc_queueclose(q);
568*7c478bd9Sstevel@tonic-gate 	} else {
569*7c478bd9Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
570*7c478bd9Sstevel@tonic-gate 		qprocsoff(q);
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
574*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
575*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&rmp->rm_lock);
576*7c478bd9Sstevel@tonic-gate 	cv_destroy(&rmp->rm_cwait);
577*7c478bd9Sstevel@tonic-gate 	kmem_free(rmp, sizeof (*rmp));
578*7c478bd9Sstevel@tonic-gate 	return (0);
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
582*7c478bd9Sstevel@tonic-gate int	rpcmod_send_msg_up = 0;
583*7c478bd9Sstevel@tonic-gate int	rpcmod_send_uderr = 0;
584*7c478bd9Sstevel@tonic-gate int	rpcmod_send_dup = 0;
585*7c478bd9Sstevel@tonic-gate int	rpcmod_send_dup_cnt = 0;
586*7c478bd9Sstevel@tonic-gate #endif
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate /*
589*7c478bd9Sstevel@tonic-gate  * rpcmodrput -	Module read put procedure.  This is called from
590*7c478bd9Sstevel@tonic-gate  *		the module, driver, or stream head downstream.
591*7c478bd9Sstevel@tonic-gate  */
592*7c478bd9Sstevel@tonic-gate void
593*7c478bd9Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp)
594*7c478bd9Sstevel@tonic-gate {
595*7c478bd9Sstevel@tonic-gate 	struct rpcm *rmp;
596*7c478bd9Sstevel@tonic-gate 	union T_primitives *pptr;
597*7c478bd9Sstevel@tonic-gate 	int hdrsz;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:");
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
602*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	if (rmp->rm_type == 0) {
605*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
606*7c478bd9Sstevel@tonic-gate 		return;
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
610*7c478bd9Sstevel@tonic-gate 	if (rpcmod_send_msg_up > 0) {
611*7c478bd9Sstevel@tonic-gate 		mblk_t *nmp = copymsg(mp);
612*7c478bd9Sstevel@tonic-gate 		if (nmp) {
613*7c478bd9Sstevel@tonic-gate 			putnext(q, nmp);
614*7c478bd9Sstevel@tonic-gate 			rpcmod_send_msg_up--;
615*7c478bd9Sstevel@tonic-gate 		}
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 	if ((rpcmod_send_uderr > 0) && mp->b_datap->db_type == M_PROTO) {
618*7c478bd9Sstevel@tonic-gate 		mblk_t *nmp;
619*7c478bd9Sstevel@tonic-gate 		struct T_unitdata_ind *data;
620*7c478bd9Sstevel@tonic-gate 		struct T_uderror_ind *ud;
621*7c478bd9Sstevel@tonic-gate 		int d;
622*7c478bd9Sstevel@tonic-gate 		data = (struct T_unitdata_ind *)mp->b_rptr;
623*7c478bd9Sstevel@tonic-gate 		if (data->PRIM_type == T_UNITDATA_IND) {
624*7c478bd9Sstevel@tonic-gate 			d = sizeof (*ud) - sizeof (*data);
625*7c478bd9Sstevel@tonic-gate 			nmp = allocb(mp->b_wptr - mp->b_rptr + d, BPRI_HI);
626*7c478bd9Sstevel@tonic-gate 			if (nmp) {
627*7c478bd9Sstevel@tonic-gate 				ud = (struct T_uderror_ind *)nmp->b_rptr;
628*7c478bd9Sstevel@tonic-gate 				ud->PRIM_type = T_UDERROR_IND;
629*7c478bd9Sstevel@tonic-gate 				ud->DEST_length = data->SRC_length;
630*7c478bd9Sstevel@tonic-gate 				ud->DEST_offset = data->SRC_offset + d;
631*7c478bd9Sstevel@tonic-gate 				ud->OPT_length = data->OPT_length;
632*7c478bd9Sstevel@tonic-gate 				ud->OPT_offset = data->OPT_offset + d;
633*7c478bd9Sstevel@tonic-gate 				ud->ERROR_type = ENETDOWN;
634*7c478bd9Sstevel@tonic-gate 				if (data->SRC_length) {
635*7c478bd9Sstevel@tonic-gate 					bcopy(mp->b_rptr +
636*7c478bd9Sstevel@tonic-gate 					    data->SRC_offset,
637*7c478bd9Sstevel@tonic-gate 					    nmp->b_rptr +
638*7c478bd9Sstevel@tonic-gate 					    ud->DEST_offset,
639*7c478bd9Sstevel@tonic-gate 					    data->SRC_length);
640*7c478bd9Sstevel@tonic-gate 				}
641*7c478bd9Sstevel@tonic-gate 				if (data->OPT_length) {
642*7c478bd9Sstevel@tonic-gate 					bcopy(mp->b_rptr +
643*7c478bd9Sstevel@tonic-gate 					    data->OPT_offset,
644*7c478bd9Sstevel@tonic-gate 					    nmp->b_rptr +
645*7c478bd9Sstevel@tonic-gate 					    ud->OPT_offset,
646*7c478bd9Sstevel@tonic-gate 					    data->OPT_length);
647*7c478bd9Sstevel@tonic-gate 				}
648*7c478bd9Sstevel@tonic-gate 				nmp->b_wptr += d;
649*7c478bd9Sstevel@tonic-gate 				nmp->b_wptr += (mp->b_wptr - mp->b_rptr);
650*7c478bd9Sstevel@tonic-gate 				nmp->b_datap->db_type = M_PROTO;
651*7c478bd9Sstevel@tonic-gate 				putnext(q, nmp);
652*7c478bd9Sstevel@tonic-gate 				rpcmod_send_uderr--;
653*7c478bd9Sstevel@tonic-gate 			}
654*7c478bd9Sstevel@tonic-gate 		}
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate #endif
657*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
658*7c478bd9Sstevel@tonic-gate 	default:
659*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
660*7c478bd9Sstevel@tonic-gate 		break;
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
663*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
664*7c478bd9Sstevel@tonic-gate 		ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t));
665*7c478bd9Sstevel@tonic-gate 		pptr = (union T_primitives *)mp->b_rptr;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 		/*
668*7c478bd9Sstevel@tonic-gate 		 * Forward this message to krpc if it is data.
669*7c478bd9Sstevel@tonic-gate 		 */
670*7c478bd9Sstevel@tonic-gate 		if (pptr->type == T_UNITDATA_IND) {
671*7c478bd9Sstevel@tonic-gate 		    mblk_t *nmp;
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 		/*
674*7c478bd9Sstevel@tonic-gate 		 * Check if the module is being popped.
675*7c478bd9Sstevel@tonic-gate 		 */
676*7c478bd9Sstevel@tonic-gate 		    mutex_enter(&rmp->rm_lock);
677*7c478bd9Sstevel@tonic-gate 		    if (rmp->rm_state & RM_CLOSING) {
678*7c478bd9Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
679*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
680*7c478bd9Sstevel@tonic-gate 			break;
681*7c478bd9Sstevel@tonic-gate 		    }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 		    switch (rmp->rm_type) {
684*7c478bd9Sstevel@tonic-gate 		    case RPC_CLIENT:
685*7c478bd9Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
686*7c478bd9Sstevel@tonic-gate 			hdrsz = mp->b_wptr - mp->b_rptr;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 			/*
689*7c478bd9Sstevel@tonic-gate 			 * Make sure the header is sane.
690*7c478bd9Sstevel@tonic-gate 			 */
691*7c478bd9Sstevel@tonic-gate 			if (hdrsz < TUNITDATAINDSZ ||
692*7c478bd9Sstevel@tonic-gate 				hdrsz < (pptr->unitdata_ind.OPT_length +
693*7c478bd9Sstevel@tonic-gate 					pptr->unitdata_ind.OPT_offset) ||
694*7c478bd9Sstevel@tonic-gate 				hdrsz < (pptr->unitdata_ind.SRC_length +
695*7c478bd9Sstevel@tonic-gate 					pptr->unitdata_ind.SRC_offset)) {
696*7c478bd9Sstevel@tonic-gate 					freemsg(mp);
697*7c478bd9Sstevel@tonic-gate 					return;
698*7c478bd9Sstevel@tonic-gate 			}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 			/*
701*7c478bd9Sstevel@tonic-gate 			 * Call clnt_clts_dispatch_notify, so that it can
702*7c478bd9Sstevel@tonic-gate 			 * pass the message to the proper caller.  Don't
703*7c478bd9Sstevel@tonic-gate 			 * discard the header just yet since the client may
704*7c478bd9Sstevel@tonic-gate 			 * need the sender's address.
705*7c478bd9Sstevel@tonic-gate 			 */
706*7c478bd9Sstevel@tonic-gate 			clnt_clts_dispatch_notify(mp, hdrsz, rmp->rm_zoneid);
707*7c478bd9Sstevel@tonic-gate 			return;
708*7c478bd9Sstevel@tonic-gate 		    case RPC_SERVER:
709*7c478bd9Sstevel@tonic-gate 			/*
710*7c478bd9Sstevel@tonic-gate 			 * rm_krpc_cell is exclusively used by the kRPC
711*7c478bd9Sstevel@tonic-gate 			 * CLTS server
712*7c478bd9Sstevel@tonic-gate 			 */
713*7c478bd9Sstevel@tonic-gate 			if (rmp->rm_krpc_cell) {
714*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
715*7c478bd9Sstevel@tonic-gate 				/*
716*7c478bd9Sstevel@tonic-gate 				 * Test duplicate request cache and
717*7c478bd9Sstevel@tonic-gate 				 * rm_ref count handling by sending a
718*7c478bd9Sstevel@tonic-gate 				 * duplicate every so often, if
719*7c478bd9Sstevel@tonic-gate 				 * desired.
720*7c478bd9Sstevel@tonic-gate 				 */
721*7c478bd9Sstevel@tonic-gate 				if (rpcmod_send_dup &&
722*7c478bd9Sstevel@tonic-gate 				    rpcmod_send_dup_cnt++ %
723*7c478bd9Sstevel@tonic-gate 				    rpcmod_send_dup)
724*7c478bd9Sstevel@tonic-gate 					nmp = copymsg(mp);
725*7c478bd9Sstevel@tonic-gate 				else
726*7c478bd9Sstevel@tonic-gate 					nmp = NULL;
727*7c478bd9Sstevel@tonic-gate #endif
728*7c478bd9Sstevel@tonic-gate 				/*
729*7c478bd9Sstevel@tonic-gate 				 * Raise the reference count on this
730*7c478bd9Sstevel@tonic-gate 				 * module to prevent it from being
731*7c478bd9Sstevel@tonic-gate 				 * popped before krpc generates the
732*7c478bd9Sstevel@tonic-gate 				 * reply.
733*7c478bd9Sstevel@tonic-gate 				 */
734*7c478bd9Sstevel@tonic-gate 				rmp->rm_ref++;
735*7c478bd9Sstevel@tonic-gate 				mutex_exit(&rmp->rm_lock);
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 				/*
738*7c478bd9Sstevel@tonic-gate 				 * Submit the message to krpc.
739*7c478bd9Sstevel@tonic-gate 				 */
740*7c478bd9Sstevel@tonic-gate 				svc_queuereq(q, mp);
741*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
742*7c478bd9Sstevel@tonic-gate 				/*
743*7c478bd9Sstevel@tonic-gate 				 * Send duplicate if we created one.
744*7c478bd9Sstevel@tonic-gate 				 */
745*7c478bd9Sstevel@tonic-gate 				if (nmp) {
746*7c478bd9Sstevel@tonic-gate 					mutex_enter(&rmp->rm_lock);
747*7c478bd9Sstevel@tonic-gate 					rmp->rm_ref++;
748*7c478bd9Sstevel@tonic-gate 					mutex_exit(&rmp->rm_lock);
749*7c478bd9Sstevel@tonic-gate 					svc_queuereq(q, nmp);
750*7c478bd9Sstevel@tonic-gate 				}
751*7c478bd9Sstevel@tonic-gate #endif
752*7c478bd9Sstevel@tonic-gate 			} else {
753*7c478bd9Sstevel@tonic-gate 				mutex_exit(&rmp->rm_lock);
754*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
755*7c478bd9Sstevel@tonic-gate 			}
756*7c478bd9Sstevel@tonic-gate 			return;
757*7c478bd9Sstevel@tonic-gate 		    default:
758*7c478bd9Sstevel@tonic-gate 			mutex_exit(&rmp->rm_lock);
759*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
760*7c478bd9Sstevel@tonic-gate 			return;
761*7c478bd9Sstevel@tonic-gate 		    } /* end switch(rmp->rm_type) */
762*7c478bd9Sstevel@tonic-gate 		} else if (pptr->type == T_UDERROR_IND) {
763*7c478bd9Sstevel@tonic-gate 		    mutex_enter(&rmp->rm_lock);
764*7c478bd9Sstevel@tonic-gate 		    hdrsz = mp->b_wptr - mp->b_rptr;
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 		/*
767*7c478bd9Sstevel@tonic-gate 		 * Make sure the header is sane
768*7c478bd9Sstevel@tonic-gate 		 */
769*7c478bd9Sstevel@tonic-gate 		    if (hdrsz < TUDERRORINDSZ ||
770*7c478bd9Sstevel@tonic-gate 			hdrsz < (pptr->uderror_ind.OPT_length +
771*7c478bd9Sstevel@tonic-gate 				pptr->uderror_ind.OPT_offset) ||
772*7c478bd9Sstevel@tonic-gate 			hdrsz < (pptr->uderror_ind.DEST_length +
773*7c478bd9Sstevel@tonic-gate 				pptr->uderror_ind.DEST_offset)) {
774*7c478bd9Sstevel@tonic-gate 			    mutex_exit(&rmp->rm_lock);
775*7c478bd9Sstevel@tonic-gate 			    freemsg(mp);
776*7c478bd9Sstevel@tonic-gate 			    return;
777*7c478bd9Sstevel@tonic-gate 		    }
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 		/*
780*7c478bd9Sstevel@tonic-gate 		 * In the case where a unit data error has been
781*7c478bd9Sstevel@tonic-gate 		 * received, all we need to do is clear the message from
782*7c478bd9Sstevel@tonic-gate 		 * the queue.
783*7c478bd9Sstevel@tonic-gate 		 */
784*7c478bd9Sstevel@tonic-gate 		    mutex_exit(&rmp->rm_lock);
785*7c478bd9Sstevel@tonic-gate 		    freemsg(mp);
786*7c478bd9Sstevel@tonic-gate 		    RPCLOG(32, "rpcmodrput: unitdata error received at "
787*7c478bd9Sstevel@tonic-gate 				"%ld\n", gethrestime_sec());
788*7c478bd9Sstevel@tonic-gate 		    return;
789*7c478bd9Sstevel@tonic-gate 		} /* end else if (pptr->type == T_UDERROR_IND) */
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
792*7c478bd9Sstevel@tonic-gate 		break;
793*7c478bd9Sstevel@tonic-gate 	} /* end switch (mp->b_datap->db_type) */
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END,
796*7c478bd9Sstevel@tonic-gate 		"rpcmodrput_end:");
797*7c478bd9Sstevel@tonic-gate 	/*
798*7c478bd9Sstevel@tonic-gate 	 * Return codes are not looked at by the STREAMS framework.
799*7c478bd9Sstevel@tonic-gate 	 */
800*7c478bd9Sstevel@tonic-gate }
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate /*
803*7c478bd9Sstevel@tonic-gate  * write put procedure
804*7c478bd9Sstevel@tonic-gate  */
805*7c478bd9Sstevel@tonic-gate void
806*7c478bd9Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp)
807*7c478bd9Sstevel@tonic-gate {
808*7c478bd9Sstevel@tonic-gate 	struct rpcm	*rmp;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
813*7c478bd9Sstevel@tonic-gate 	    case M_PROTO:
814*7c478bd9Sstevel@tonic-gate 	    case M_PCPROTO:
815*7c478bd9Sstevel@tonic-gate 		    break;
816*7c478bd9Sstevel@tonic-gate 	    default:
817*7c478bd9Sstevel@tonic-gate 		    rpcmodwput_other(q, mp);
818*7c478bd9Sstevel@tonic-gate 		    return;
819*7c478bd9Sstevel@tonic-gate 	}
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	/*
822*7c478bd9Sstevel@tonic-gate 	 * Check to see if we can send the message downstream.
823*7c478bd9Sstevel@tonic-gate 	 */
824*7c478bd9Sstevel@tonic-gate 	if (canputnext(q)) {
825*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
826*7c478bd9Sstevel@tonic-gate 		return;
827*7c478bd9Sstevel@tonic-gate 	}
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
830*7c478bd9Sstevel@tonic-gate 	ASSERT(rmp != NULL);
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	/*
833*7c478bd9Sstevel@tonic-gate 	 * The first canputnext failed.  Try again except this time with the
834*7c478bd9Sstevel@tonic-gate 	 * lock held, so that we can check the state of the stream to see if
835*7c478bd9Sstevel@tonic-gate 	 * it is closing.  If either of these conditions evaluate to true
836*7c478bd9Sstevel@tonic-gate 	 * then send the meesage.
837*7c478bd9Sstevel@tonic-gate 	 */
838*7c478bd9Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
839*7c478bd9Sstevel@tonic-gate 	if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) {
840*7c478bd9Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
841*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
842*7c478bd9Sstevel@tonic-gate 	} else {
843*7c478bd9Sstevel@tonic-gate 		/*
844*7c478bd9Sstevel@tonic-gate 		 * canputnext failed again and the stream is not closing.
845*7c478bd9Sstevel@tonic-gate 		 * Place the message on the queue and let the service
846*7c478bd9Sstevel@tonic-gate 		 * procedure handle the message.
847*7c478bd9Sstevel@tonic-gate 		 */
848*7c478bd9Sstevel@tonic-gate 		mutex_exit(&rmp->rm_lock);
849*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
850*7c478bd9Sstevel@tonic-gate 	}
851*7c478bd9Sstevel@tonic-gate }
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate static void
854*7c478bd9Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp)
855*7c478bd9Sstevel@tonic-gate {
856*7c478bd9Sstevel@tonic-gate 	struct rpcm	*rmp;
857*7c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
860*7c478bd9Sstevel@tonic-gate 	ASSERT(rmp != NULL);
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
863*7c478bd9Sstevel@tonic-gate 		case M_IOCTL:
864*7c478bd9Sstevel@tonic-gate 			iocp = (struct iocblk *)mp->b_rptr;
865*7c478bd9Sstevel@tonic-gate 			ASSERT(iocp != NULL);
866*7c478bd9Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
867*7c478bd9Sstevel@tonic-gate 			    case RPC_CLIENT:
868*7c478bd9Sstevel@tonic-gate 			    case RPC_SERVER:
869*7c478bd9Sstevel@tonic-gate 				    mutex_enter(&rmp->rm_lock);
870*7c478bd9Sstevel@tonic-gate 				    rmp->rm_type = iocp->ioc_cmd;
871*7c478bd9Sstevel@tonic-gate 				    mutex_exit(&rmp->rm_lock);
872*7c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type = M_IOCACK;
873*7c478bd9Sstevel@tonic-gate 				    qreply(q, mp);
874*7c478bd9Sstevel@tonic-gate 				    return;
875*7c478bd9Sstevel@tonic-gate 			    default:
876*7c478bd9Sstevel@tonic-gate 				/*
877*7c478bd9Sstevel@tonic-gate 				 * pass the ioctl downstream and hope someone
878*7c478bd9Sstevel@tonic-gate 				 * down there knows how to handle it.
879*7c478bd9Sstevel@tonic-gate 				 */
880*7c478bd9Sstevel@tonic-gate 				    putnext(q, mp);
881*7c478bd9Sstevel@tonic-gate 				    return;
882*7c478bd9Sstevel@tonic-gate 			}
883*7c478bd9Sstevel@tonic-gate 		default:
884*7c478bd9Sstevel@tonic-gate 			break;
885*7c478bd9Sstevel@tonic-gate 	}
886*7c478bd9Sstevel@tonic-gate 	/*
887*7c478bd9Sstevel@tonic-gate 	 * This is something we definitely do not know how to handle, just
888*7c478bd9Sstevel@tonic-gate 	 * pass the message downstream
889*7c478bd9Sstevel@tonic-gate 	 */
890*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
891*7c478bd9Sstevel@tonic-gate }
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate /*
894*7c478bd9Sstevel@tonic-gate  * Module write service procedure. This is called by downstream modules
895*7c478bd9Sstevel@tonic-gate  * for back enabling during flow control.
896*7c478bd9Sstevel@tonic-gate  */
897*7c478bd9Sstevel@tonic-gate void
898*7c478bd9Sstevel@tonic-gate rpcmodwsrv(queue_t *q)
899*7c478bd9Sstevel@tonic-gate {
900*7c478bd9Sstevel@tonic-gate 	struct rpcm	*rmp;
901*7c478bd9Sstevel@tonic-gate 	mblk_t		*mp = NULL;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
904*7c478bd9Sstevel@tonic-gate 	ASSERT(rmp != NULL);
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	/*
907*7c478bd9Sstevel@tonic-gate 	 * Get messages that may be queued and send them down stream
908*7c478bd9Sstevel@tonic-gate 	 */
909*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
910*7c478bd9Sstevel@tonic-gate 		/*
911*7c478bd9Sstevel@tonic-gate 		 * Optimize the service procedure for the server-side, by
912*7c478bd9Sstevel@tonic-gate 		 * avoiding a call to canputnext().
913*7c478bd9Sstevel@tonic-gate 		 */
914*7c478bd9Sstevel@tonic-gate 		if (rmp->rm_type == RPC_SERVER || canputnext(q)) {
915*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
916*7c478bd9Sstevel@tonic-gate 			continue;
917*7c478bd9Sstevel@tonic-gate 		}
918*7c478bd9Sstevel@tonic-gate 		(void) putbq(q, mp);
919*7c478bd9Sstevel@tonic-gate 		return;
920*7c478bd9Sstevel@tonic-gate 	}
921*7c478bd9Sstevel@tonic-gate }
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate static void
924*7c478bd9Sstevel@tonic-gate rpcmod_release(queue_t *q, mblk_t *bp)
925*7c478bd9Sstevel@tonic-gate {
926*7c478bd9Sstevel@tonic-gate 	struct rpcm *rmp;
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	/*
929*7c478bd9Sstevel@tonic-gate 	 * For now, just free the message.
930*7c478bd9Sstevel@tonic-gate 	 */
931*7c478bd9Sstevel@tonic-gate 	if (bp)
932*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
933*7c478bd9Sstevel@tonic-gate 	rmp = (struct rpcm *)q->q_ptr;
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	mutex_enter(&rmp->rm_lock);
936*7c478bd9Sstevel@tonic-gate 	rmp->rm_ref--;
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) {
939*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&rmp->rm_cwait);
940*7c478bd9Sstevel@tonic-gate 	}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	mutex_exit(&rmp->rm_lock);
943*7c478bd9Sstevel@tonic-gate }
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate /*
946*7c478bd9Sstevel@tonic-gate  * This part of rpcmod is pushed on a connection-oriented transport for use
947*7c478bd9Sstevel@tonic-gate  * by RPC.  It serves to bypass the Stream head, implements
948*7c478bd9Sstevel@tonic-gate  * the record marking protocol, and dispatches incoming RPC messages.
949*7c478bd9Sstevel@tonic-gate  */
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate /* Default idle timer values */
952*7c478bd9Sstevel@tonic-gate #define	MIR_CLNT_IDLE_TIMEOUT	(5 * (60 * 1000L))	/* 5 minutes */
953*7c478bd9Sstevel@tonic-gate #define	MIR_SVC_IDLE_TIMEOUT	(6 * (60 * 1000L))	/* 6 minutes */
954*7c478bd9Sstevel@tonic-gate #define	MIR_SVC_ORDREL_TIMEOUT	(10 * (60 * 1000L))	/* 10 minutes */
955*7c478bd9Sstevel@tonic-gate #define	MIR_LASTFRAG	0x80000000	/* Record marker */
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate #define	DLEN(mp) (mp->b_cont ? msgdsize(mp) : (mp->b_wptr - mp->b_rptr))
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate typedef struct mir_s {
960*7c478bd9Sstevel@tonic-gate 	void	*mir_krpc_cell;	/* Reserved for KRPC use. This field */
961*7c478bd9Sstevel@tonic-gate 					/* must be first in the structure. */
962*7c478bd9Sstevel@tonic-gate 	struct xprt_style_ops	*rm_ops;
963*7c478bd9Sstevel@tonic-gate 	int	mir_type;		/* Client or server side stream */
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	mblk_t	*mir_head_mp;		/* RPC msg in progress */
966*7c478bd9Sstevel@tonic-gate 		/*
967*7c478bd9Sstevel@tonic-gate 		 * mir_head_mp points the first mblk being collected in
968*7c478bd9Sstevel@tonic-gate 		 * the current RPC message.  Record headers are removed
969*7c478bd9Sstevel@tonic-gate 		 * before data is linked into mir_head_mp.
970*7c478bd9Sstevel@tonic-gate 		 */
971*7c478bd9Sstevel@tonic-gate 	mblk_t	*mir_tail_mp;		/* Last mblk in mir_head_mp */
972*7c478bd9Sstevel@tonic-gate 		/*
973*7c478bd9Sstevel@tonic-gate 		 * mir_tail_mp points to the last mblk in the message
974*7c478bd9Sstevel@tonic-gate 		 * chain starting at mir_head_mp.  It is only valid
975*7c478bd9Sstevel@tonic-gate 		 * if mir_head_mp is non-NULL and is used to add new
976*7c478bd9Sstevel@tonic-gate 		 * data blocks to the end of chain quickly.
977*7c478bd9Sstevel@tonic-gate 		 */
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	int32_t	mir_frag_len;		/* Bytes seen in the current frag */
980*7c478bd9Sstevel@tonic-gate 		/*
981*7c478bd9Sstevel@tonic-gate 		 * mir_frag_len starts at -4 for beginning of each fragment.
982*7c478bd9Sstevel@tonic-gate 		 * When this length is negative, it indicates the number of
983*7c478bd9Sstevel@tonic-gate 		 * bytes that rpcmod needs to complete the record marker
984*7c478bd9Sstevel@tonic-gate 		 * header.  When it is positive or zero, it holds the number
985*7c478bd9Sstevel@tonic-gate 		 * of bytes that have arrived for the current fragment and
986*7c478bd9Sstevel@tonic-gate 		 * are held in mir_header_mp.
987*7c478bd9Sstevel@tonic-gate 		 */
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	int32_t	mir_frag_header;
990*7c478bd9Sstevel@tonic-gate 		/*
991*7c478bd9Sstevel@tonic-gate 		 * Fragment header as collected for the current fragment.
992*7c478bd9Sstevel@tonic-gate 		 * It holds the last-fragment indicator and the number
993*7c478bd9Sstevel@tonic-gate 		 * of bytes in the fragment.
994*7c478bd9Sstevel@tonic-gate 		 */
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	unsigned int
997*7c478bd9Sstevel@tonic-gate 		mir_ordrel_pending : 1,	/* Sent T_ORDREL_REQ */
998*7c478bd9Sstevel@tonic-gate 		mir_hold_inbound : 1,	/* Hold inbound messages on server */
999*7c478bd9Sstevel@tonic-gate 					/* side until outbound flow control */
1000*7c478bd9Sstevel@tonic-gate 					/* is relieved. */
1001*7c478bd9Sstevel@tonic-gate 		mir_closing : 1,	/* The stream is being closed */
1002*7c478bd9Sstevel@tonic-gate 		mir_inrservice : 1,	/* data queued or rd srv proc running */
1003*7c478bd9Sstevel@tonic-gate 		mir_inwservice : 1,	/* data queued or wr srv proc running */
1004*7c478bd9Sstevel@tonic-gate 		mir_inwflushdata : 1,	/* flush M_DATAs when srv runs */
1005*7c478bd9Sstevel@tonic-gate 		/*
1006*7c478bd9Sstevel@tonic-gate 		 * On client streams, mir_clntreq is 0 or 1; it is set
1007*7c478bd9Sstevel@tonic-gate 		 * to 1 whenever a new request is sent out (mir_wput)
1008*7c478bd9Sstevel@tonic-gate 		 * and cleared when the timer fires (mir_timer).  If
1009*7c478bd9Sstevel@tonic-gate 		 * the timer fires with this value equal to 0, then the
1010*7c478bd9Sstevel@tonic-gate 		 * stream is considered idle and KRPC is notified.
1011*7c478bd9Sstevel@tonic-gate 		 */
1012*7c478bd9Sstevel@tonic-gate 		mir_clntreq : 1,
1013*7c478bd9Sstevel@tonic-gate 		/*
1014*7c478bd9Sstevel@tonic-gate 		 * On server streams, stop accepting messages
1015*7c478bd9Sstevel@tonic-gate 		 */
1016*7c478bd9Sstevel@tonic-gate 		mir_svc_no_more_msgs : 1,
1017*7c478bd9Sstevel@tonic-gate 		mir_listen_stream : 1,	/* listen end point */
1018*7c478bd9Sstevel@tonic-gate 		mir_setup_complete : 1,	/* server has initialized everything */
1019*7c478bd9Sstevel@tonic-gate 		mir_timer_call : 1,
1020*7c478bd9Sstevel@tonic-gate 		mir_junk_fill_thru_bit_31 : 21;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	timeout_id_t mir_timer_id;	/* Timer for idle checks */
1023*7c478bd9Sstevel@tonic-gate 	clock_t	mir_idle_timeout;	/* Allowed idle time before shutdown */
1024*7c478bd9Sstevel@tonic-gate 		/*
1025*7c478bd9Sstevel@tonic-gate 		 * This value is copied from clnt_idle_timeout or
1026*7c478bd9Sstevel@tonic-gate 		 * svc_idle_timeout during the appropriate ioctl.
1027*7c478bd9Sstevel@tonic-gate 		 * Kept in milliseconds
1028*7c478bd9Sstevel@tonic-gate 		 */
1029*7c478bd9Sstevel@tonic-gate 	clock_t	mir_use_timestamp;	/* updated on client with each use */
1030*7c478bd9Sstevel@tonic-gate 		/*
1031*7c478bd9Sstevel@tonic-gate 		 * This value is set to lbolt
1032*7c478bd9Sstevel@tonic-gate 		 * every time a client stream sends or receives data.
1033*7c478bd9Sstevel@tonic-gate 		 * Even if the timer message arrives, we don't shutdown
1034*7c478bd9Sstevel@tonic-gate 		 * client unless:
1035*7c478bd9Sstevel@tonic-gate 		 *    lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp.
1036*7c478bd9Sstevel@tonic-gate 		 * This value is kept in HZ.
1037*7c478bd9Sstevel@tonic-gate 		 */
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	uint_t	*mir_max_msg_sizep;	/* Reference to sanity check size */
1040*7c478bd9Sstevel@tonic-gate 		/*
1041*7c478bd9Sstevel@tonic-gate 		 * This pointer is set to &clnt_max_msg_size or
1042*7c478bd9Sstevel@tonic-gate 		 * &svc_max_msg_size during the appropriate ioctl.
1043*7c478bd9Sstevel@tonic-gate 		 */
1044*7c478bd9Sstevel@tonic-gate 	zoneid_t mir_zoneid;	/* zone which pushed rpcmod */
1045*7c478bd9Sstevel@tonic-gate 	/* Server-side fields. */
1046*7c478bd9Sstevel@tonic-gate 	int	mir_ref_cnt;		/* Reference count: server side only */
1047*7c478bd9Sstevel@tonic-gate 					/* counts the number of references */
1048*7c478bd9Sstevel@tonic-gate 					/* that a kernel RPC server thread */
1049*7c478bd9Sstevel@tonic-gate 					/* (see svc_run()) has on this rpcmod */
1050*7c478bd9Sstevel@tonic-gate 					/* slot. Effectively, it is the */
1051*7c478bd9Sstevel@tonic-gate 					/* number * of unprocessed messages */
1052*7c478bd9Sstevel@tonic-gate 					/* that have been passed up to the */
1053*7c478bd9Sstevel@tonic-gate 					/* KRPC layer */
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	mblk_t	*mir_svc_pend_mp;	/* Pending T_ORDREL_IND or */
1056*7c478bd9Sstevel@tonic-gate 					/* T_DISCON_IND */
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	/*
1059*7c478bd9Sstevel@tonic-gate 	 * these fields are for both client and server, but for debugging,
1060*7c478bd9Sstevel@tonic-gate 	 * it is easier to have these last in the structure.
1061*7c478bd9Sstevel@tonic-gate 	 */
1062*7c478bd9Sstevel@tonic-gate 	kmutex_t	mir_mutex;	/* Mutex and condvar for close */
1063*7c478bd9Sstevel@tonic-gate 	kcondvar_t	mir_condvar;	/* synchronization. */
1064*7c478bd9Sstevel@tonic-gate 	kcondvar_t	mir_timer_cv;	/* Timer routine sync. */
1065*7c478bd9Sstevel@tonic-gate } mir_t;
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate #define	MIR_SVC_QUIESCED(mir)	\
1068*7c478bd9Sstevel@tonic-gate 	(mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0)
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate #define	MIR_CLEAR_INRSRV(mir_ptr)	{	\
1071*7c478bd9Sstevel@tonic-gate 	(mir_ptr)->mir_inrservice = 0;	\
1072*7c478bd9Sstevel@tonic-gate 	if ((mir_ptr)->mir_type == RPC_SERVER &&	\
1073*7c478bd9Sstevel@tonic-gate 		(mir_ptr)->mir_closing)	\
1074*7c478bd9Sstevel@tonic-gate 		cv_signal(&(mir_ptr)->mir_condvar);	\
1075*7c478bd9Sstevel@tonic-gate }
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate /*
1078*7c478bd9Sstevel@tonic-gate  * Don't block service procedure (and mir_close) if
1079*7c478bd9Sstevel@tonic-gate  * we are in the process of closing.
1080*7c478bd9Sstevel@tonic-gate  */
1081*7c478bd9Sstevel@tonic-gate #define	MIR_WCANPUTNEXT(mir_ptr, write_q)	\
1082*7c478bd9Sstevel@tonic-gate 	(canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1))
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate static int	mir_clnt_dup_request(queue_t *q, mblk_t *mp);
1085*7c478bd9Sstevel@tonic-gate static void	mir_rput_proto(queue_t *q, mblk_t *mp);
1086*7c478bd9Sstevel@tonic-gate static int	mir_svc_policy_notify(queue_t *q, int event);
1087*7c478bd9Sstevel@tonic-gate static void	mir_svc_release(queue_t *wq, mblk_t *mp);
1088*7c478bd9Sstevel@tonic-gate static void	mir_svc_start(queue_t *wq);
1089*7c478bd9Sstevel@tonic-gate static void	mir_svc_idle_start(queue_t *, mir_t *);
1090*7c478bd9Sstevel@tonic-gate static void	mir_svc_idle_stop(queue_t *, mir_t *);
1091*7c478bd9Sstevel@tonic-gate static void	mir_svc_start_close(queue_t *, mir_t *);
1092*7c478bd9Sstevel@tonic-gate static void	mir_clnt_idle_do_stop(queue_t *);
1093*7c478bd9Sstevel@tonic-gate static void	mir_clnt_idle_stop(queue_t *, mir_t *);
1094*7c478bd9Sstevel@tonic-gate static void	mir_clnt_idle_start(queue_t *, mir_t *);
1095*7c478bd9Sstevel@tonic-gate static void	mir_wput(queue_t *q, mblk_t *mp);
1096*7c478bd9Sstevel@tonic-gate static void	mir_wput_other(queue_t *q, mblk_t *mp);
1097*7c478bd9Sstevel@tonic-gate static void	mir_wsrv(queue_t *q);
1098*7c478bd9Sstevel@tonic-gate static	void	mir_disconnect(queue_t *, mir_t *ir);
1099*7c478bd9Sstevel@tonic-gate static	int	mir_check_len(queue_t *, int32_t, mblk_t *);
1100*7c478bd9Sstevel@tonic-gate static	void	mir_timer(void *);
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate extern void	(*mir_rele)(queue_t *, mblk_t *);
1103*7c478bd9Sstevel@tonic-gate extern void	(*mir_start)(queue_t *);
1104*7c478bd9Sstevel@tonic-gate extern void	(*clnt_stop_idle)(queue_t *);
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate clock_t	clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT;
1107*7c478bd9Sstevel@tonic-gate clock_t	svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT;
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate /*
1110*7c478bd9Sstevel@tonic-gate  * Timeout for subsequent notifications of idle connection.  This is
1111*7c478bd9Sstevel@tonic-gate  * typically used to clean up after a wedged orderly release.
1112*7c478bd9Sstevel@tonic-gate  */
1113*7c478bd9Sstevel@tonic-gate clock_t	svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate extern	uint_t	*clnt_max_msg_sizep;
1116*7c478bd9Sstevel@tonic-gate extern	uint_t	*svc_max_msg_sizep;
1117*7c478bd9Sstevel@tonic-gate uint_t	clnt_max_msg_size = RPC_MAXDATASIZE;
1118*7c478bd9Sstevel@tonic-gate uint_t	svc_max_msg_size = RPC_MAXDATASIZE;
1119*7c478bd9Sstevel@tonic-gate uint_t	mir_krpc_cell_null;
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate static void
1122*7c478bd9Sstevel@tonic-gate mir_timer_stop(mir_t *mir)
1123*7c478bd9Sstevel@tonic-gate {
1124*7c478bd9Sstevel@tonic-gate 	timeout_id_t tid;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	/*
1129*7c478bd9Sstevel@tonic-gate 	 * Since the mir_mutex lock needs to be released to call
1130*7c478bd9Sstevel@tonic-gate 	 * untimeout(), we need to make sure that no other thread
1131*7c478bd9Sstevel@tonic-gate 	 * can start/stop the timer (changing mir_timer_id) during
1132*7c478bd9Sstevel@tonic-gate 	 * that time.  The mir_timer_call bit and the mir_timer_cv
1133*7c478bd9Sstevel@tonic-gate 	 * condition variable are used to synchronize this.  Setting
1134*7c478bd9Sstevel@tonic-gate 	 * mir_timer_call also tells mir_timer() (refer to the comments
1135*7c478bd9Sstevel@tonic-gate 	 * in mir_timer()) that it does not need to do anything.
1136*7c478bd9Sstevel@tonic-gate 	 */
1137*7c478bd9Sstevel@tonic-gate 	while (mir->mir_timer_call)
1138*7c478bd9Sstevel@tonic-gate 		cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
1139*7c478bd9Sstevel@tonic-gate 	mir->mir_timer_call = B_TRUE;
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	if ((tid = mir->mir_timer_id) != 0) {
1142*7c478bd9Sstevel@tonic-gate 		mir->mir_timer_id = 0;
1143*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
1144*7c478bd9Sstevel@tonic-gate 		(void) untimeout(tid);
1145*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 	mir->mir_timer_call = B_FALSE;
1148*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&mir->mir_timer_cv);
1149*7c478bd9Sstevel@tonic-gate }
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate static void
1152*7c478bd9Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl)
1153*7c478bd9Sstevel@tonic-gate {
1154*7c478bd9Sstevel@tonic-gate 	timeout_id_t tid;
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 	while (mir->mir_timer_call)
1159*7c478bd9Sstevel@tonic-gate 		cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
1160*7c478bd9Sstevel@tonic-gate 	mir->mir_timer_call = B_TRUE;
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	if ((tid = mir->mir_timer_id) != 0) {
1163*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
1164*7c478bd9Sstevel@tonic-gate 		(void) untimeout(tid);
1165*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
1166*7c478bd9Sstevel@tonic-gate 	}
1167*7c478bd9Sstevel@tonic-gate 	/* Only start the timer when it is not closing. */
1168*7c478bd9Sstevel@tonic-gate 	if (!mir->mir_closing) {
1169*7c478bd9Sstevel@tonic-gate 		mir->mir_timer_id = timeout(mir_timer, q,
1170*7c478bd9Sstevel@tonic-gate 		    MSEC_TO_TICK(intrvl));
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 	mir->mir_timer_call = B_FALSE;
1173*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&mir->mir_timer_cv);
1174*7c478bd9Sstevel@tonic-gate }
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate static int
1177*7c478bd9Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp)
1178*7c478bd9Sstevel@tonic-gate {
1179*7c478bd9Sstevel@tonic-gate 	mblk_t  *mp1;
1180*7c478bd9Sstevel@tonic-gate 	uint32_t  new_xid;
1181*7c478bd9Sstevel@tonic-gate 	uint32_t  old_xid;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex));
1184*7c478bd9Sstevel@tonic-gate 	new_xid = BE32_TO_U32(&mp->b_rptr[4]);
1185*7c478bd9Sstevel@tonic-gate 	/*
1186*7c478bd9Sstevel@tonic-gate 	 * This loop is a bit tacky -- it walks the STREAMS list of
1187*7c478bd9Sstevel@tonic-gate 	 * flow-controlled messages.
1188*7c478bd9Sstevel@tonic-gate 	 */
1189*7c478bd9Sstevel@tonic-gate 	if ((mp1 = q->q_first) != NULL) {
1190*7c478bd9Sstevel@tonic-gate 		do {
1191*7c478bd9Sstevel@tonic-gate 			old_xid = BE32_TO_U32(&mp1->b_rptr[4]);
1192*7c478bd9Sstevel@tonic-gate 			if (new_xid == old_xid)
1193*7c478bd9Sstevel@tonic-gate 				return (1);
1194*7c478bd9Sstevel@tonic-gate 		} while ((mp1 = mp1->b_next) != NULL);
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 	return (0);
1197*7c478bd9Sstevel@tonic-gate }
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate static int
1200*7c478bd9Sstevel@tonic-gate mir_close(queue_t *q)
1201*7c478bd9Sstevel@tonic-gate {
1202*7c478bd9Sstevel@tonic-gate 	mir_t	*mir;
1203*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
1204*7c478bd9Sstevel@tonic-gate 	bool_t queue_cleaned = FALSE;
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q);
1207*7c478bd9Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
1208*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
1209*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
1210*7c478bd9Sstevel@tonic-gate 	if ((mp = mir->mir_head_mp) != NULL) {
1211*7c478bd9Sstevel@tonic-gate 		mir->mir_head_mp = (mblk_t *)0;
1212*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 	/*
1215*7c478bd9Sstevel@tonic-gate 	 * Set mir_closing so we get notified when MIR_SVC_QUIESCED()
1216*7c478bd9Sstevel@tonic-gate 	 * is TRUE.  And mir_timer_start() won't start the timer again.
1217*7c478bd9Sstevel@tonic-gate 	 */
1218*7c478bd9Sstevel@tonic-gate 	mir->mir_closing = B_TRUE;
1219*7c478bd9Sstevel@tonic-gate 	mir_timer_stop(mir);
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	if (mir->mir_type == RPC_SERVER) {
1222*7c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);	/* Ditch anything waiting on read q */
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 		/*
1225*7c478bd9Sstevel@tonic-gate 		 * This will prevent more requests from arriving and
1226*7c478bd9Sstevel@tonic-gate 		 * will force rpcmod to ignore flow control.
1227*7c478bd9Sstevel@tonic-gate 		 */
1228*7c478bd9Sstevel@tonic-gate 		mir_svc_start_close(WR(q), mir);
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 		while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) {
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 			if (mir->mir_ref_cnt && !mir->mir_inrservice &&
1233*7c478bd9Sstevel@tonic-gate 					(queue_cleaned == FALSE)) {
1234*7c478bd9Sstevel@tonic-gate 				/*
1235*7c478bd9Sstevel@tonic-gate 				 * call into SVC to clean the queue
1236*7c478bd9Sstevel@tonic-gate 				 */
1237*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
1238*7c478bd9Sstevel@tonic-gate 				svc_queueclean(q);
1239*7c478bd9Sstevel@tonic-gate 				queue_cleaned = TRUE;
1240*7c478bd9Sstevel@tonic-gate 				mutex_enter(&mir->mir_mutex);
1241*7c478bd9Sstevel@tonic-gate 				continue;
1242*7c478bd9Sstevel@tonic-gate 			}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 			/*
1245*7c478bd9Sstevel@tonic-gate 			 * Bugid 1253810 - Force the write service
1246*7c478bd9Sstevel@tonic-gate 			 * procedure to send its messages, regardless
1247*7c478bd9Sstevel@tonic-gate 			 * whether the downstream  module is ready
1248*7c478bd9Sstevel@tonic-gate 			 * to accept data.
1249*7c478bd9Sstevel@tonic-gate 			 */
1250*7c478bd9Sstevel@tonic-gate 			if (mir->mir_inwservice == 1)
1251*7c478bd9Sstevel@tonic-gate 				qenable(WR(q));
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 			cv_wait(&mir->mir_condvar, &mir->mir_mutex);
1254*7c478bd9Sstevel@tonic-gate 		}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
1257*7c478bd9Sstevel@tonic-gate 		qprocsoff(q);
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 		/* Notify KRPC that this stream is going away. */
1260*7c478bd9Sstevel@tonic-gate 		svc_queueclose(q);
1261*7c478bd9Sstevel@tonic-gate 	} else {
1262*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
1263*7c478bd9Sstevel@tonic-gate 		qprocsoff(q);
1264*7c478bd9Sstevel@tonic-gate 	}
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&mir->mir_mutex);
1267*7c478bd9Sstevel@tonic-gate 	cv_destroy(&mir->mir_condvar);
1268*7c478bd9Sstevel@tonic-gate 	cv_destroy(&mir->mir_timer_cv);
1269*7c478bd9Sstevel@tonic-gate 	kmem_free(mir, sizeof (mir_t));
1270*7c478bd9Sstevel@tonic-gate 	return (0);
1271*7c478bd9Sstevel@tonic-gate }
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate /*
1274*7c478bd9Sstevel@tonic-gate  * This is server side only (RPC_SERVER).
1275*7c478bd9Sstevel@tonic-gate  *
1276*7c478bd9Sstevel@tonic-gate  * Exit idle mode.
1277*7c478bd9Sstevel@tonic-gate  */
1278*7c478bd9Sstevel@tonic-gate static void
1279*7c478bd9Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir)
1280*7c478bd9Sstevel@tonic-gate {
1281*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
1282*7c478bd9Sstevel@tonic-gate 	ASSERT((q->q_flag & QREADR) == 0);
1283*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
1284*7c478bd9Sstevel@tonic-gate 	RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q);
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	mir_timer_stop(mir);
1287*7c478bd9Sstevel@tonic-gate }
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate /*
1290*7c478bd9Sstevel@tonic-gate  * This is server side only (RPC_SERVER).
1291*7c478bd9Sstevel@tonic-gate  *
1292*7c478bd9Sstevel@tonic-gate  * Start idle processing, which will include setting idle timer if the
1293*7c478bd9Sstevel@tonic-gate  * stream is not being closed.
1294*7c478bd9Sstevel@tonic-gate  */
1295*7c478bd9Sstevel@tonic-gate static void
1296*7c478bd9Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir)
1297*7c478bd9Sstevel@tonic-gate {
1298*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
1299*7c478bd9Sstevel@tonic-gate 	ASSERT((q->q_flag & QREADR) == 0);
1300*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
1301*7c478bd9Sstevel@tonic-gate 	RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q);
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 	/*
1304*7c478bd9Sstevel@tonic-gate 	 * Don't re-start idle timer if we are closing queues.
1305*7c478bd9Sstevel@tonic-gate 	 */
1306*7c478bd9Sstevel@tonic-gate 	if (mir->mir_closing) {
1307*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n",
1308*7c478bd9Sstevel@tonic-gate 			(void *)q);
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 		/*
1311*7c478bd9Sstevel@tonic-gate 		 * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED()
1312*7c478bd9Sstevel@tonic-gate 		 * is true.  When it is true, and we are in the process of
1313*7c478bd9Sstevel@tonic-gate 		 * closing the stream, signal any thread waiting in
1314*7c478bd9Sstevel@tonic-gate 		 * mir_close().
1315*7c478bd9Sstevel@tonic-gate 		 */
1316*7c478bd9Sstevel@tonic-gate 		if (mir->mir_inwservice == 0)
1317*7c478bd9Sstevel@tonic-gate 			cv_signal(&mir->mir_condvar);
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	} else {
1320*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_idle_start - reset %s timer\n",
1321*7c478bd9Sstevel@tonic-gate 			mir->mir_ordrel_pending ? "ordrel" : "normal");
1322*7c478bd9Sstevel@tonic-gate 		/*
1323*7c478bd9Sstevel@tonic-gate 		 * Normal condition, start the idle timer.  If an orderly
1324*7c478bd9Sstevel@tonic-gate 		 * release has been sent, set the timeout to wait for the
1325*7c478bd9Sstevel@tonic-gate 		 * client to close its side of the connection.  Otherwise,
1326*7c478bd9Sstevel@tonic-gate 		 * use the normal idle timeout.
1327*7c478bd9Sstevel@tonic-gate 		 */
1328*7c478bd9Sstevel@tonic-gate 		mir_timer_start(q, mir, mir->mir_ordrel_pending ?
1329*7c478bd9Sstevel@tonic-gate 		    svc_ordrel_timeout : mir->mir_idle_timeout);
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate }
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1334*7c478bd9Sstevel@tonic-gate static int
1335*7c478bd9Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1336*7c478bd9Sstevel@tonic-gate {
1337*7c478bd9Sstevel@tonic-gate 	mir_t	*mir;
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q);
1340*7c478bd9Sstevel@tonic-gate 	/* Set variables used directly by KRPC. */
1341*7c478bd9Sstevel@tonic-gate 	if (!mir_rele)
1342*7c478bd9Sstevel@tonic-gate 		mir_rele = mir_svc_release;
1343*7c478bd9Sstevel@tonic-gate 	if (!mir_start)
1344*7c478bd9Sstevel@tonic-gate 		mir_start = mir_svc_start;
1345*7c478bd9Sstevel@tonic-gate 	if (!clnt_stop_idle)
1346*7c478bd9Sstevel@tonic-gate 		clnt_stop_idle = mir_clnt_idle_do_stop;
1347*7c478bd9Sstevel@tonic-gate 	if (!clnt_max_msg_sizep)
1348*7c478bd9Sstevel@tonic-gate 		clnt_max_msg_sizep = &clnt_max_msg_size;
1349*7c478bd9Sstevel@tonic-gate 	if (!svc_max_msg_sizep)
1350*7c478bd9Sstevel@tonic-gate 		svc_max_msg_sizep = &svc_max_msg_size;
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate 	/* Allocate a zero'ed out mir structure for this stream. */
1353*7c478bd9Sstevel@tonic-gate 	mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP);
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	/*
1356*7c478bd9Sstevel@tonic-gate 	 * We set hold inbound here so that incoming messages will
1357*7c478bd9Sstevel@tonic-gate 	 * be held on the read-side queue until the stream is completely
1358*7c478bd9Sstevel@tonic-gate 	 * initialized with a RPC_CLIENT or RPC_SERVER ioctl.  During
1359*7c478bd9Sstevel@tonic-gate 	 * the ioctl processing, the flag is cleared and any messages that
1360*7c478bd9Sstevel@tonic-gate 	 * arrived between the open and the ioctl are delivered to KRPC.
1361*7c478bd9Sstevel@tonic-gate 	 *
1362*7c478bd9Sstevel@tonic-gate 	 * Early data should never arrive on a client stream since
1363*7c478bd9Sstevel@tonic-gate 	 * servers only respond to our requests and we do not send any.
1364*7c478bd9Sstevel@tonic-gate 	 * until after the stream is initialized.  Early data is
1365*7c478bd9Sstevel@tonic-gate 	 * very common on a server stream where the client will start
1366*7c478bd9Sstevel@tonic-gate 	 * sending data as soon as the connection is made (and this
1367*7c478bd9Sstevel@tonic-gate 	 * is especially true with TCP where the protocol accepts the
1368*7c478bd9Sstevel@tonic-gate 	 * connection before nfsd or KRPC is notified about it).
1369*7c478bd9Sstevel@tonic-gate 	 */
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	mir->mir_hold_inbound = 1;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	/*
1374*7c478bd9Sstevel@tonic-gate 	 * Start the record marker looking for a 4-byte header.  When
1375*7c478bd9Sstevel@tonic-gate 	 * this length is negative, it indicates that rpcmod is looking
1376*7c478bd9Sstevel@tonic-gate 	 * for bytes to consume for the record marker header.  When it
1377*7c478bd9Sstevel@tonic-gate 	 * is positive, it holds the number of bytes that have arrived
1378*7c478bd9Sstevel@tonic-gate 	 * for the current fragment and are being held in mir_header_mp.
1379*7c478bd9Sstevel@tonic-gate 	 */
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 	mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	mir->mir_zoneid = getzoneid();
1384*7c478bd9Sstevel@tonic-gate 	mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL);
1385*7c478bd9Sstevel@tonic-gate 	cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL);
1386*7c478bd9Sstevel@tonic-gate 	cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL);
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	q->q_ptr = (char *)mir;
1389*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (char *)mir;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	/*
1392*7c478bd9Sstevel@tonic-gate 	 * We noenable the read-side queue because we don't want it
1393*7c478bd9Sstevel@tonic-gate 	 * automatically enabled by putq.  We enable it explicitly
1394*7c478bd9Sstevel@tonic-gate 	 * in mir_wsrv when appropriate. (See additional comments on
1395*7c478bd9Sstevel@tonic-gate 	 * flow control at the beginning of mir_rsrv.)
1396*7c478bd9Sstevel@tonic-gate 	 */
1397*7c478bd9Sstevel@tonic-gate 	noenable(q);
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 	qprocson(q);
1400*7c478bd9Sstevel@tonic-gate 	return (0);
1401*7c478bd9Sstevel@tonic-gate }
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate /*
1404*7c478bd9Sstevel@tonic-gate  * Read-side put routine for both the client and server side.  Does the
1405*7c478bd9Sstevel@tonic-gate  * record marking for incoming RPC messages, and when complete, dispatches
1406*7c478bd9Sstevel@tonic-gate  * the message to either the client or server.
1407*7c478bd9Sstevel@tonic-gate  */
1408*7c478bd9Sstevel@tonic-gate static void
1409*7c478bd9Sstevel@tonic-gate mir_do_rput(queue_t *q, mblk_t *mp, int srv)
1410*7c478bd9Sstevel@tonic-gate {
1411*7c478bd9Sstevel@tonic-gate 	mblk_t	*cont_mp;
1412*7c478bd9Sstevel@tonic-gate 	int	excess;
1413*7c478bd9Sstevel@tonic-gate 	int32_t	frag_len;
1414*7c478bd9Sstevel@tonic-gate 	int32_t	frag_header;
1415*7c478bd9Sstevel@tonic-gate 	mblk_t	*head_mp;
1416*7c478bd9Sstevel@tonic-gate 	int	len;
1417*7c478bd9Sstevel@tonic-gate 	mir_t	*mir;
1418*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp1;
1419*7c478bd9Sstevel@tonic-gate 	unsigned char	*rptr;
1420*7c478bd9Sstevel@tonic-gate 	mblk_t	*tail_mp;
1421*7c478bd9Sstevel@tonic-gate 	unsigned char	*wptr;
1422*7c478bd9Sstevel@tonic-gate 	boolean_t	stop_timer = B_FALSE;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
1425*7c478bd9Sstevel@tonic-gate 	ASSERT(mir != NULL);
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	/*
1428*7c478bd9Sstevel@tonic-gate 	 * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER
1429*7c478bd9Sstevel@tonic-gate 	 * with the corresponding ioctl, then don't accept
1430*7c478bd9Sstevel@tonic-gate 	 * any inbound data.  This should never happen for streams
1431*7c478bd9Sstevel@tonic-gate 	 * created by nfsd or client-side KRPC because they are careful
1432*7c478bd9Sstevel@tonic-gate 	 * to set the mode of the stream before doing anything else.
1433*7c478bd9Sstevel@tonic-gate 	 */
1434*7c478bd9Sstevel@tonic-gate 	if (mir->mir_type == 0) {
1435*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1436*7c478bd9Sstevel@tonic-gate 		return;
1437*7c478bd9Sstevel@tonic-gate 	}
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
1442*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1443*7c478bd9Sstevel@tonic-gate 		break;
1444*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
1445*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
1446*7c478bd9Sstevel@tonic-gate 		rptr = mp->b_rptr;
1447*7c478bd9Sstevel@tonic-gate 		if (mp->b_wptr - rptr < sizeof (uint32_t)) {
1448*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n",
1449*7c478bd9Sstevel@tonic-gate 			    (int)(mp->b_wptr - rptr));
1450*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1451*7c478bd9Sstevel@tonic-gate 			return;
1452*7c478bd9Sstevel@tonic-gate 		}
1453*7c478bd9Sstevel@tonic-gate 		if (((union T_primitives *)rptr)->type != T_DATA_IND) {
1454*7c478bd9Sstevel@tonic-gate 			mir_rput_proto(q, mp);
1455*7c478bd9Sstevel@tonic-gate 			return;
1456*7c478bd9Sstevel@tonic-gate 		}
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 		/* Throw away the T_DATA_IND block and continue with data. */
1459*7c478bd9Sstevel@tonic-gate 		mp1 = mp;
1460*7c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
1461*7c478bd9Sstevel@tonic-gate 		freeb(mp1);
1462*7c478bd9Sstevel@tonic-gate 		break;
1463*7c478bd9Sstevel@tonic-gate 	case M_SETOPTS:
1464*7c478bd9Sstevel@tonic-gate 		/*
1465*7c478bd9Sstevel@tonic-gate 		 * If a module on the stream is trying set the Stream head's
1466*7c478bd9Sstevel@tonic-gate 		 * high water mark, then set our hiwater to the requested
1467*7c478bd9Sstevel@tonic-gate 		 * value.  We are the "stream head" for all inbound
1468*7c478bd9Sstevel@tonic-gate 		 * data messages since messages are passed directly to KRPC.
1469*7c478bd9Sstevel@tonic-gate 		 */
1470*7c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) >= sizeof (struct stroptions)) {
1471*7c478bd9Sstevel@tonic-gate 			struct stroptions	*stropts;
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 			stropts = (struct stroptions *)mp->b_rptr;
1474*7c478bd9Sstevel@tonic-gate 			if ((stropts->so_flags & SO_HIWAT) &&
1475*7c478bd9Sstevel@tonic-gate 				!(stropts->so_flags & SO_BAND)) {
1476*7c478bd9Sstevel@tonic-gate 				(void) strqset(q, QHIWAT, 0, stropts->so_hiwat);
1477*7c478bd9Sstevel@tonic-gate 			}
1478*7c478bd9Sstevel@tonic-gate 		}
1479*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1480*7c478bd9Sstevel@tonic-gate 		return;
1481*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
1482*7c478bd9Sstevel@tonic-gate 		RPCLOG(32, "mir_do_rput: ignoring M_FLUSH on q 0x%p. ",
1483*7c478bd9Sstevel@tonic-gate 		    (void *)q);
1484*7c478bd9Sstevel@tonic-gate 		RPCLOG(32, "M_FLUSH is %x\n", (uint_t)*mp->b_rptr);
1485*7c478bd9Sstevel@tonic-gate 
1486*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1487*7c478bd9Sstevel@tonic-gate 		return;
1488*7c478bd9Sstevel@tonic-gate 	default:
1489*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1490*7c478bd9Sstevel@tonic-gate 		return;
1491*7c478bd9Sstevel@tonic-gate 	}
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate 	/*
1496*7c478bd9Sstevel@tonic-gate 	 * If this connection is closing, don't accept any new messages.
1497*7c478bd9Sstevel@tonic-gate 	 */
1498*7c478bd9Sstevel@tonic-gate 	if (mir->mir_svc_no_more_msgs) {
1499*7c478bd9Sstevel@tonic-gate 		ASSERT(mir->mir_type == RPC_SERVER);
1500*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
1501*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1502*7c478bd9Sstevel@tonic-gate 		return;
1503*7c478bd9Sstevel@tonic-gate 	}
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	/* Get local copies for quicker access. */
1506*7c478bd9Sstevel@tonic-gate 	frag_len = mir->mir_frag_len;
1507*7c478bd9Sstevel@tonic-gate 	frag_header = mir->mir_frag_header;
1508*7c478bd9Sstevel@tonic-gate 	head_mp = mir->mir_head_mp;
1509*7c478bd9Sstevel@tonic-gate 	tail_mp = mir->mir_tail_mp;
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	/* Loop, processing each message block in the mp chain separately. */
1512*7c478bd9Sstevel@tonic-gate 	do {
1513*7c478bd9Sstevel@tonic-gate 		/*
1514*7c478bd9Sstevel@tonic-gate 		 * cont_mp is used in the do/while condition below to
1515*7c478bd9Sstevel@tonic-gate 		 * walk to the next block in the STREAMS message.
1516*7c478bd9Sstevel@tonic-gate 		 * mp->b_cont may be nil'ed during processing so we
1517*7c478bd9Sstevel@tonic-gate 		 * can't rely on it to find the next block.
1518*7c478bd9Sstevel@tonic-gate 		 */
1519*7c478bd9Sstevel@tonic-gate 		cont_mp = mp->b_cont;
1520*7c478bd9Sstevel@tonic-gate 
1521*7c478bd9Sstevel@tonic-gate 		/*
1522*7c478bd9Sstevel@tonic-gate 		 * Get local copies of rptr and wptr for our processing.
1523*7c478bd9Sstevel@tonic-gate 		 * These always point into "mp" (the current block being
1524*7c478bd9Sstevel@tonic-gate 		 * processed), but rptr is updated as we consume any
1525*7c478bd9Sstevel@tonic-gate 		 * record header in this message, and wptr is updated to
1526*7c478bd9Sstevel@tonic-gate 		 * point to the end of the data for the current fragment,
1527*7c478bd9Sstevel@tonic-gate 		 * if it ends in this block.  The main point is that
1528*7c478bd9Sstevel@tonic-gate 		 * they are not always the same as b_rptr and b_wptr.
1529*7c478bd9Sstevel@tonic-gate 		 * b_rptr and b_wptr will be updated when appropriate.
1530*7c478bd9Sstevel@tonic-gate 		 */
1531*7c478bd9Sstevel@tonic-gate 		rptr = mp->b_rptr;
1532*7c478bd9Sstevel@tonic-gate 		wptr = mp->b_wptr;
1533*7c478bd9Sstevel@tonic-gate same_mblk:;
1534*7c478bd9Sstevel@tonic-gate 		len = (int)(wptr - rptr);
1535*7c478bd9Sstevel@tonic-gate 		if (len <= 0) {
1536*7c478bd9Sstevel@tonic-gate 			/*
1537*7c478bd9Sstevel@tonic-gate 			 * If we have processed all of the data in the message
1538*7c478bd9Sstevel@tonic-gate 			 * or the block is empty to begin with, then we're
1539*7c478bd9Sstevel@tonic-gate 			 * done with this block and can go on to cont_mp,
1540*7c478bd9Sstevel@tonic-gate 			 * if there is one.
1541*7c478bd9Sstevel@tonic-gate 			 *
1542*7c478bd9Sstevel@tonic-gate 			 * First, we check to see if the current block is
1543*7c478bd9Sstevel@tonic-gate 			 * now zero-length and, if so, we free it.
1544*7c478bd9Sstevel@tonic-gate 			 * This happens when either the block was empty
1545*7c478bd9Sstevel@tonic-gate 			 * to begin with or we consumed all of the data
1546*7c478bd9Sstevel@tonic-gate 			 * for the record marking header.
1547*7c478bd9Sstevel@tonic-gate 			 */
1548*7c478bd9Sstevel@tonic-gate 			if (rptr <= mp->b_rptr) {
1549*7c478bd9Sstevel@tonic-gate 				/*
1550*7c478bd9Sstevel@tonic-gate 				 * If head_mp is non-NULL, add cont_mp to the
1551*7c478bd9Sstevel@tonic-gate 				 * mblk list. XXX But there is a possibility
1552*7c478bd9Sstevel@tonic-gate 				 * that tail_mp = mp or even head_mp = mp XXX
1553*7c478bd9Sstevel@tonic-gate 				 */
1554*7c478bd9Sstevel@tonic-gate 				if (head_mp) {
1555*7c478bd9Sstevel@tonic-gate 					if (head_mp == mp)
1556*7c478bd9Sstevel@tonic-gate 						head_mp = NULL;
1557*7c478bd9Sstevel@tonic-gate 					else if (tail_mp != mp) {
1558*7c478bd9Sstevel@tonic-gate 		ASSERT((tail_mp->b_cont == NULL) || (tail_mp->b_cont == mp));
1559*7c478bd9Sstevel@tonic-gate 						tail_mp->b_cont = cont_mp;
1560*7c478bd9Sstevel@tonic-gate 						/*
1561*7c478bd9Sstevel@tonic-gate 						 * It's possible that, because
1562*7c478bd9Sstevel@tonic-gate 						 * of a very short mblk (0-3
1563*7c478bd9Sstevel@tonic-gate 						 * bytes), we've ended up here
1564*7c478bd9Sstevel@tonic-gate 						 * and that cont_mp could be
1565*7c478bd9Sstevel@tonic-gate 						 * NULL (if we're at the end
1566*7c478bd9Sstevel@tonic-gate 						 * of an mblk chain). If so,
1567*7c478bd9Sstevel@tonic-gate 						 * don't set tail_mp to
1568*7c478bd9Sstevel@tonic-gate 						 * cont_mp, because the next
1569*7c478bd9Sstevel@tonic-gate 						 * time we access it, we'll
1570*7c478bd9Sstevel@tonic-gate 						 * dereference a NULL pointer
1571*7c478bd9Sstevel@tonic-gate 						 * and crash. Just leave
1572*7c478bd9Sstevel@tonic-gate 						 * tail_mp pointing at the
1573*7c478bd9Sstevel@tonic-gate 						 * current end of chain.
1574*7c478bd9Sstevel@tonic-gate 						 */
1575*7c478bd9Sstevel@tonic-gate 						if (cont_mp)
1576*7c478bd9Sstevel@tonic-gate 							tail_mp = cont_mp;
1577*7c478bd9Sstevel@tonic-gate 					} else {
1578*7c478bd9Sstevel@tonic-gate 						mblk_t *smp = head_mp;
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 						while ((smp->b_cont != NULL) &&
1581*7c478bd9Sstevel@tonic-gate 							(smp->b_cont != mp))
1582*7c478bd9Sstevel@tonic-gate 							smp = smp->b_cont;
1583*7c478bd9Sstevel@tonic-gate 						smp->b_cont = cont_mp;
1584*7c478bd9Sstevel@tonic-gate 						/*
1585*7c478bd9Sstevel@tonic-gate 						 * Don't set tail_mp to cont_mp
1586*7c478bd9Sstevel@tonic-gate 						 * if it's NULL. Instead, set
1587*7c478bd9Sstevel@tonic-gate 						 * tail_mp to smp, which is the
1588*7c478bd9Sstevel@tonic-gate 						 * end of the chain starting
1589*7c478bd9Sstevel@tonic-gate 						 * at head_mp.
1590*7c478bd9Sstevel@tonic-gate 						 */
1591*7c478bd9Sstevel@tonic-gate 						if (cont_mp)
1592*7c478bd9Sstevel@tonic-gate 							tail_mp = cont_mp;
1593*7c478bd9Sstevel@tonic-gate 						else
1594*7c478bd9Sstevel@tonic-gate 							tail_mp = smp;
1595*7c478bd9Sstevel@tonic-gate 					}
1596*7c478bd9Sstevel@tonic-gate 				}
1597*7c478bd9Sstevel@tonic-gate 				freeb(mp);
1598*7c478bd9Sstevel@tonic-gate 			}
1599*7c478bd9Sstevel@tonic-gate 			continue;
1600*7c478bd9Sstevel@tonic-gate 		}
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 		/*
1603*7c478bd9Sstevel@tonic-gate 		 * frag_len starts at -4 and is incremented past the record
1604*7c478bd9Sstevel@tonic-gate 		 * marking header to 0, and then becomes positive as real data
1605*7c478bd9Sstevel@tonic-gate 		 * bytes are received for the message.  While frag_len is less
1606*7c478bd9Sstevel@tonic-gate 		 * than zero, we need more bytes for the record marking
1607*7c478bd9Sstevel@tonic-gate 		 * header.
1608*7c478bd9Sstevel@tonic-gate 		 */
1609*7c478bd9Sstevel@tonic-gate 		if (frag_len < 0) {
1610*7c478bd9Sstevel@tonic-gate 			uchar_t	*up = rptr;
1611*7c478bd9Sstevel@tonic-gate 			/*
1612*7c478bd9Sstevel@tonic-gate 			 * Collect as many bytes as we need for the record
1613*7c478bd9Sstevel@tonic-gate 			 * marking header and that are available in this block.
1614*7c478bd9Sstevel@tonic-gate 			 */
1615*7c478bd9Sstevel@tonic-gate 			do {
1616*7c478bd9Sstevel@tonic-gate 				--len;
1617*7c478bd9Sstevel@tonic-gate 				frag_len++;
1618*7c478bd9Sstevel@tonic-gate 				frag_header <<= 8;
1619*7c478bd9Sstevel@tonic-gate 				frag_header += (*up++ & 0xFF);
1620*7c478bd9Sstevel@tonic-gate 			} while (len > 0 && frag_len < 0);
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate 			if (rptr == mp->b_rptr) {
1623*7c478bd9Sstevel@tonic-gate 				/*
1624*7c478bd9Sstevel@tonic-gate 				 * The record header is located at the
1625*7c478bd9Sstevel@tonic-gate 				 * beginning of the block, so just walk
1626*7c478bd9Sstevel@tonic-gate 				 * b_rptr past it.
1627*7c478bd9Sstevel@tonic-gate 				 */
1628*7c478bd9Sstevel@tonic-gate 				mp->b_rptr = rptr = up;
1629*7c478bd9Sstevel@tonic-gate 			} else {
1630*7c478bd9Sstevel@tonic-gate 				/*
1631*7c478bd9Sstevel@tonic-gate 				 * The record header is located in the middle
1632*7c478bd9Sstevel@tonic-gate 				 * of a block, so copy any remaining data up.
1633*7c478bd9Sstevel@tonic-gate 				 * This happens when an RPC message is
1634*7c478bd9Sstevel@tonic-gate 				 * fragmented into multiple pieces and
1635*7c478bd9Sstevel@tonic-gate 				 * a middle (or end) fragment immediately
1636*7c478bd9Sstevel@tonic-gate 				 * follows a previous fragment in the same
1637*7c478bd9Sstevel@tonic-gate 				 * message block.
1638*7c478bd9Sstevel@tonic-gate 				 */
1639*7c478bd9Sstevel@tonic-gate 				wptr = &rptr[len];
1640*7c478bd9Sstevel@tonic-gate 				mp->b_wptr = wptr;
1641*7c478bd9Sstevel@tonic-gate 				if (len) {
1642*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, "mir_do_rput: copying %d "
1643*7c478bd9Sstevel@tonic-gate 					    "bytes of data up", len);
1644*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, " db_ref %d\n",
1645*7c478bd9Sstevel@tonic-gate 					    (uint_t)mp->b_datap->db_ref);
1646*7c478bd9Sstevel@tonic-gate 					bcopy(up, rptr, len);
1647*7c478bd9Sstevel@tonic-gate 				}
1648*7c478bd9Sstevel@tonic-gate 			}
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 			/*
1651*7c478bd9Sstevel@tonic-gate 			 * If we haven't received the complete record header
1652*7c478bd9Sstevel@tonic-gate 			 * yet, then loop around to get the next block in the
1653*7c478bd9Sstevel@tonic-gate 			 * STREAMS message. The logic at same_mblk label will
1654*7c478bd9Sstevel@tonic-gate 			 * free the current block if it has become empty.
1655*7c478bd9Sstevel@tonic-gate 			 */
1656*7c478bd9Sstevel@tonic-gate 			if (frag_len < 0) {
1657*7c478bd9Sstevel@tonic-gate 				RPCLOG(32, "mir_do_rput: frag_len is still < 0 "
1658*7c478bd9Sstevel@tonic-gate 				"(%d)", len);
1659*7c478bd9Sstevel@tonic-gate 				goto same_mblk;
1660*7c478bd9Sstevel@tonic-gate 			}
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate #ifdef	RPCDEBUG
1663*7c478bd9Sstevel@tonic-gate 			if ((frag_header & MIR_LASTFRAG) == 0) {
1664*7c478bd9Sstevel@tonic-gate 				RPCLOG0(32, "mir_do_rput: multi-fragment "
1665*7c478bd9Sstevel@tonic-gate 				    "record\n");
1666*7c478bd9Sstevel@tonic-gate 			}
1667*7c478bd9Sstevel@tonic-gate 			{
1668*7c478bd9Sstevel@tonic-gate 				uint_t l = frag_header & ~MIR_LASTFRAG;
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate 				if (l != 0 && mir->mir_max_msg_sizep &&
1671*7c478bd9Sstevel@tonic-gate 				    l >= *mir->mir_max_msg_sizep) {
1672*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, "mir_do_rput: fragment size"
1673*7c478bd9Sstevel@tonic-gate 					    " (%d) > maximum", l);
1674*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, " (%u)\n",
1675*7c478bd9Sstevel@tonic-gate 					    *mir->mir_max_msg_sizep);
1676*7c478bd9Sstevel@tonic-gate 				}
1677*7c478bd9Sstevel@tonic-gate 			}
1678*7c478bd9Sstevel@tonic-gate #endif
1679*7c478bd9Sstevel@tonic-gate 			/*
1680*7c478bd9Sstevel@tonic-gate 			 * At this point we have retrieved the complete record
1681*7c478bd9Sstevel@tonic-gate 			 * header for this fragment.  If the current block is
1682*7c478bd9Sstevel@tonic-gate 			 * empty, then we need to free it and walk to the next
1683*7c478bd9Sstevel@tonic-gate 			 * block.
1684*7c478bd9Sstevel@tonic-gate 			 */
1685*7c478bd9Sstevel@tonic-gate 			if (mp->b_rptr >= wptr) {
1686*7c478bd9Sstevel@tonic-gate 				/*
1687*7c478bd9Sstevel@tonic-gate 				 * If this is not the last fragment or if we
1688*7c478bd9Sstevel@tonic-gate 				 * have not received all the data for this
1689*7c478bd9Sstevel@tonic-gate 				 * RPC message, then loop around to the next
1690*7c478bd9Sstevel@tonic-gate 				 * block.
1691*7c478bd9Sstevel@tonic-gate 				 */
1692*7c478bd9Sstevel@tonic-gate 				if (!(frag_header & MIR_LASTFRAG) ||
1693*7c478bd9Sstevel@tonic-gate 					(frag_len -
1694*7c478bd9Sstevel@tonic-gate 					(frag_header & ~MIR_LASTFRAG)) ||
1695*7c478bd9Sstevel@tonic-gate 					!head_mp)
1696*7c478bd9Sstevel@tonic-gate 					goto same_mblk;
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 				/*
1699*7c478bd9Sstevel@tonic-gate 				 * Quick walk to next block in the
1700*7c478bd9Sstevel@tonic-gate 				 * STREAMS message.
1701*7c478bd9Sstevel@tonic-gate 				 */
1702*7c478bd9Sstevel@tonic-gate 				freeb(mp);
1703*7c478bd9Sstevel@tonic-gate 				continue;
1704*7c478bd9Sstevel@tonic-gate 			}
1705*7c478bd9Sstevel@tonic-gate 		}
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 		/*
1708*7c478bd9Sstevel@tonic-gate 		 * We've collected the complete record header.  The data
1709*7c478bd9Sstevel@tonic-gate 		 * in the current block is added to the end of the RPC
1710*7c478bd9Sstevel@tonic-gate 		 * message.  Note that tail_mp is the same as mp after
1711*7c478bd9Sstevel@tonic-gate 		 * this linkage.
1712*7c478bd9Sstevel@tonic-gate 		 */
1713*7c478bd9Sstevel@tonic-gate 		if (!head_mp)
1714*7c478bd9Sstevel@tonic-gate 			head_mp = mp;
1715*7c478bd9Sstevel@tonic-gate 		else if (tail_mp != mp) {
1716*7c478bd9Sstevel@tonic-gate 			ASSERT((tail_mp->b_cont == NULL) ||
1717*7c478bd9Sstevel@tonic-gate 			    (tail_mp->b_cont == mp));
1718*7c478bd9Sstevel@tonic-gate 			tail_mp->b_cont = mp;
1719*7c478bd9Sstevel@tonic-gate 		}
1720*7c478bd9Sstevel@tonic-gate 		tail_mp = mp;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 		/*
1723*7c478bd9Sstevel@tonic-gate 		 * Add the length of this block to the accumulated
1724*7c478bd9Sstevel@tonic-gate 		 * fragment length.
1725*7c478bd9Sstevel@tonic-gate 		 */
1726*7c478bd9Sstevel@tonic-gate 		frag_len += len;
1727*7c478bd9Sstevel@tonic-gate 		excess = frag_len - (frag_header & ~MIR_LASTFRAG);
1728*7c478bd9Sstevel@tonic-gate 		/*
1729*7c478bd9Sstevel@tonic-gate 		 * If we have not received all the data for this fragment,
1730*7c478bd9Sstevel@tonic-gate 		 * then walk to the next block.
1731*7c478bd9Sstevel@tonic-gate 		 */
1732*7c478bd9Sstevel@tonic-gate 		if (excess < 0)
1733*7c478bd9Sstevel@tonic-gate 			continue;
1734*7c478bd9Sstevel@tonic-gate 
1735*7c478bd9Sstevel@tonic-gate 		/*
1736*7c478bd9Sstevel@tonic-gate 		 * We've received a complete fragment, so reset frag_len
1737*7c478bd9Sstevel@tonic-gate 		 * for the next one.
1738*7c478bd9Sstevel@tonic-gate 		 */
1739*7c478bd9Sstevel@tonic-gate 		frag_len = -(int32_t)sizeof (uint32_t);
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate 		/*
1742*7c478bd9Sstevel@tonic-gate 		 * Update rptr to point to the beginning of the next
1743*7c478bd9Sstevel@tonic-gate 		 * fragment in this block.  If there are no more bytes
1744*7c478bd9Sstevel@tonic-gate 		 * in the block (excess is 0), then rptr will be equal
1745*7c478bd9Sstevel@tonic-gate 		 * to wptr.
1746*7c478bd9Sstevel@tonic-gate 		 */
1747*7c478bd9Sstevel@tonic-gate 		rptr = wptr - excess;
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 		/*
1750*7c478bd9Sstevel@tonic-gate 		 * Now we check to see if this fragment is the last one in
1751*7c478bd9Sstevel@tonic-gate 		 * the RPC message.
1752*7c478bd9Sstevel@tonic-gate 		 */
1753*7c478bd9Sstevel@tonic-gate 		if (!(frag_header & MIR_LASTFRAG)) {
1754*7c478bd9Sstevel@tonic-gate 			/*
1755*7c478bd9Sstevel@tonic-gate 			 * This isn't the last one, so start processing the
1756*7c478bd9Sstevel@tonic-gate 			 * next fragment.
1757*7c478bd9Sstevel@tonic-gate 			 */
1758*7c478bd9Sstevel@tonic-gate 			frag_header = 0;
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 			/*
1761*7c478bd9Sstevel@tonic-gate 			 * If excess is 0, the next fragment
1762*7c478bd9Sstevel@tonic-gate 			 * starts at the beginning of the next block --
1763*7c478bd9Sstevel@tonic-gate 			 * we "continue" to the end of the while loop and
1764*7c478bd9Sstevel@tonic-gate 			 * walk to cont_mp.
1765*7c478bd9Sstevel@tonic-gate 			 */
1766*7c478bd9Sstevel@tonic-gate 			if (excess == 0)
1767*7c478bd9Sstevel@tonic-gate 				continue;
1768*7c478bd9Sstevel@tonic-gate 			RPCLOG0(32, "mir_do_rput: multi-fragment message with "
1769*7c478bd9Sstevel@tonic-gate 			    "two or more fragments in one mblk\n");
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 			/*
1772*7c478bd9Sstevel@tonic-gate 			 * If excess is non-0, then the next fragment starts
1773*7c478bd9Sstevel@tonic-gate 			 * in this block.  rptr points to the beginning
1774*7c478bd9Sstevel@tonic-gate 			 * of the next fragment and we "goto same_mblk"
1775*7c478bd9Sstevel@tonic-gate 			 * to continue processing.
1776*7c478bd9Sstevel@tonic-gate 			 */
1777*7c478bd9Sstevel@tonic-gate 			goto same_mblk;
1778*7c478bd9Sstevel@tonic-gate 		}
1779*7c478bd9Sstevel@tonic-gate 
1780*7c478bd9Sstevel@tonic-gate 		/*
1781*7c478bd9Sstevel@tonic-gate 		 * We've got a complete RPC message.  Before passing it
1782*7c478bd9Sstevel@tonic-gate 		 * upstream, check to see if there is extra data in this
1783*7c478bd9Sstevel@tonic-gate 		 * message block. If so, then we separate the excess
1784*7c478bd9Sstevel@tonic-gate 		 * from the complete message. The excess data is processed
1785*7c478bd9Sstevel@tonic-gate 		 * after the current message goes upstream.
1786*7c478bd9Sstevel@tonic-gate 		 */
1787*7c478bd9Sstevel@tonic-gate 		if (excess > 0) {
1788*7c478bd9Sstevel@tonic-gate 			RPCLOG(32, "mir_do_rput: end of record, but excess "
1789*7c478bd9Sstevel@tonic-gate 			    "data (%d bytes) in this mblk. dupb/copyb "
1790*7c478bd9Sstevel@tonic-gate 			    "needed\n", excess);
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate 			/* Duplicate only the overlapping block. */
1793*7c478bd9Sstevel@tonic-gate 			mp1 = dupb(tail_mp);
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 			/*
1796*7c478bd9Sstevel@tonic-gate 			 * dupb() might have failed due to ref count wrap around
1797*7c478bd9Sstevel@tonic-gate 			 * so try a copyb().
1798*7c478bd9Sstevel@tonic-gate 			 */
1799*7c478bd9Sstevel@tonic-gate 			if (mp1 == NULL)
1800*7c478bd9Sstevel@tonic-gate 				mp1 = copyb(tail_mp);
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate 			/*
1803*7c478bd9Sstevel@tonic-gate 			 * Do not use bufcall() to schedule a "buffer
1804*7c478bd9Sstevel@tonic-gate 			 * availability event."  The reason is that
1805*7c478bd9Sstevel@tonic-gate 			 * bufcall() has problems.  For example, if memory
1806*7c478bd9Sstevel@tonic-gate 			 * runs out, bufcall() itself will fail since it
1807*7c478bd9Sstevel@tonic-gate 			 * needs to allocate memory.  The most appropriate
1808*7c478bd9Sstevel@tonic-gate 			 * action right now is to disconnect this connection
1809*7c478bd9Sstevel@tonic-gate 			 * as the system is under stress.  We should try to
1810*7c478bd9Sstevel@tonic-gate 			 * free up resources.
1811*7c478bd9Sstevel@tonic-gate 			 */
1812*7c478bd9Sstevel@tonic-gate 			if (mp1 == NULL) {
1813*7c478bd9Sstevel@tonic-gate 				freemsg(head_mp);
1814*7c478bd9Sstevel@tonic-gate 				RPCLOG0(1, "mir_do_rput: dupb/copyb failed\n");
1815*7c478bd9Sstevel@tonic-gate 				mir->mir_frag_header = 0;
1816*7c478bd9Sstevel@tonic-gate 				mir->mir_frag_len = -(int)sizeof (uint32_t);
1817*7c478bd9Sstevel@tonic-gate 				mir->mir_head_mp = NULL;
1818*7c478bd9Sstevel@tonic-gate 				mir->mir_tail_mp = NULL;
1819*7c478bd9Sstevel@tonic-gate 
1820*7c478bd9Sstevel@tonic-gate 				mir_disconnect(q, mir);
1821*7c478bd9Sstevel@tonic-gate 				return;
1822*7c478bd9Sstevel@tonic-gate 			}
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 			/*
1825*7c478bd9Sstevel@tonic-gate 			 * The new message block is linked with the
1826*7c478bd9Sstevel@tonic-gate 			 * continuation block in cont_mp.  We then point
1827*7c478bd9Sstevel@tonic-gate 			 * cont_mp to the new block so that we will
1828*7c478bd9Sstevel@tonic-gate 			 * process it next.
1829*7c478bd9Sstevel@tonic-gate 			 */
1830*7c478bd9Sstevel@tonic-gate 			mp1->b_cont = cont_mp;
1831*7c478bd9Sstevel@tonic-gate 			cont_mp = mp1;
1832*7c478bd9Sstevel@tonic-gate 			/*
1833*7c478bd9Sstevel@tonic-gate 			 * Data in the new block begins at the
1834*7c478bd9Sstevel@tonic-gate 			 * next fragment (rptr).
1835*7c478bd9Sstevel@tonic-gate 			 */
1836*7c478bd9Sstevel@tonic-gate 			cont_mp->b_rptr += (rptr - tail_mp->b_rptr);
1837*7c478bd9Sstevel@tonic-gate 			ASSERT(cont_mp->b_rptr >= cont_mp->b_datap->db_base);
1838*7c478bd9Sstevel@tonic-gate 			ASSERT(cont_mp->b_rptr <= cont_mp->b_wptr);
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 			/* Data in the current fragment ends at rptr. */
1841*7c478bd9Sstevel@tonic-gate 			tail_mp->b_wptr = rptr;
1842*7c478bd9Sstevel@tonic-gate 			ASSERT(tail_mp->b_wptr <= tail_mp->b_datap->db_lim);
1843*7c478bd9Sstevel@tonic-gate 			ASSERT(tail_mp->b_wptr >= tail_mp->b_rptr);
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 		}
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 		/* tail_mp is the last block with data for this RPC message. */
1848*7c478bd9Sstevel@tonic-gate 		tail_mp->b_cont = NULL;
1849*7c478bd9Sstevel@tonic-gate 
1850*7c478bd9Sstevel@tonic-gate 		/* Pass the RPC message to the current consumer. */
1851*7c478bd9Sstevel@tonic-gate 		switch (mir->mir_type) {
1852*7c478bd9Sstevel@tonic-gate 		case RPC_CLIENT:
1853*7c478bd9Sstevel@tonic-gate 			if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) {
1854*7c478bd9Sstevel@tonic-gate 				/*
1855*7c478bd9Sstevel@tonic-gate 				 * Mark this stream as active.  This marker
1856*7c478bd9Sstevel@tonic-gate 				 * is used in mir_timer().
1857*7c478bd9Sstevel@tonic-gate 				 */
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 				mir->mir_clntreq = 1;
1860*7c478bd9Sstevel@tonic-gate 				mir->mir_use_timestamp = lbolt;
1861*7c478bd9Sstevel@tonic-gate 			} else
1862*7c478bd9Sstevel@tonic-gate 				freemsg(head_mp);
1863*7c478bd9Sstevel@tonic-gate 			break;
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 		case RPC_SERVER:
1866*7c478bd9Sstevel@tonic-gate 			/*
1867*7c478bd9Sstevel@tonic-gate 			 * Check for flow control before passing the
1868*7c478bd9Sstevel@tonic-gate 			 * message to KRPC.
1869*7c478bd9Sstevel@tonic-gate 			 */
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 			if (!mir->mir_hold_inbound) {
1872*7c478bd9Sstevel@tonic-gate 			    if (mir->mir_krpc_cell) {
1873*7c478bd9Sstevel@tonic-gate 				/*
1874*7c478bd9Sstevel@tonic-gate 				 * If the reference count is 0
1875*7c478bd9Sstevel@tonic-gate 				 * (not including this request),
1876*7c478bd9Sstevel@tonic-gate 				 * then the stream is transitioning
1877*7c478bd9Sstevel@tonic-gate 				 * from idle to non-idle.  In this case,
1878*7c478bd9Sstevel@tonic-gate 				 * we cancel the idle timer.
1879*7c478bd9Sstevel@tonic-gate 				 */
1880*7c478bd9Sstevel@tonic-gate 				if (mir->mir_ref_cnt++ == 0)
1881*7c478bd9Sstevel@tonic-gate 					stop_timer = B_TRUE;
1882*7c478bd9Sstevel@tonic-gate 				if (mir_check_len(q,
1883*7c478bd9Sstevel@tonic-gate 					(int32_t)msgdsize(mp), mp))
1884*7c478bd9Sstevel@tonic-gate 						return;
1885*7c478bd9Sstevel@tonic-gate 				svc_queuereq(q, head_mp); /* to KRPC */
1886*7c478bd9Sstevel@tonic-gate 			    } else {
1887*7c478bd9Sstevel@tonic-gate 				/*
1888*7c478bd9Sstevel@tonic-gate 				 * Count # of times this happens. Should be
1889*7c478bd9Sstevel@tonic-gate 				 * never, but experience shows otherwise.
1890*7c478bd9Sstevel@tonic-gate 				 */
1891*7c478bd9Sstevel@tonic-gate 				mir_krpc_cell_null++;
1892*7c478bd9Sstevel@tonic-gate 				freemsg(head_mp);
1893*7c478bd9Sstevel@tonic-gate 			    }
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate 			} else {
1896*7c478bd9Sstevel@tonic-gate 				/*
1897*7c478bd9Sstevel@tonic-gate 				 * If the outbound side of the stream is
1898*7c478bd9Sstevel@tonic-gate 				 * flow controlled, then hold this message
1899*7c478bd9Sstevel@tonic-gate 				 * until client catches up. mir_hold_inbound
1900*7c478bd9Sstevel@tonic-gate 				 * is set in mir_wput and cleared in mir_wsrv.
1901*7c478bd9Sstevel@tonic-gate 				 */
1902*7c478bd9Sstevel@tonic-gate 				if (srv)
1903*7c478bd9Sstevel@tonic-gate 					(void) putbq(q, head_mp);
1904*7c478bd9Sstevel@tonic-gate 				else
1905*7c478bd9Sstevel@tonic-gate 					(void) putq(q, head_mp);
1906*7c478bd9Sstevel@tonic-gate 				mir->mir_inrservice = B_TRUE;
1907*7c478bd9Sstevel@tonic-gate 			}
1908*7c478bd9Sstevel@tonic-gate 			break;
1909*7c478bd9Sstevel@tonic-gate 		default:
1910*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: unknown mir_type %d\n",
1911*7c478bd9Sstevel@tonic-gate 				mir->mir_type);
1912*7c478bd9Sstevel@tonic-gate 			freemsg(head_mp);
1913*7c478bd9Sstevel@tonic-gate 			break;
1914*7c478bd9Sstevel@tonic-gate 		}
1915*7c478bd9Sstevel@tonic-gate 
1916*7c478bd9Sstevel@tonic-gate 		/*
1917*7c478bd9Sstevel@tonic-gate 		 * Reset head_mp and frag_header since we're starting on a
1918*7c478bd9Sstevel@tonic-gate 		 * new RPC fragment and message.
1919*7c478bd9Sstevel@tonic-gate 		 */
1920*7c478bd9Sstevel@tonic-gate 		head_mp = NULL;
1921*7c478bd9Sstevel@tonic-gate 		tail_mp = NULL;
1922*7c478bd9Sstevel@tonic-gate 		frag_header = 0;
1923*7c478bd9Sstevel@tonic-gate 	} while ((mp = cont_mp) != NULL);
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 	/*
1926*7c478bd9Sstevel@tonic-gate 	 * Do a sanity check on the message length.  If this message is
1927*7c478bd9Sstevel@tonic-gate 	 * getting excessively large, shut down the connection.
1928*7c478bd9Sstevel@tonic-gate 	 */
1929*7c478bd9Sstevel@tonic-gate 	if (head_mp != NULL && mir->mir_setup_complete &&
1930*7c478bd9Sstevel@tonic-gate 		mir_check_len(q, frag_len, head_mp))
1931*7c478bd9Sstevel@tonic-gate 		return;
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	/* Save our local copies back in the mir structure. */
1934*7c478bd9Sstevel@tonic-gate 	mir->mir_frag_header = frag_header;
1935*7c478bd9Sstevel@tonic-gate 	mir->mir_frag_len = frag_len;
1936*7c478bd9Sstevel@tonic-gate 	mir->mir_head_mp = head_mp;
1937*7c478bd9Sstevel@tonic-gate 	mir->mir_tail_mp = tail_mp;
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	/*
1940*7c478bd9Sstevel@tonic-gate 	 * The timer is stopped after the whole message chain is processed.
1941*7c478bd9Sstevel@tonic-gate 	 * The reason is that stopping the timer releases the mir_mutex
1942*7c478bd9Sstevel@tonic-gate 	 * lock temporarily.  This means that the request can be serviced
1943*7c478bd9Sstevel@tonic-gate 	 * while we are still processing the message chain.  This is not
1944*7c478bd9Sstevel@tonic-gate 	 * good.  So we stop the timer here instead.
1945*7c478bd9Sstevel@tonic-gate 	 *
1946*7c478bd9Sstevel@tonic-gate 	 * Note that if the timer fires before we stop it, it will not
1947*7c478bd9Sstevel@tonic-gate 	 * do any harm as MIR_SVC_QUIESCED() is false and mir_timer()
1948*7c478bd9Sstevel@tonic-gate 	 * will just return;
1949*7c478bd9Sstevel@tonic-gate 	 */
1950*7c478bd9Sstevel@tonic-gate 	if (stop_timer) {
1951*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_do_rput stopping idle timer on 0x%p because "
1952*7c478bd9Sstevel@tonic-gate 		    "ref cnt going to non zero\n", (void *) WR(q));
1953*7c478bd9Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
1954*7c478bd9Sstevel@tonic-gate 	}
1955*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
1956*7c478bd9Sstevel@tonic-gate }
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate static void
1959*7c478bd9Sstevel@tonic-gate mir_rput(queue_t *q, mblk_t *mp)
1960*7c478bd9Sstevel@tonic-gate {
1961*7c478bd9Sstevel@tonic-gate 	mir_do_rput(q, mp, 0);
1962*7c478bd9Sstevel@tonic-gate }
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate static void
1965*7c478bd9Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp)
1966*7c478bd9Sstevel@tonic-gate {
1967*7c478bd9Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
1968*7c478bd9Sstevel@tonic-gate 	uint32_t	type;
1969*7c478bd9Sstevel@tonic-gate 	uint32_t reason = 0;
1970*7c478bd9Sstevel@tonic-gate 
1971*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	type = ((union T_primitives *)mp->b_rptr)->type;
1974*7c478bd9Sstevel@tonic-gate 	switch (mir->mir_type) {
1975*7c478bd9Sstevel@tonic-gate 	case RPC_CLIENT:
1976*7c478bd9Sstevel@tonic-gate 		switch (type) {
1977*7c478bd9Sstevel@tonic-gate 		case T_DISCON_IND:
1978*7c478bd9Sstevel@tonic-gate 		    reason =
1979*7c478bd9Sstevel@tonic-gate 			((struct T_discon_ind *)(mp->b_rptr))->DISCON_reason;
1980*7c478bd9Sstevel@tonic-gate 		    /*FALLTHROUGH*/
1981*7c478bd9Sstevel@tonic-gate 		case T_ORDREL_IND:
1982*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
1983*7c478bd9Sstevel@tonic-gate 			if (mir->mir_head_mp) {
1984*7c478bd9Sstevel@tonic-gate 				freemsg(mir->mir_head_mp);
1985*7c478bd9Sstevel@tonic-gate 				mir->mir_head_mp = (mblk_t *)0;
1986*7c478bd9Sstevel@tonic-gate 				mir->mir_tail_mp = (mblk_t *)0;
1987*7c478bd9Sstevel@tonic-gate 			}
1988*7c478bd9Sstevel@tonic-gate 			/*
1989*7c478bd9Sstevel@tonic-gate 			 * We are disconnecting, but not necessarily
1990*7c478bd9Sstevel@tonic-gate 			 * closing. By not closing, we will fail to
1991*7c478bd9Sstevel@tonic-gate 			 * pick up a possibly changed global timeout value,
1992*7c478bd9Sstevel@tonic-gate 			 * unless we store it now.
1993*7c478bd9Sstevel@tonic-gate 			 */
1994*7c478bd9Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
1995*7c478bd9Sstevel@tonic-gate 			mir_clnt_idle_stop(WR(q), mir);
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 			/*
1998*7c478bd9Sstevel@tonic-gate 			 * Even though we are unconnected, we still
1999*7c478bd9Sstevel@tonic-gate 			 * leave the idle timer going on the client. The
2000*7c478bd9Sstevel@tonic-gate 			 * reason for is that if we've disconnected due
2001*7c478bd9Sstevel@tonic-gate 			 * to a server-side disconnect, reset, or connection
2002*7c478bd9Sstevel@tonic-gate 			 * timeout, there is a possibility the client may
2003*7c478bd9Sstevel@tonic-gate 			 * retry the RPC request. This retry needs to done on
2004*7c478bd9Sstevel@tonic-gate 			 * the same bound address for the server to interpret
2005*7c478bd9Sstevel@tonic-gate 			 * it as such. However, we don't want
2006*7c478bd9Sstevel@tonic-gate 			 * to wait forever for that possibility. If the
2007*7c478bd9Sstevel@tonic-gate 			 * end-point stays unconnected for mir_idle_timeout
2008*7c478bd9Sstevel@tonic-gate 			 * units of time, then that is a signal to the
2009*7c478bd9Sstevel@tonic-gate 			 * connection manager to give up waiting for the
2010*7c478bd9Sstevel@tonic-gate 			 * application (eg. NFS) to send a retry.
2011*7c478bd9Sstevel@tonic-gate 			 */
2012*7c478bd9Sstevel@tonic-gate 			mir_clnt_idle_start(WR(q), mir);
2013*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2014*7c478bd9Sstevel@tonic-gate 			clnt_dispatch_notifyall(WR(q), type, reason);
2015*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2016*7c478bd9Sstevel@tonic-gate 			return;
2017*7c478bd9Sstevel@tonic-gate 		case T_ERROR_ACK:
2018*7c478bd9Sstevel@tonic-gate 		{
2019*7c478bd9Sstevel@tonic-gate 			struct T_error_ack	*terror;
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 			terror = (struct T_error_ack *)mp->b_rptr;
2022*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p",
2023*7c478bd9Sstevel@tonic-gate 				(void *)q);
2024*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, " ERROR_prim: %s,",
2025*7c478bd9Sstevel@tonic-gate 				rpc_tpiprim2name(terror->ERROR_prim));
2026*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, " TLI_error: %s,",
2027*7c478bd9Sstevel@tonic-gate 				rpc_tpierr2name(terror->TLI_error));
2028*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error);
2029*7c478bd9Sstevel@tonic-gate 			if (terror->ERROR_prim == T_DISCON_REQ)  {
2030*7c478bd9Sstevel@tonic-gate 				clnt_dispatch_notifyall(WR(q), type, reason);
2031*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
2032*7c478bd9Sstevel@tonic-gate 				return;
2033*7c478bd9Sstevel@tonic-gate 			} else {
2034*7c478bd9Sstevel@tonic-gate 				if (clnt_dispatch_notifyconn(WR(q), mp))
2035*7c478bd9Sstevel@tonic-gate 					return;
2036*7c478bd9Sstevel@tonic-gate 			}
2037*7c478bd9Sstevel@tonic-gate 			break;
2038*7c478bd9Sstevel@tonic-gate 		}
2039*7c478bd9Sstevel@tonic-gate 		case T_OK_ACK:
2040*7c478bd9Sstevel@tonic-gate 		{
2041*7c478bd9Sstevel@tonic-gate 			struct T_ok_ack	*tok = (struct T_ok_ack *)mp->b_rptr;
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate 			if (tok->CORRECT_prim == T_DISCON_REQ) {
2044*7c478bd9Sstevel@tonic-gate 				clnt_dispatch_notifyall(WR(q), type, reason);
2045*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
2046*7c478bd9Sstevel@tonic-gate 				return;
2047*7c478bd9Sstevel@tonic-gate 			} else {
2048*7c478bd9Sstevel@tonic-gate 				if (clnt_dispatch_notifyconn(WR(q), mp))
2049*7c478bd9Sstevel@tonic-gate 					return;
2050*7c478bd9Sstevel@tonic-gate 			}
2051*7c478bd9Sstevel@tonic-gate 			break;
2052*7c478bd9Sstevel@tonic-gate 		}
2053*7c478bd9Sstevel@tonic-gate 		case T_CONN_CON:
2054*7c478bd9Sstevel@tonic-gate 		case T_INFO_ACK:
2055*7c478bd9Sstevel@tonic-gate 		case T_OPTMGMT_ACK:
2056*7c478bd9Sstevel@tonic-gate 			if (clnt_dispatch_notifyconn(WR(q), mp))
2057*7c478bd9Sstevel@tonic-gate 				return;
2058*7c478bd9Sstevel@tonic-gate 			break;
2059*7c478bd9Sstevel@tonic-gate 		case T_BIND_ACK:
2060*7c478bd9Sstevel@tonic-gate 			break;
2061*7c478bd9Sstevel@tonic-gate 		default:
2062*7c478bd9Sstevel@tonic-gate 			RPCLOG(1, "mir_rput: unexpected message %d "
2063*7c478bd9Sstevel@tonic-gate 			    "for KRPC client\n",
2064*7c478bd9Sstevel@tonic-gate 			    ((union T_primitives *)mp->b_rptr)->type);
2065*7c478bd9Sstevel@tonic-gate 			break;
2066*7c478bd9Sstevel@tonic-gate 		}
2067*7c478bd9Sstevel@tonic-gate 		break;
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 	case RPC_SERVER:
2070*7c478bd9Sstevel@tonic-gate 		switch (type) {
2071*7c478bd9Sstevel@tonic-gate 		case T_BIND_ACK:
2072*7c478bd9Sstevel@tonic-gate 		{
2073*7c478bd9Sstevel@tonic-gate 			struct T_bind_ack	*tbind;
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 			/*
2076*7c478bd9Sstevel@tonic-gate 			 * If this is a listening stream, then shut
2077*7c478bd9Sstevel@tonic-gate 			 * off the idle timer.
2078*7c478bd9Sstevel@tonic-gate 			 */
2079*7c478bd9Sstevel@tonic-gate 			tbind = (struct T_bind_ack *)mp->b_rptr;
2080*7c478bd9Sstevel@tonic-gate 			if (tbind->CONIND_number > 0) {
2081*7c478bd9Sstevel@tonic-gate 				mutex_enter(&mir->mir_mutex);
2082*7c478bd9Sstevel@tonic-gate 				mir_svc_idle_stop(WR(q), mir);
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate 				/*
2085*7c478bd9Sstevel@tonic-gate 				 * mark this as a listen endpoint
2086*7c478bd9Sstevel@tonic-gate 				 * for special handling.
2087*7c478bd9Sstevel@tonic-gate 				 */
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate 				mir->mir_listen_stream = 1;
2090*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2091*7c478bd9Sstevel@tonic-gate 			}
2092*7c478bd9Sstevel@tonic-gate 			break;
2093*7c478bd9Sstevel@tonic-gate 		}
2094*7c478bd9Sstevel@tonic-gate 		case T_DISCON_IND:
2095*7c478bd9Sstevel@tonic-gate 		case T_ORDREL_IND:
2096*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_rput_proto: got %s indication\n",
2097*7c478bd9Sstevel@tonic-gate 				type == T_DISCON_IND ? "disconnect"
2098*7c478bd9Sstevel@tonic-gate 				: "orderly release");
2099*7c478bd9Sstevel@tonic-gate 
2100*7c478bd9Sstevel@tonic-gate 			/*
2101*7c478bd9Sstevel@tonic-gate 			 * For listen endpoint just pass
2102*7c478bd9Sstevel@tonic-gate 			 * on the message.
2103*7c478bd9Sstevel@tonic-gate 			 */
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 			if (mir->mir_listen_stream)
2106*7c478bd9Sstevel@tonic-gate 				break;
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
2109*7c478bd9Sstevel@tonic-gate 
2110*7c478bd9Sstevel@tonic-gate 			/*
2111*7c478bd9Sstevel@tonic-gate 			 * If client wants to break off connection, record
2112*7c478bd9Sstevel@tonic-gate 			 * that fact.
2113*7c478bd9Sstevel@tonic-gate 			 */
2114*7c478bd9Sstevel@tonic-gate 			mir_svc_start_close(WR(q), mir);
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate 			/*
2117*7c478bd9Sstevel@tonic-gate 			 * If we are idle, then send the orderly release
2118*7c478bd9Sstevel@tonic-gate 			 * or disconnect indication to nfsd.
2119*7c478bd9Sstevel@tonic-gate 			 */
2120*7c478bd9Sstevel@tonic-gate 			if (MIR_SVC_QUIESCED(mir)) {
2121*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2122*7c478bd9Sstevel@tonic-gate 				break;
2123*7c478bd9Sstevel@tonic-gate 			}
2124*7c478bd9Sstevel@tonic-gate 
2125*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_rput_proto: not idle, so "
2126*7c478bd9Sstevel@tonic-gate 				"disconnect/ord rel indication not passed "
2127*7c478bd9Sstevel@tonic-gate 				"upstream on 0x%p\n", (void *)q);
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 			/*
2130*7c478bd9Sstevel@tonic-gate 			 * Hold the indication until we get idle
2131*7c478bd9Sstevel@tonic-gate 			 * If there already is an indication stored,
2132*7c478bd9Sstevel@tonic-gate 			 * replace it if the new one is a disconnect. The
2133*7c478bd9Sstevel@tonic-gate 			 * reasoning is that disconnection takes less time
2134*7c478bd9Sstevel@tonic-gate 			 * to process, and once a client decides to
2135*7c478bd9Sstevel@tonic-gate 			 * disconnect, we should do that.
2136*7c478bd9Sstevel@tonic-gate 			 */
2137*7c478bd9Sstevel@tonic-gate 			if (mir->mir_svc_pend_mp) {
2138*7c478bd9Sstevel@tonic-gate 				if (type == T_DISCON_IND) {
2139*7c478bd9Sstevel@tonic-gate 					RPCLOG(16, "mir_rput_proto: replacing"
2140*7c478bd9Sstevel@tonic-gate 					    " held disconnect/ord rel"
2141*7c478bd9Sstevel@tonic-gate 					    " indication with disconnect on"
2142*7c478bd9Sstevel@tonic-gate 					    " 0x%p\n", (void *)q);
2143*7c478bd9Sstevel@tonic-gate 
2144*7c478bd9Sstevel@tonic-gate 					freemsg(mir->mir_svc_pend_mp);
2145*7c478bd9Sstevel@tonic-gate 					mir->mir_svc_pend_mp = mp;
2146*7c478bd9Sstevel@tonic-gate 				} else {
2147*7c478bd9Sstevel@tonic-gate 					RPCLOG(16, "mir_rput_proto: already "
2148*7c478bd9Sstevel@tonic-gate 					    "held a disconnect/ord rel "
2149*7c478bd9Sstevel@tonic-gate 					    "indication. freeing ord rel "
2150*7c478bd9Sstevel@tonic-gate 					    "ind on 0x%p\n", (void *)q);
2151*7c478bd9Sstevel@tonic-gate 					freemsg(mp);
2152*7c478bd9Sstevel@tonic-gate 				}
2153*7c478bd9Sstevel@tonic-gate 			} else
2154*7c478bd9Sstevel@tonic-gate 				mir->mir_svc_pend_mp = mp;
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2157*7c478bd9Sstevel@tonic-gate 			return;
2158*7c478bd9Sstevel@tonic-gate 
2159*7c478bd9Sstevel@tonic-gate 		default:
2160*7c478bd9Sstevel@tonic-gate 			/* nfsd handles server-side non-data messages. */
2161*7c478bd9Sstevel@tonic-gate 			break;
2162*7c478bd9Sstevel@tonic-gate 		}
2163*7c478bd9Sstevel@tonic-gate 		break;
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 	default:
2166*7c478bd9Sstevel@tonic-gate 		break;
2167*7c478bd9Sstevel@tonic-gate 	}
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
2170*7c478bd9Sstevel@tonic-gate }
2171*7c478bd9Sstevel@tonic-gate 
2172*7c478bd9Sstevel@tonic-gate /*
2173*7c478bd9Sstevel@tonic-gate  * The server-side read queues are used to hold inbound messages while
2174*7c478bd9Sstevel@tonic-gate  * outbound flow control is exerted.  When outbound flow control is
2175*7c478bd9Sstevel@tonic-gate  * relieved, mir_wsrv qenables the read-side queue.  Read-side queues
2176*7c478bd9Sstevel@tonic-gate  * are not enabled by STREAMS and are explicitly noenable'ed in mir_open.
2177*7c478bd9Sstevel@tonic-gate  *
2178*7c478bd9Sstevel@tonic-gate  * For the server side,  we have two types of messages queued. The first type
2179*7c478bd9Sstevel@tonic-gate  * are messages that are ready to be XDR decoded and and then sent to the
2180*7c478bd9Sstevel@tonic-gate  * RPC program's dispatch routine. The second type are "raw" messages that
2181*7c478bd9Sstevel@tonic-gate  * haven't been processed, i.e. assembled from rpc record fragements into
2182*7c478bd9Sstevel@tonic-gate  * full requests. The only time we will see the second type of message
2183*7c478bd9Sstevel@tonic-gate  * queued is if we have a memory allocation failure while processing a
2184*7c478bd9Sstevel@tonic-gate  * a raw message. The field mir_first_non_processed_mblk will mark the
2185*7c478bd9Sstevel@tonic-gate  * first such raw message. So the flow for server side is:
2186*7c478bd9Sstevel@tonic-gate  *
2187*7c478bd9Sstevel@tonic-gate  *	- send processed queued messages to kRPC until we run out or find
2188*7c478bd9Sstevel@tonic-gate  *	  one that needs additional processing because we were short on memory
2189*7c478bd9Sstevel@tonic-gate  *	  earlier
2190*7c478bd9Sstevel@tonic-gate  *	- process a message that was deferred because of lack of
2191*7c478bd9Sstevel@tonic-gate  *	  memory
2192*7c478bd9Sstevel@tonic-gate  *	- continue processing messages until the queue empties or we
2193*7c478bd9Sstevel@tonic-gate  *	  have to stop because of lack of memory
2194*7c478bd9Sstevel@tonic-gate  *	- during each of the above phase, if the queue is empty and
2195*7c478bd9Sstevel@tonic-gate  *	  there are no pending messages that were passed to the RPC
2196*7c478bd9Sstevel@tonic-gate  *	  layer, send upstream the pending disconnect/ordrel indication if
2197*7c478bd9Sstevel@tonic-gate  *	  there is one
2198*7c478bd9Sstevel@tonic-gate  *
2199*7c478bd9Sstevel@tonic-gate  * The read-side queue is also enabled by a bufcall callback if dupmsg
2200*7c478bd9Sstevel@tonic-gate  * fails in mir_rput.
2201*7c478bd9Sstevel@tonic-gate  */
2202*7c478bd9Sstevel@tonic-gate static void
2203*7c478bd9Sstevel@tonic-gate mir_rsrv(queue_t *q)
2204*7c478bd9Sstevel@tonic-gate {
2205*7c478bd9Sstevel@tonic-gate 	mir_t	*mir;
2206*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
2207*7c478bd9Sstevel@tonic-gate 	mblk_t	*cmp = NULL;
2208*7c478bd9Sstevel@tonic-gate 	boolean_t stop_timer = B_FALSE;
2209*7c478bd9Sstevel@tonic-gate 
2210*7c478bd9Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
2211*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 	mp = NULL;
2214*7c478bd9Sstevel@tonic-gate 	switch (mir->mir_type) {
2215*7c478bd9Sstevel@tonic-gate 	case RPC_SERVER:
2216*7c478bd9Sstevel@tonic-gate 		if (mir->mir_ref_cnt == 0)
2217*7c478bd9Sstevel@tonic-gate 			mir->mir_hold_inbound = 0;
2218*7c478bd9Sstevel@tonic-gate 		if (mir->mir_hold_inbound) {
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 			ASSERT(cmp == NULL);
2221*7c478bd9Sstevel@tonic-gate 			if (q->q_first == NULL) {
2222*7c478bd9Sstevel@tonic-gate 
2223*7c478bd9Sstevel@tonic-gate 				MIR_CLEAR_INRSRV(mir);
2224*7c478bd9Sstevel@tonic-gate 
2225*7c478bd9Sstevel@tonic-gate 				if (MIR_SVC_QUIESCED(mir)) {
2226*7c478bd9Sstevel@tonic-gate 					cmp = mir->mir_svc_pend_mp;
2227*7c478bd9Sstevel@tonic-gate 					mir->mir_svc_pend_mp = NULL;
2228*7c478bd9Sstevel@tonic-gate 				}
2229*7c478bd9Sstevel@tonic-gate 			}
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2232*7c478bd9Sstevel@tonic-gate 
2233*7c478bd9Sstevel@tonic-gate 			if (cmp != NULL) {
2234*7c478bd9Sstevel@tonic-gate 				RPCLOG(16, "mir_rsrv: line %d: sending a held "
2235*7c478bd9Sstevel@tonic-gate 				    "disconnect/ord rel indication upstream\n",
2236*7c478bd9Sstevel@tonic-gate 				    __LINE__);
2237*7c478bd9Sstevel@tonic-gate 				putnext(q, cmp);
2238*7c478bd9Sstevel@tonic-gate 			}
2239*7c478bd9Sstevel@tonic-gate 
2240*7c478bd9Sstevel@tonic-gate 			return;
2241*7c478bd9Sstevel@tonic-gate 		}
2242*7c478bd9Sstevel@tonic-gate 		while (mp = getq(q)) {
2243*7c478bd9Sstevel@tonic-gate 			if (mir->mir_krpc_cell) {
2244*7c478bd9Sstevel@tonic-gate 				/*
2245*7c478bd9Sstevel@tonic-gate 				 * If we were idle, turn off idle timer since
2246*7c478bd9Sstevel@tonic-gate 				 * we aren't idle any more.
2247*7c478bd9Sstevel@tonic-gate 				 */
2248*7c478bd9Sstevel@tonic-gate 				if (mir->mir_ref_cnt++ == 0)
2249*7c478bd9Sstevel@tonic-gate 					stop_timer = B_TRUE;
2250*7c478bd9Sstevel@tonic-gate 				if (mir_check_len(q,
2251*7c478bd9Sstevel@tonic-gate 					(int32_t)msgdsize(mp), mp))
2252*7c478bd9Sstevel@tonic-gate 						return;
2253*7c478bd9Sstevel@tonic-gate 				svc_queuereq(q, mp);
2254*7c478bd9Sstevel@tonic-gate 			} else {
2255*7c478bd9Sstevel@tonic-gate 				/*
2256*7c478bd9Sstevel@tonic-gate 				 * Count # of times this happens. Should be
2257*7c478bd9Sstevel@tonic-gate 				 * never, but experience shows otherwise.
2258*7c478bd9Sstevel@tonic-gate 				 */
2259*7c478bd9Sstevel@tonic-gate 				mir_krpc_cell_null++;
2260*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
2261*7c478bd9Sstevel@tonic-gate 			}
2262*7c478bd9Sstevel@tonic-gate 		}
2263*7c478bd9Sstevel@tonic-gate 		break;
2264*7c478bd9Sstevel@tonic-gate 	case RPC_CLIENT:
2265*7c478bd9Sstevel@tonic-gate 		break;
2266*7c478bd9Sstevel@tonic-gate 	default:
2267*7c478bd9Sstevel@tonic-gate 		RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type);
2268*7c478bd9Sstevel@tonic-gate 
2269*7c478bd9Sstevel@tonic-gate 		if (q->q_first == NULL)
2270*7c478bd9Sstevel@tonic-gate 			MIR_CLEAR_INRSRV(mir);
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 		return;
2275*7c478bd9Sstevel@tonic-gate 	}
2276*7c478bd9Sstevel@tonic-gate 
2277*7c478bd9Sstevel@tonic-gate 	/*
2278*7c478bd9Sstevel@tonic-gate 	 * The timer is stopped after all the messages are processed.
2279*7c478bd9Sstevel@tonic-gate 	 * The reason is that stopping the timer releases the mir_mutex
2280*7c478bd9Sstevel@tonic-gate 	 * lock temporarily.  This means that the request can be serviced
2281*7c478bd9Sstevel@tonic-gate 	 * while we are still processing the message queue.  This is not
2282*7c478bd9Sstevel@tonic-gate 	 * good.  So we stop the timer here instead.
2283*7c478bd9Sstevel@tonic-gate 	 */
2284*7c478bd9Sstevel@tonic-gate 	if (stop_timer)  {
2285*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref "
2286*7c478bd9Sstevel@tonic-gate 		    "cnt going to non zero\n", (void *)WR(q));
2287*7c478bd9Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
2288*7c478bd9Sstevel@tonic-gate 	}
2289*7c478bd9Sstevel@tonic-gate 
2290*7c478bd9Sstevel@tonic-gate 	if (q->q_first == NULL) {
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate 		MIR_CLEAR_INRSRV(mir);
2293*7c478bd9Sstevel@tonic-gate 
2294*7c478bd9Sstevel@tonic-gate 		ASSERT(cmp == NULL);
2295*7c478bd9Sstevel@tonic-gate 		if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) {
2296*7c478bd9Sstevel@tonic-gate 			cmp = mir->mir_svc_pend_mp;
2297*7c478bd9Sstevel@tonic-gate 			mir->mir_svc_pend_mp = NULL;
2298*7c478bd9Sstevel@tonic-gate 		}
2299*7c478bd9Sstevel@tonic-gate 
2300*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2301*7c478bd9Sstevel@tonic-gate 
2302*7c478bd9Sstevel@tonic-gate 		if (cmp != NULL) {
2303*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_rsrv: line %d: sending a held "
2304*7c478bd9Sstevel@tonic-gate 				"disconnect/ord rel indication upstream\n",
2305*7c478bd9Sstevel@tonic-gate 				__LINE__);
2306*7c478bd9Sstevel@tonic-gate 			putnext(q, cmp);
2307*7c478bd9Sstevel@tonic-gate 		}
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate 		return;
2310*7c478bd9Sstevel@tonic-gate 	}
2311*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
2312*7c478bd9Sstevel@tonic-gate }
2313*7c478bd9Sstevel@tonic-gate 
2314*7c478bd9Sstevel@tonic-gate static int mir_svc_policy_fails;
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate /*
2317*7c478bd9Sstevel@tonic-gate  * Called to send an event code to nfsd/lockd so that it initiates
2318*7c478bd9Sstevel@tonic-gate  * connection close.
2319*7c478bd9Sstevel@tonic-gate  */
2320*7c478bd9Sstevel@tonic-gate static int
2321*7c478bd9Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event)
2322*7c478bd9Sstevel@tonic-gate {
2323*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
2324*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2325*7c478bd9Sstevel@tonic-gate 	mir_t *mir = (mir_t *)q->q_ptr;
2326*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
2327*7c478bd9Sstevel@tonic-gate #endif
2328*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
2329*7c478bd9Sstevel@tonic-gate 
2330*7c478bd9Sstevel@tonic-gate 	/*
2331*7c478bd9Sstevel@tonic-gate 	 * Create an M_DATA message with the event code and pass it to the
2332*7c478bd9Sstevel@tonic-gate 	 * Stream head (nfsd or whoever created the stream will consume it).
2333*7c478bd9Sstevel@tonic-gate 	 */
2334*7c478bd9Sstevel@tonic-gate 	mp = allocb(sizeof (int), BPRI_HI);
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate 	if (!mp) {
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate 		mir_svc_policy_fails++;
2339*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_policy_notify: could not allocate event "
2340*7c478bd9Sstevel@tonic-gate 			"%d\n", event);
2341*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2342*7c478bd9Sstevel@tonic-gate 	}
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate 	U32_TO_BE32(event, mp->b_rptr);
2345*7c478bd9Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + sizeof (int);
2346*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
2347*7c478bd9Sstevel@tonic-gate 	return (0);
2348*7c478bd9Sstevel@tonic-gate }
2349*7c478bd9Sstevel@tonic-gate 
2350*7c478bd9Sstevel@tonic-gate /*
2351*7c478bd9Sstevel@tonic-gate  * Server side: start the close phase. We want to get this rpcmod slot in an
2352*7c478bd9Sstevel@tonic-gate  * idle state before mir_close() is called.
2353*7c478bd9Sstevel@tonic-gate  */
2354*7c478bd9Sstevel@tonic-gate static void
2355*7c478bd9Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir)
2356*7c478bd9Sstevel@tonic-gate {
2357*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
2358*7c478bd9Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
2359*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_SERVER);
2360*7c478bd9Sstevel@tonic-gate 
2361*7c478bd9Sstevel@tonic-gate 
2362*7c478bd9Sstevel@tonic-gate 	/*
2363*7c478bd9Sstevel@tonic-gate 	 * Do not accept any more messages.
2364*7c478bd9Sstevel@tonic-gate 	 */
2365*7c478bd9Sstevel@tonic-gate 	mir->mir_svc_no_more_msgs = 1;
2366*7c478bd9Sstevel@tonic-gate 
2367*7c478bd9Sstevel@tonic-gate 	/*
2368*7c478bd9Sstevel@tonic-gate 	 * Next two statements will make the read service procedure invoke
2369*7c478bd9Sstevel@tonic-gate 	 * svc_queuereq() on everything stuck in the streams read queue.
2370*7c478bd9Sstevel@tonic-gate 	 * It's not necessary because enabling the write queue will
2371*7c478bd9Sstevel@tonic-gate 	 * have the same effect, but why not speed the process along?
2372*7c478bd9Sstevel@tonic-gate 	 */
2373*7c478bd9Sstevel@tonic-gate 	mir->mir_hold_inbound = 0;
2374*7c478bd9Sstevel@tonic-gate 	qenable(RD(wq));
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	/*
2377*7c478bd9Sstevel@tonic-gate 	 * Meanwhile force the write service procedure to send the
2378*7c478bd9Sstevel@tonic-gate 	 * responses downstream, regardless of flow control.
2379*7c478bd9Sstevel@tonic-gate 	 */
2380*7c478bd9Sstevel@tonic-gate 	qenable(wq);
2381*7c478bd9Sstevel@tonic-gate }
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate /*
2384*7c478bd9Sstevel@tonic-gate  * This routine is called directly by KRPC after a request is completed,
2385*7c478bd9Sstevel@tonic-gate  * whether a reply was sent or the request was dropped.
2386*7c478bd9Sstevel@tonic-gate  */
2387*7c478bd9Sstevel@tonic-gate static void
2388*7c478bd9Sstevel@tonic-gate mir_svc_release(queue_t *wq, mblk_t *mp)
2389*7c478bd9Sstevel@tonic-gate {
2390*7c478bd9Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
2391*7c478bd9Sstevel@tonic-gate 	mblk_t	*cmp = NULL;
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
2394*7c478bd9Sstevel@tonic-gate 	if (mp)
2395*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2398*7c478bd9Sstevel@tonic-gate 	mir->mir_ref_cnt--;
2399*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_ref_cnt >= 0);
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	/*
2402*7c478bd9Sstevel@tonic-gate 	 * Start idle processing if this is the last reference.
2403*7c478bd9Sstevel@tonic-gate 	 */
2404*7c478bd9Sstevel@tonic-gate 	if (MIR_SVC_QUIESCED(mir)) {
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_release starting idle timer on 0x%p "
2407*7c478bd9Sstevel@tonic-gate 		    "because ref cnt is zero\n", (void *) wq);
2408*7c478bd9Sstevel@tonic-gate 
2409*7c478bd9Sstevel@tonic-gate 		cmp = mir->mir_svc_pend_mp;
2410*7c478bd9Sstevel@tonic-gate 		mir->mir_svc_pend_mp = NULL;
2411*7c478bd9Sstevel@tonic-gate 		mir_svc_idle_start(wq, mir);
2412*7c478bd9Sstevel@tonic-gate 	}
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
2415*7c478bd9Sstevel@tonic-gate 
2416*7c478bd9Sstevel@tonic-gate 	if (cmp) {
2417*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_svc_release: sending a held "
2418*7c478bd9Sstevel@tonic-gate 		    "disconnect/ord rel indication upstream on queue 0x%p\n",
2419*7c478bd9Sstevel@tonic-gate 		    (void *)RD(wq));
2420*7c478bd9Sstevel@tonic-gate 
2421*7c478bd9Sstevel@tonic-gate 		putnext(RD(wq), cmp);
2422*7c478bd9Sstevel@tonic-gate 	}
2423*7c478bd9Sstevel@tonic-gate }
2424*7c478bd9Sstevel@tonic-gate 
2425*7c478bd9Sstevel@tonic-gate /*
2426*7c478bd9Sstevel@tonic-gate  * This routine is called by server-side KRPC when it is ready to
2427*7c478bd9Sstevel@tonic-gate  * handle inbound messages on the stream.
2428*7c478bd9Sstevel@tonic-gate  */
2429*7c478bd9Sstevel@tonic-gate static void
2430*7c478bd9Sstevel@tonic-gate mir_svc_start(queue_t *wq)
2431*7c478bd9Sstevel@tonic-gate {
2432*7c478bd9Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
2433*7c478bd9Sstevel@tonic-gate 
2434*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2435*7c478bd9Sstevel@tonic-gate 	mir->mir_setup_complete = 1;
2436*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
2437*7c478bd9Sstevel@tonic-gate 	qenable(RD(wq));
2438*7c478bd9Sstevel@tonic-gate }
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate /*
2441*7c478bd9Sstevel@tonic-gate  * client side wrapper for stopping timer with normal idle timeout.
2442*7c478bd9Sstevel@tonic-gate  */
2443*7c478bd9Sstevel@tonic-gate static void
2444*7c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir)
2445*7c478bd9Sstevel@tonic-gate {
2446*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
2447*7c478bd9Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
2448*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_CLIENT);
2449*7c478bd9Sstevel@tonic-gate 
2450*7c478bd9Sstevel@tonic-gate 	mir_timer_stop(mir);
2451*7c478bd9Sstevel@tonic-gate }
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate /*
2454*7c478bd9Sstevel@tonic-gate  * client side wrapper for stopping timer with normal idle timeout.
2455*7c478bd9Sstevel@tonic-gate  */
2456*7c478bd9Sstevel@tonic-gate static void
2457*7c478bd9Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir)
2458*7c478bd9Sstevel@tonic-gate {
2459*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
2460*7c478bd9Sstevel@tonic-gate 	ASSERT((wq->q_flag & QREADR) == 0);
2461*7c478bd9Sstevel@tonic-gate 	ASSERT(mir->mir_type == RPC_CLIENT);
2462*7c478bd9Sstevel@tonic-gate 
2463*7c478bd9Sstevel@tonic-gate 	mir_timer_start(wq, mir, mir->mir_idle_timeout);
2464*7c478bd9Sstevel@tonic-gate }
2465*7c478bd9Sstevel@tonic-gate 
2466*7c478bd9Sstevel@tonic-gate /*
2467*7c478bd9Sstevel@tonic-gate  * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on
2468*7c478bd9Sstevel@tonic-gate  * end-points that aren't connected.
2469*7c478bd9Sstevel@tonic-gate  */
2470*7c478bd9Sstevel@tonic-gate static void
2471*7c478bd9Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq)
2472*7c478bd9Sstevel@tonic-gate {
2473*7c478bd9Sstevel@tonic-gate 	mir_t   *mir = (mir_t *)wq->q_ptr;
2474*7c478bd9Sstevel@tonic-gate 
2475*7c478bd9Sstevel@tonic-gate 	RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq);
2476*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
2477*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2478*7c478bd9Sstevel@tonic-gate 	mir_clnt_idle_stop(wq, mir);
2479*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
2480*7c478bd9Sstevel@tonic-gate }
2481*7c478bd9Sstevel@tonic-gate 
2482*7c478bd9Sstevel@tonic-gate /*
2483*7c478bd9Sstevel@tonic-gate  * Timer handler.  It handles idle timeout and memory shortage problem.
2484*7c478bd9Sstevel@tonic-gate  */
2485*7c478bd9Sstevel@tonic-gate static void
2486*7c478bd9Sstevel@tonic-gate mir_timer(void *arg)
2487*7c478bd9Sstevel@tonic-gate {
2488*7c478bd9Sstevel@tonic-gate 	queue_t *wq = (queue_t *)arg;
2489*7c478bd9Sstevel@tonic-gate 	mir_t *mir = (mir_t *)wq->q_ptr;
2490*7c478bd9Sstevel@tonic-gate 	boolean_t notify;
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2493*7c478bd9Sstevel@tonic-gate 
2494*7c478bd9Sstevel@tonic-gate 	/*
2495*7c478bd9Sstevel@tonic-gate 	 * mir_timer_call is set only when either mir_timer_[start|stop]
2496*7c478bd9Sstevel@tonic-gate 	 * is progressing.  And mir_timer() can only be run while they
2497*7c478bd9Sstevel@tonic-gate 	 * are progressing if the timer is being stopped.  So just
2498*7c478bd9Sstevel@tonic-gate 	 * return.
2499*7c478bd9Sstevel@tonic-gate 	 */
2500*7c478bd9Sstevel@tonic-gate 	if (mir->mir_timer_call) {
2501*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2502*7c478bd9Sstevel@tonic-gate 		return;
2503*7c478bd9Sstevel@tonic-gate 	}
2504*7c478bd9Sstevel@tonic-gate 	mir->mir_timer_id = 0;
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate 	switch (mir->mir_type) {
2507*7c478bd9Sstevel@tonic-gate 	case RPC_CLIENT:
2508*7c478bd9Sstevel@tonic-gate 
2509*7c478bd9Sstevel@tonic-gate 		/*
2510*7c478bd9Sstevel@tonic-gate 		 * For clients, the timer fires at clnt_idle_timeout
2511*7c478bd9Sstevel@tonic-gate 		 * intervals.  If the activity marker (mir_clntreq) is
2512*7c478bd9Sstevel@tonic-gate 		 * zero, then the stream has been idle since the last
2513*7c478bd9Sstevel@tonic-gate 		 * timer event and we notify KRPC.  If mir_clntreq is
2514*7c478bd9Sstevel@tonic-gate 		 * non-zero, then the stream is active and we just
2515*7c478bd9Sstevel@tonic-gate 		 * restart the timer for another interval.  mir_clntreq
2516*7c478bd9Sstevel@tonic-gate 		 * is set to 1 in mir_wput for every request passed
2517*7c478bd9Sstevel@tonic-gate 		 * downstream.
2518*7c478bd9Sstevel@tonic-gate 		 *
2519*7c478bd9Sstevel@tonic-gate 		 * If this was a memory shortage timer reset the idle
2520*7c478bd9Sstevel@tonic-gate 		 * timeout regardless; the mir_clntreq will not be a
2521*7c478bd9Sstevel@tonic-gate 		 * valid indicator.
2522*7c478bd9Sstevel@tonic-gate 		 *
2523*7c478bd9Sstevel@tonic-gate 		 * The timer is initially started in mir_wput during
2524*7c478bd9Sstevel@tonic-gate 		 * RPC_CLIENT ioctl processing.
2525*7c478bd9Sstevel@tonic-gate 		 *
2526*7c478bd9Sstevel@tonic-gate 		 * The timer interval can be changed for individual
2527*7c478bd9Sstevel@tonic-gate 		 * streams with the ND variable "mir_idle_timeout".
2528*7c478bd9Sstevel@tonic-gate 		 */
2529*7c478bd9Sstevel@tonic-gate 		if (mir->mir_clntreq > 0 && mir->mir_use_timestamp +
2530*7c478bd9Sstevel@tonic-gate 		    MSEC_TO_TICK(mir->mir_idle_timeout) - lbolt >= 0) {
2531*7c478bd9Sstevel@tonic-gate 			clock_t tout;
2532*7c478bd9Sstevel@tonic-gate 
2533*7c478bd9Sstevel@tonic-gate 			tout = mir->mir_idle_timeout -
2534*7c478bd9Sstevel@tonic-gate 				TICK_TO_MSEC(lbolt - mir->mir_use_timestamp);
2535*7c478bd9Sstevel@tonic-gate 			if (tout < 0)
2536*7c478bd9Sstevel@tonic-gate 				tout = 1000;
2537*7c478bd9Sstevel@tonic-gate #if 0
2538*7c478bd9Sstevel@tonic-gate printf("mir_timer[%d < %d + %d]: reset client timer to %d (ms)\n",
2539*7c478bd9Sstevel@tonic-gate TICK_TO_MSEC(lbolt), TICK_TO_MSEC(mir->mir_use_timestamp),
2540*7c478bd9Sstevel@tonic-gate mir->mir_idle_timeout, tout);
2541*7c478bd9Sstevel@tonic-gate #endif
2542*7c478bd9Sstevel@tonic-gate 			mir->mir_clntreq = 0;
2543*7c478bd9Sstevel@tonic-gate 			mir_timer_start(wq, mir, tout);
2544*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2545*7c478bd9Sstevel@tonic-gate 			return;
2546*7c478bd9Sstevel@tonic-gate 		}
2547*7c478bd9Sstevel@tonic-gate #if 0
2548*7c478bd9Sstevel@tonic-gate printf("mir_timer[%d]: doing client timeout\n", lbolt / hz);
2549*7c478bd9Sstevel@tonic-gate #endif
2550*7c478bd9Sstevel@tonic-gate 		/*
2551*7c478bd9Sstevel@tonic-gate 		 * We are disconnecting, but not necessarily
2552*7c478bd9Sstevel@tonic-gate 		 * closing. By not closing, we will fail to
2553*7c478bd9Sstevel@tonic-gate 		 * pick up a possibly changed global timeout value,
2554*7c478bd9Sstevel@tonic-gate 		 * unless we store it now.
2555*7c478bd9Sstevel@tonic-gate 		 */
2556*7c478bd9Sstevel@tonic-gate 		mir->mir_idle_timeout = clnt_idle_timeout;
2557*7c478bd9Sstevel@tonic-gate 		mir_clnt_idle_start(wq, mir);
2558*7c478bd9Sstevel@tonic-gate 
2559*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2560*7c478bd9Sstevel@tonic-gate 		/*
2561*7c478bd9Sstevel@tonic-gate 		 * We pass T_ORDREL_REQ as an integer value
2562*7c478bd9Sstevel@tonic-gate 		 * to KRPC as the indication that the stream
2563*7c478bd9Sstevel@tonic-gate 		 * is idle.  This is not a T_ORDREL_REQ message,
2564*7c478bd9Sstevel@tonic-gate 		 * it is just a convenient value since we call
2565*7c478bd9Sstevel@tonic-gate 		 * the same KRPC routine for T_ORDREL_INDs and
2566*7c478bd9Sstevel@tonic-gate 		 * T_DISCON_INDs.
2567*7c478bd9Sstevel@tonic-gate 		 */
2568*7c478bd9Sstevel@tonic-gate 		clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0);
2569*7c478bd9Sstevel@tonic-gate 		return;
2570*7c478bd9Sstevel@tonic-gate 
2571*7c478bd9Sstevel@tonic-gate 	case RPC_SERVER:
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 		/*
2574*7c478bd9Sstevel@tonic-gate 		 * For servers, the timer is only running when the stream
2575*7c478bd9Sstevel@tonic-gate 		 * is really idle or memory is short.  The timer is started
2576*7c478bd9Sstevel@tonic-gate 		 * by mir_wput when mir_type is set to RPC_SERVER and
2577*7c478bd9Sstevel@tonic-gate 		 * by mir_svc_idle_start whenever the stream goes idle
2578*7c478bd9Sstevel@tonic-gate 		 * (mir_ref_cnt == 0).  The timer is cancelled in
2579*7c478bd9Sstevel@tonic-gate 		 * mir_rput whenever a new inbound request is passed to KRPC
2580*7c478bd9Sstevel@tonic-gate 		 * and the stream was previously idle.
2581*7c478bd9Sstevel@tonic-gate 		 *
2582*7c478bd9Sstevel@tonic-gate 		 * The timer interval can be changed for individual
2583*7c478bd9Sstevel@tonic-gate 		 * streams with the ND variable "mir_idle_timeout".
2584*7c478bd9Sstevel@tonic-gate 		 *
2585*7c478bd9Sstevel@tonic-gate 		 * If the stream is not idle do nothing.
2586*7c478bd9Sstevel@tonic-gate 		 */
2587*7c478bd9Sstevel@tonic-gate 		if (!MIR_SVC_QUIESCED(mir)) {
2588*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2589*7c478bd9Sstevel@tonic-gate 			return;
2590*7c478bd9Sstevel@tonic-gate 		}
2591*7c478bd9Sstevel@tonic-gate 
2592*7c478bd9Sstevel@tonic-gate 		notify = !mir->mir_inrservice;
2593*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2594*7c478bd9Sstevel@tonic-gate 
2595*7c478bd9Sstevel@tonic-gate 		/*
2596*7c478bd9Sstevel@tonic-gate 		 * If there is no packet queued up in read queue, the stream
2597*7c478bd9Sstevel@tonic-gate 		 * is really idle so notify nfsd to close it.
2598*7c478bd9Sstevel@tonic-gate 		 */
2599*7c478bd9Sstevel@tonic-gate 		if (notify) {
2600*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_timer: telling stream head listener "
2601*7c478bd9Sstevel@tonic-gate 			    "to close stream (0x%p)\n", (void *) RD(wq));
2602*7c478bd9Sstevel@tonic-gate 			(void) mir_svc_policy_notify(RD(wq), 1);
2603*7c478bd9Sstevel@tonic-gate 		}
2604*7c478bd9Sstevel@tonic-gate 		return;
2605*7c478bd9Sstevel@tonic-gate 	default:
2606*7c478bd9Sstevel@tonic-gate 		RPCLOG(1, "mir_timer: unexpected mir_type %d\n",
2607*7c478bd9Sstevel@tonic-gate 			mir->mir_type);
2608*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2609*7c478bd9Sstevel@tonic-gate 		return;
2610*7c478bd9Sstevel@tonic-gate 	}
2611*7c478bd9Sstevel@tonic-gate }
2612*7c478bd9Sstevel@tonic-gate 
2613*7c478bd9Sstevel@tonic-gate /*
2614*7c478bd9Sstevel@tonic-gate  * Called by the RPC package to send either a call or a return, or a
2615*7c478bd9Sstevel@tonic-gate  * transport connection request.  Adds the record marking header.
2616*7c478bd9Sstevel@tonic-gate  */
2617*7c478bd9Sstevel@tonic-gate static void
2618*7c478bd9Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp)
2619*7c478bd9Sstevel@tonic-gate {
2620*7c478bd9Sstevel@tonic-gate 	uint_t	frag_header;
2621*7c478bd9Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
2622*7c478bd9Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate 	if (!mir) {
2625*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2626*7c478bd9Sstevel@tonic-gate 		return;
2627*7c478bd9Sstevel@tonic-gate 	}
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_DATA) {
2630*7c478bd9Sstevel@tonic-gate 		mir_wput_other(q, mp);
2631*7c478bd9Sstevel@tonic-gate 		return;
2632*7c478bd9Sstevel@tonic-gate 	}
2633*7c478bd9Sstevel@tonic-gate 
2634*7c478bd9Sstevel@tonic-gate 	if (mir->mir_ordrel_pending == 1) {
2635*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2636*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n",
2637*7c478bd9Sstevel@tonic-gate 			(void *)q);
2638*7c478bd9Sstevel@tonic-gate 		return;
2639*7c478bd9Sstevel@tonic-gate 	}
2640*7c478bd9Sstevel@tonic-gate 
2641*7c478bd9Sstevel@tonic-gate 	frag_header = (uint_t)DLEN(mp);
2642*7c478bd9Sstevel@tonic-gate 	frag_header |= MIR_LASTFRAG;
2643*7c478bd9Sstevel@tonic-gate 
2644*7c478bd9Sstevel@tonic-gate 	/* Stick in the 4 byte record marking header. */
2645*7c478bd9Sstevel@tonic-gate 	if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) ||
2646*7c478bd9Sstevel@tonic-gate 	    !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
2647*7c478bd9Sstevel@tonic-gate 		/*
2648*7c478bd9Sstevel@tonic-gate 		 * Since we know that M_DATA messages are created exclusively
2649*7c478bd9Sstevel@tonic-gate 		 * by KRPC, we expect that KRPC will leave room for our header
2650*7c478bd9Sstevel@tonic-gate 		 * and 4 byte align which is normal for XDR.
2651*7c478bd9Sstevel@tonic-gate 		 * If KRPC (or someone else) does not cooperate, then we
2652*7c478bd9Sstevel@tonic-gate 		 * just throw away the message.
2653*7c478bd9Sstevel@tonic-gate 		 */
2654*7c478bd9Sstevel@tonic-gate 		RPCLOG(1, "mir_wput: KRPC did not leave space for record "
2655*7c478bd9Sstevel@tonic-gate 		    "fragment header (%d bytes left)\n",
2656*7c478bd9Sstevel@tonic-gate 		    (int)(rptr - mp->b_datap->db_base));
2657*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2658*7c478bd9Sstevel@tonic-gate 		return;
2659*7c478bd9Sstevel@tonic-gate 	}
2660*7c478bd9Sstevel@tonic-gate 	rptr -= sizeof (uint32_t);
2661*7c478bd9Sstevel@tonic-gate 	*(uint32_t *)rptr = htonl(frag_header);
2662*7c478bd9Sstevel@tonic-gate 	mp->b_rptr = rptr;
2663*7c478bd9Sstevel@tonic-gate 
2664*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2665*7c478bd9Sstevel@tonic-gate 	if (mir->mir_type == RPC_CLIENT) {
2666*7c478bd9Sstevel@tonic-gate 		/*
2667*7c478bd9Sstevel@tonic-gate 		 * For the client, set mir_clntreq to indicate that the
2668*7c478bd9Sstevel@tonic-gate 		 * connection is active.
2669*7c478bd9Sstevel@tonic-gate 		 */
2670*7c478bd9Sstevel@tonic-gate 		mir->mir_clntreq = 1;
2671*7c478bd9Sstevel@tonic-gate 		mir->mir_use_timestamp = lbolt;
2672*7c478bd9Sstevel@tonic-gate 	}
2673*7c478bd9Sstevel@tonic-gate 
2674*7c478bd9Sstevel@tonic-gate 	/*
2675*7c478bd9Sstevel@tonic-gate 	 * If we haven't already queued some data and the downstream module
2676*7c478bd9Sstevel@tonic-gate 	 * can accept more data, send it on, otherwise we queue the message
2677*7c478bd9Sstevel@tonic-gate 	 * and take other actions depending on mir_type.
2678*7c478bd9Sstevel@tonic-gate 	 */
2679*7c478bd9Sstevel@tonic-gate 	if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) {
2680*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2681*7c478bd9Sstevel@tonic-gate 
2682*7c478bd9Sstevel@tonic-gate 		/*
2683*7c478bd9Sstevel@tonic-gate 		 * Now we pass the RPC message downstream.
2684*7c478bd9Sstevel@tonic-gate 		 */
2685*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
2686*7c478bd9Sstevel@tonic-gate 		return;
2687*7c478bd9Sstevel@tonic-gate 	}
2688*7c478bd9Sstevel@tonic-gate 
2689*7c478bd9Sstevel@tonic-gate 	switch (mir->mir_type) {
2690*7c478bd9Sstevel@tonic-gate 	case RPC_CLIENT:
2691*7c478bd9Sstevel@tonic-gate 		/*
2692*7c478bd9Sstevel@tonic-gate 		 * Check for a previous duplicate request on the
2693*7c478bd9Sstevel@tonic-gate 		 * queue.  If there is one, then we throw away
2694*7c478bd9Sstevel@tonic-gate 		 * the current message and let the previous one
2695*7c478bd9Sstevel@tonic-gate 		 * go through.  If we can't find a duplicate, then
2696*7c478bd9Sstevel@tonic-gate 		 * send this one.  This tap dance is an effort
2697*7c478bd9Sstevel@tonic-gate 		 * to reduce traffic and processing requirements
2698*7c478bd9Sstevel@tonic-gate 		 * under load conditions.
2699*7c478bd9Sstevel@tonic-gate 		 */
2700*7c478bd9Sstevel@tonic-gate 		if (mir_clnt_dup_request(q, mp)) {
2701*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2702*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2703*7c478bd9Sstevel@tonic-gate 			return;
2704*7c478bd9Sstevel@tonic-gate 		}
2705*7c478bd9Sstevel@tonic-gate 		break;
2706*7c478bd9Sstevel@tonic-gate 	case RPC_SERVER:
2707*7c478bd9Sstevel@tonic-gate 		/*
2708*7c478bd9Sstevel@tonic-gate 		 * Set mir_hold_inbound so that new inbound RPC
2709*7c478bd9Sstevel@tonic-gate 		 * messages will be held until the client catches
2710*7c478bd9Sstevel@tonic-gate 		 * up on the earlier replies.  This flag is cleared
2711*7c478bd9Sstevel@tonic-gate 		 * in mir_wsrv after flow control is relieved;
2712*7c478bd9Sstevel@tonic-gate 		 * the read-side queue is also enabled at that time.
2713*7c478bd9Sstevel@tonic-gate 		 */
2714*7c478bd9Sstevel@tonic-gate 		mir->mir_hold_inbound = 1;
2715*7c478bd9Sstevel@tonic-gate 		break;
2716*7c478bd9Sstevel@tonic-gate 	default:
2717*7c478bd9Sstevel@tonic-gate 		RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type);
2718*7c478bd9Sstevel@tonic-gate 		break;
2719*7c478bd9Sstevel@tonic-gate 	}
2720*7c478bd9Sstevel@tonic-gate 	mir->mir_inwservice = 1;
2721*7c478bd9Sstevel@tonic-gate 	(void) putq(q, mp);
2722*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
2723*7c478bd9Sstevel@tonic-gate }
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate static void
2726*7c478bd9Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp)
2727*7c478bd9Sstevel@tonic-gate {
2728*7c478bd9Sstevel@tonic-gate 	mir_t	*mir = (mir_t *)q->q_ptr;
2729*7c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp;
2730*7c478bd9Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
2731*7c478bd9Sstevel@tonic-gate 	bool_t	flush_in_svc = FALSE;
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
2734*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
2735*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
2736*7c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)rptr;
2737*7c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
2738*7c478bd9Sstevel@tonic-gate 		case RPC_CLIENT:
2739*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
2740*7c478bd9Sstevel@tonic-gate 			if (mir->mir_type != 0 &&
2741*7c478bd9Sstevel@tonic-gate 			    mir->mir_type != iocp->ioc_cmd) {
2742*7c478bd9Sstevel@tonic-gate ioc_eperm:
2743*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2744*7c478bd9Sstevel@tonic-gate 				iocp->ioc_error = EPERM;
2745*7c478bd9Sstevel@tonic-gate 				iocp->ioc_count = 0;
2746*7c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCACK;
2747*7c478bd9Sstevel@tonic-gate 				qreply(q, mp);
2748*7c478bd9Sstevel@tonic-gate 				return;
2749*7c478bd9Sstevel@tonic-gate 			}
2750*7c478bd9Sstevel@tonic-gate 
2751*7c478bd9Sstevel@tonic-gate 			mir->mir_type = iocp->ioc_cmd;
2752*7c478bd9Sstevel@tonic-gate 
2753*7c478bd9Sstevel@tonic-gate 			/*
2754*7c478bd9Sstevel@tonic-gate 			 * Clear mir_hold_inbound which was set to 1 by
2755*7c478bd9Sstevel@tonic-gate 			 * mir_open.  This flag is not used on client
2756*7c478bd9Sstevel@tonic-gate 			 * streams.
2757*7c478bd9Sstevel@tonic-gate 			 */
2758*7c478bd9Sstevel@tonic-gate 			mir->mir_hold_inbound = 0;
2759*7c478bd9Sstevel@tonic-gate 			mir->mir_max_msg_sizep = &clnt_max_msg_size;
2760*7c478bd9Sstevel@tonic-gate 
2761*7c478bd9Sstevel@tonic-gate 			/*
2762*7c478bd9Sstevel@tonic-gate 			 * Start the idle timer.  See mir_timer() for more
2763*7c478bd9Sstevel@tonic-gate 			 * information on how client timers work.
2764*7c478bd9Sstevel@tonic-gate 			 */
2765*7c478bd9Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
2766*7c478bd9Sstevel@tonic-gate 			mir_clnt_idle_start(q, mir);
2767*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2768*7c478bd9Sstevel@tonic-gate 
2769*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
2770*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);
2771*7c478bd9Sstevel@tonic-gate 			return;
2772*7c478bd9Sstevel@tonic-gate 		case RPC_SERVER:
2773*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
2774*7c478bd9Sstevel@tonic-gate 			if (mir->mir_type != 0 &&
2775*7c478bd9Sstevel@tonic-gate 			    mir->mir_type != iocp->ioc_cmd)
2776*7c478bd9Sstevel@tonic-gate 				goto ioc_eperm;
2777*7c478bd9Sstevel@tonic-gate 
2778*7c478bd9Sstevel@tonic-gate 			/*
2779*7c478bd9Sstevel@tonic-gate 			 * We don't clear mir_hold_inbound here because
2780*7c478bd9Sstevel@tonic-gate 			 * mir_hold_inbound is used in the flow control
2781*7c478bd9Sstevel@tonic-gate 			 * model. If we cleared it here, then we'd commit
2782*7c478bd9Sstevel@tonic-gate 			 * a small violation to the model where the transport
2783*7c478bd9Sstevel@tonic-gate 			 * might immediately block downstream flow.
2784*7c478bd9Sstevel@tonic-gate 			 */
2785*7c478bd9Sstevel@tonic-gate 
2786*7c478bd9Sstevel@tonic-gate 			mir->mir_type = iocp->ioc_cmd;
2787*7c478bd9Sstevel@tonic-gate 			mir->mir_max_msg_sizep = &svc_max_msg_size;
2788*7c478bd9Sstevel@tonic-gate 
2789*7c478bd9Sstevel@tonic-gate 			/*
2790*7c478bd9Sstevel@tonic-gate 			 * Start the idle timer.  See mir_timer() for more
2791*7c478bd9Sstevel@tonic-gate 			 * information on how server timers work.
2792*7c478bd9Sstevel@tonic-gate 			 *
2793*7c478bd9Sstevel@tonic-gate 			 * Note that it is important to start the idle timer
2794*7c478bd9Sstevel@tonic-gate 			 * here so that connections time out even if we
2795*7c478bd9Sstevel@tonic-gate 			 * never receive any data on them.
2796*7c478bd9Sstevel@tonic-gate 			 */
2797*7c478bd9Sstevel@tonic-gate 			mir->mir_idle_timeout = svc_idle_timeout;
2798*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other starting idle timer on 0x%p "
2799*7c478bd9Sstevel@tonic-gate 			    "because we got RPC_SERVER ioctl\n", (void *)q);
2800*7c478bd9Sstevel@tonic-gate 			mir_svc_idle_start(q, mir);
2801*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2802*7c478bd9Sstevel@tonic-gate 
2803*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
2804*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);
2805*7c478bd9Sstevel@tonic-gate 			return;
2806*7c478bd9Sstevel@tonic-gate 		default:
2807*7c478bd9Sstevel@tonic-gate 			break;
2808*7c478bd9Sstevel@tonic-gate 		}
2809*7c478bd9Sstevel@tonic-gate 		break;
2810*7c478bd9Sstevel@tonic-gate 
2811*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
2812*7c478bd9Sstevel@tonic-gate 		if (mir->mir_type == RPC_CLIENT) {
2813*7c478bd9Sstevel@tonic-gate 			/*
2814*7c478bd9Sstevel@tonic-gate 			 * We are likely being called from the context of a
2815*7c478bd9Sstevel@tonic-gate 			 * service procedure. So we need to enqueue. However
2816*7c478bd9Sstevel@tonic-gate 			 * enqueing may put our message behind data messages.
2817*7c478bd9Sstevel@tonic-gate 			 * So flush the data first.
2818*7c478bd9Sstevel@tonic-gate 			 */
2819*7c478bd9Sstevel@tonic-gate 			flush_in_svc = TRUE;
2820*7c478bd9Sstevel@tonic-gate 		}
2821*7c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) < sizeof (uint32_t) ||
2822*7c478bd9Sstevel@tonic-gate 				!IS_P2ALIGNED(rptr, sizeof (uint32_t)))
2823*7c478bd9Sstevel@tonic-gate 			break;
2824*7c478bd9Sstevel@tonic-gate 
2825*7c478bd9Sstevel@tonic-gate 		switch (((union T_primitives *)rptr)->type) {
2826*7c478bd9Sstevel@tonic-gate 		case T_DATA_REQ:
2827*7c478bd9Sstevel@tonic-gate 			/* Don't pass T_DATA_REQ messages downstream. */
2828*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2829*7c478bd9Sstevel@tonic-gate 			return;
2830*7c478bd9Sstevel@tonic-gate 		case T_ORDREL_REQ:
2831*7c478bd9Sstevel@tonic-gate 			RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n",
2832*7c478bd9Sstevel@tonic-gate 			    (void *)q);
2833*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
2834*7c478bd9Sstevel@tonic-gate 			if (mir->mir_type != RPC_SERVER) {
2835*7c478bd9Sstevel@tonic-gate 				/*
2836*7c478bd9Sstevel@tonic-gate 				 * We are likely being called from
2837*7c478bd9Sstevel@tonic-gate 				 * clnt_dispatch_notifyall(). Sending
2838*7c478bd9Sstevel@tonic-gate 				 * a T_ORDREL_REQ will result in
2839*7c478bd9Sstevel@tonic-gate 				 * a some kind of _IND message being sent,
2840*7c478bd9Sstevel@tonic-gate 				 * will be another call to
2841*7c478bd9Sstevel@tonic-gate 				 * clnt_dispatch_notifyall(). To keep the stack
2842*7c478bd9Sstevel@tonic-gate 				 * lean, queue this message.
2843*7c478bd9Sstevel@tonic-gate 				 */
2844*7c478bd9Sstevel@tonic-gate 				mir->mir_inwservice = 1;
2845*7c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
2846*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2847*7c478bd9Sstevel@tonic-gate 				return;
2848*7c478bd9Sstevel@tonic-gate 			}
2849*7c478bd9Sstevel@tonic-gate 
2850*7c478bd9Sstevel@tonic-gate 			/*
2851*7c478bd9Sstevel@tonic-gate 			 * Mark the structure such that we don't accept any
2852*7c478bd9Sstevel@tonic-gate 			 * more requests from client. We could defer this
2853*7c478bd9Sstevel@tonic-gate 			 * until we actually send the orderly release
2854*7c478bd9Sstevel@tonic-gate 			 * request downstream, but all that does is delay
2855*7c478bd9Sstevel@tonic-gate 			 * the closing of this stream.
2856*7c478bd9Sstevel@tonic-gate 			 */
2857*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ "
2858*7c478bd9Sstevel@tonic-gate 			    " so calling mir_svc_start_close\n", (void *)q);
2859*7c478bd9Sstevel@tonic-gate 
2860*7c478bd9Sstevel@tonic-gate 			mir_svc_start_close(q, mir);
2861*7c478bd9Sstevel@tonic-gate 
2862*7c478bd9Sstevel@tonic-gate 			/*
2863*7c478bd9Sstevel@tonic-gate 			 * If we have sent down a T_ORDREL_REQ, don't send
2864*7c478bd9Sstevel@tonic-gate 			 * any more.
2865*7c478bd9Sstevel@tonic-gate 			 */
2866*7c478bd9Sstevel@tonic-gate 			if (mir->mir_ordrel_pending) {
2867*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
2868*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2869*7c478bd9Sstevel@tonic-gate 				return;
2870*7c478bd9Sstevel@tonic-gate 			}
2871*7c478bd9Sstevel@tonic-gate 
2872*7c478bd9Sstevel@tonic-gate 			/*
2873*7c478bd9Sstevel@tonic-gate 			 * If the stream is not idle, then we hold the
2874*7c478bd9Sstevel@tonic-gate 			 * orderly release until it becomes idle.  This
2875*7c478bd9Sstevel@tonic-gate 			 * ensures that KRPC will be able to reply to
2876*7c478bd9Sstevel@tonic-gate 			 * all requests that we have passed to it.
2877*7c478bd9Sstevel@tonic-gate 			 *
2878*7c478bd9Sstevel@tonic-gate 			 * We also queue the request if there is data already
2879*7c478bd9Sstevel@tonic-gate 			 * queued, because we cannot allow the T_ORDREL_REQ
2880*7c478bd9Sstevel@tonic-gate 			 * to go before data. When we had a separate reply
2881*7c478bd9Sstevel@tonic-gate 			 * count, this was not a problem, because the
2882*7c478bd9Sstevel@tonic-gate 			 * reply count was reconciled when mir_wsrv()
2883*7c478bd9Sstevel@tonic-gate 			 * completed.
2884*7c478bd9Sstevel@tonic-gate 			 */
2885*7c478bd9Sstevel@tonic-gate 			if (!MIR_SVC_QUIESCED(mir) ||
2886*7c478bd9Sstevel@tonic-gate 			    mir->mir_inwservice == 1) {
2887*7c478bd9Sstevel@tonic-gate 				mir->mir_inwservice = 1;
2888*7c478bd9Sstevel@tonic-gate 				(void) putq(q, mp);
2889*7c478bd9Sstevel@tonic-gate 
2890*7c478bd9Sstevel@tonic-gate 				RPCLOG(16, "mir_wput_other: queuing "
2891*7c478bd9Sstevel@tonic-gate 				    "T_ORDREL_REQ on 0x%p\n", (void *)q);
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
2894*7c478bd9Sstevel@tonic-gate 				return;
2895*7c478bd9Sstevel@tonic-gate 			}
2896*7c478bd9Sstevel@tonic-gate 
2897*7c478bd9Sstevel@tonic-gate 			/*
2898*7c478bd9Sstevel@tonic-gate 			 * Mark the structure so that we know we sent
2899*7c478bd9Sstevel@tonic-gate 			 * an orderly release request, and reset the idle timer.
2900*7c478bd9Sstevel@tonic-gate 			 */
2901*7c478bd9Sstevel@tonic-gate 			mir->mir_ordrel_pending = 1;
2902*7c478bd9Sstevel@tonic-gate 
2903*7c478bd9Sstevel@tonic-gate 			RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start"
2904*7c478bd9Sstevel@tonic-gate 			    " on 0x%p because we got T_ORDREL_REQ\n",
2905*7c478bd9Sstevel@tonic-gate 			    (void *)q);
2906*7c478bd9Sstevel@tonic-gate 
2907*7c478bd9Sstevel@tonic-gate 			mir_svc_idle_start(q, mir);
2908*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2909*7c478bd9Sstevel@tonic-gate 
2910*7c478bd9Sstevel@tonic-gate 			/*
2911*7c478bd9Sstevel@tonic-gate 			 * When we break, we will putnext the T_ORDREL_REQ.
2912*7c478bd9Sstevel@tonic-gate 			 */
2913*7c478bd9Sstevel@tonic-gate 			break;
2914*7c478bd9Sstevel@tonic-gate 
2915*7c478bd9Sstevel@tonic-gate 		case T_CONN_REQ:
2916*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
2917*7c478bd9Sstevel@tonic-gate 			if (mir->mir_head_mp != NULL) {
2918*7c478bd9Sstevel@tonic-gate 				freemsg(mir->mir_head_mp);
2919*7c478bd9Sstevel@tonic-gate 				mir->mir_head_mp = NULL;
2920*7c478bd9Sstevel@tonic-gate 				mir->mir_tail_mp = NULL;
2921*7c478bd9Sstevel@tonic-gate 			}
2922*7c478bd9Sstevel@tonic-gate 			mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
2923*7c478bd9Sstevel@tonic-gate 			/*
2924*7c478bd9Sstevel@tonic-gate 			 * Restart timer in case mir_clnt_idle_do_stop() was
2925*7c478bd9Sstevel@tonic-gate 			 * called.
2926*7c478bd9Sstevel@tonic-gate 			 */
2927*7c478bd9Sstevel@tonic-gate 			mir->mir_idle_timeout = clnt_idle_timeout;
2928*7c478bd9Sstevel@tonic-gate 			mir_clnt_idle_stop(q, mir);
2929*7c478bd9Sstevel@tonic-gate 			mir_clnt_idle_start(q, mir);
2930*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2931*7c478bd9Sstevel@tonic-gate 			break;
2932*7c478bd9Sstevel@tonic-gate 
2933*7c478bd9Sstevel@tonic-gate 		default:
2934*7c478bd9Sstevel@tonic-gate 			/*
2935*7c478bd9Sstevel@tonic-gate 			 * T_DISCON_REQ is one of the interesting default
2936*7c478bd9Sstevel@tonic-gate 			 * cases here. Ideally, an M_FLUSH is done before
2937*7c478bd9Sstevel@tonic-gate 			 * T_DISCON_REQ is done. However, that is somewhat
2938*7c478bd9Sstevel@tonic-gate 			 * cumbersome for clnt_cots.c to do. So we queue
2939*7c478bd9Sstevel@tonic-gate 			 * T_DISCON_REQ, and let the service procedure
2940*7c478bd9Sstevel@tonic-gate 			 * flush all M_DATA.
2941*7c478bd9Sstevel@tonic-gate 			 */
2942*7c478bd9Sstevel@tonic-gate 			break;
2943*7c478bd9Sstevel@tonic-gate 		}
2944*7c478bd9Sstevel@tonic-gate 		/* fallthru */;
2945*7c478bd9Sstevel@tonic-gate 	default:
2946*7c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type >= QPCTL) {
2947*7c478bd9Sstevel@tonic-gate 			if (mp->b_datap->db_type == M_FLUSH) {
2948*7c478bd9Sstevel@tonic-gate 				if (mir->mir_type == RPC_CLIENT &&
2949*7c478bd9Sstevel@tonic-gate 				    *mp->b_rptr & FLUSHW) {
2950*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, "mir_wput_other: flushing "
2951*7c478bd9Sstevel@tonic-gate 					    "wq 0x%p\n", (void *)q);
2952*7c478bd9Sstevel@tonic-gate 					if (*mp->b_rptr & FLUSHBAND) {
2953*7c478bd9Sstevel@tonic-gate 						flushband(q, *(mp->b_rptr + 1),
2954*7c478bd9Sstevel@tonic-gate 							FLUSHDATA);
2955*7c478bd9Sstevel@tonic-gate 					} else {
2956*7c478bd9Sstevel@tonic-gate 						flushq(q, FLUSHDATA);
2957*7c478bd9Sstevel@tonic-gate 					}
2958*7c478bd9Sstevel@tonic-gate 				} else {
2959*7c478bd9Sstevel@tonic-gate 					RPCLOG(32, "mir_wput_other: ignoring "
2960*7c478bd9Sstevel@tonic-gate 					    "M_FLUSH on wq 0x%p\n", (void *)q);
2961*7c478bd9Sstevel@tonic-gate 				}
2962*7c478bd9Sstevel@tonic-gate 			}
2963*7c478bd9Sstevel@tonic-gate 			break;
2964*7c478bd9Sstevel@tonic-gate 		}
2965*7c478bd9Sstevel@tonic-gate 
2966*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
2967*7c478bd9Sstevel@tonic-gate 		if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) {
2968*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
2969*7c478bd9Sstevel@tonic-gate 			break;
2970*7c478bd9Sstevel@tonic-gate 		}
2971*7c478bd9Sstevel@tonic-gate 		mir->mir_inwservice = 1;
2972*7c478bd9Sstevel@tonic-gate 		mir->mir_inwflushdata = flush_in_svc;
2973*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
2974*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
2975*7c478bd9Sstevel@tonic-gate 		qenable(q);
2976*7c478bd9Sstevel@tonic-gate 
2977*7c478bd9Sstevel@tonic-gate 		return;
2978*7c478bd9Sstevel@tonic-gate 	}
2979*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
2980*7c478bd9Sstevel@tonic-gate }
2981*7c478bd9Sstevel@tonic-gate 
2982*7c478bd9Sstevel@tonic-gate static void
2983*7c478bd9Sstevel@tonic-gate mir_wsrv(queue_t *q)
2984*7c478bd9Sstevel@tonic-gate {
2985*7c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
2986*7c478bd9Sstevel@tonic-gate 	mir_t	*mir;
2987*7c478bd9Sstevel@tonic-gate 	bool_t flushdata;
2988*7c478bd9Sstevel@tonic-gate 
2989*7c478bd9Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
2990*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mir->mir_mutex);
2991*7c478bd9Sstevel@tonic-gate 
2992*7c478bd9Sstevel@tonic-gate 	flushdata = mir->mir_inwflushdata;
2993*7c478bd9Sstevel@tonic-gate 	mir->mir_inwflushdata = 0;
2994*7c478bd9Sstevel@tonic-gate 
2995*7c478bd9Sstevel@tonic-gate 	while (mp = getq(q)) {
2996*7c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type == M_DATA) {
2997*7c478bd9Sstevel@tonic-gate 			/*
2998*7c478bd9Sstevel@tonic-gate 			 * Do not send any more data if we have sent
2999*7c478bd9Sstevel@tonic-gate 			 * a T_ORDREL_REQ.
3000*7c478bd9Sstevel@tonic-gate 			 */
3001*7c478bd9Sstevel@tonic-gate 			if (flushdata || mir->mir_ordrel_pending == 1) {
3002*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
3003*7c478bd9Sstevel@tonic-gate 				continue;
3004*7c478bd9Sstevel@tonic-gate 			}
3005*7c478bd9Sstevel@tonic-gate 
3006*7c478bd9Sstevel@tonic-gate 			/*
3007*7c478bd9Sstevel@tonic-gate 			 * Make sure that the stream can really handle more
3008*7c478bd9Sstevel@tonic-gate 			 * data.
3009*7c478bd9Sstevel@tonic-gate 			 */
3010*7c478bd9Sstevel@tonic-gate 			if (!MIR_WCANPUTNEXT(mir, q)) {
3011*7c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
3012*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mir->mir_mutex);
3013*7c478bd9Sstevel@tonic-gate 				return;
3014*7c478bd9Sstevel@tonic-gate 			}
3015*7c478bd9Sstevel@tonic-gate 
3016*7c478bd9Sstevel@tonic-gate 			/*
3017*7c478bd9Sstevel@tonic-gate 			 * Now we pass the RPC message downstream.
3018*7c478bd9Sstevel@tonic-gate 			 */
3019*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
3020*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
3021*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
3022*7c478bd9Sstevel@tonic-gate 			continue;
3023*7c478bd9Sstevel@tonic-gate 		}
3024*7c478bd9Sstevel@tonic-gate 
3025*7c478bd9Sstevel@tonic-gate 		/*
3026*7c478bd9Sstevel@tonic-gate 		 * This is not an RPC message, pass it downstream
3027*7c478bd9Sstevel@tonic-gate 		 * (ignoring flow control) if the server side is not sending a
3028*7c478bd9Sstevel@tonic-gate 		 * T_ORDREL_REQ downstream.
3029*7c478bd9Sstevel@tonic-gate 		 */
3030*7c478bd9Sstevel@tonic-gate 		if (mir->mir_type != RPC_SERVER ||
3031*7c478bd9Sstevel@tonic-gate 			    ((union T_primitives *)mp->b_rptr)->type !=
3032*7c478bd9Sstevel@tonic-gate 			    T_ORDREL_REQ) {
3033*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mir->mir_mutex);
3034*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
3035*7c478bd9Sstevel@tonic-gate 			mutex_enter(&mir->mir_mutex);
3036*7c478bd9Sstevel@tonic-gate 			continue;
3037*7c478bd9Sstevel@tonic-gate 		}
3038*7c478bd9Sstevel@tonic-gate 
3039*7c478bd9Sstevel@tonic-gate 		if (mir->mir_ordrel_pending == 1) {
3040*7c478bd9Sstevel@tonic-gate 			/*
3041*7c478bd9Sstevel@tonic-gate 			 * Don't send two T_ORDRELs
3042*7c478bd9Sstevel@tonic-gate 			 */
3043*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
3044*7c478bd9Sstevel@tonic-gate 			continue;
3045*7c478bd9Sstevel@tonic-gate 		}
3046*7c478bd9Sstevel@tonic-gate 
3047*7c478bd9Sstevel@tonic-gate 		/*
3048*7c478bd9Sstevel@tonic-gate 		 * Mark the structure so that we know we sent an orderly
3049*7c478bd9Sstevel@tonic-gate 		 * release request.  We will check to see slot is idle at the
3050*7c478bd9Sstevel@tonic-gate 		 * end of this routine, and if so, reset the idle timer to
3051*7c478bd9Sstevel@tonic-gate 		 * handle orderly release timeouts.
3052*7c478bd9Sstevel@tonic-gate 		 */
3053*7c478bd9Sstevel@tonic-gate 		mir->mir_ordrel_pending = 1;
3054*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n",
3055*7c478bd9Sstevel@tonic-gate 								(void *)q);
3056*7c478bd9Sstevel@tonic-gate 		/*
3057*7c478bd9Sstevel@tonic-gate 		 * Send the orderly release downstream. If there are other
3058*7c478bd9Sstevel@tonic-gate 		 * pending replies we won't be able to send them.  However,
3059*7c478bd9Sstevel@tonic-gate 		 * the only reason we should send the orderly release is if
3060*7c478bd9Sstevel@tonic-gate 		 * we were idle, or if an unusual event occurred.
3061*7c478bd9Sstevel@tonic-gate 		 */
3062*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
3063*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
3064*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mir->mir_mutex);
3065*7c478bd9Sstevel@tonic-gate 	}
3066*7c478bd9Sstevel@tonic-gate 
3067*7c478bd9Sstevel@tonic-gate 	if (q->q_first == NULL)
3068*7c478bd9Sstevel@tonic-gate 		/*
3069*7c478bd9Sstevel@tonic-gate 		 * If we call mir_svc_idle_start() below, then
3070*7c478bd9Sstevel@tonic-gate 		 * clearing mir_inwservice here will also result in
3071*7c478bd9Sstevel@tonic-gate 		 * any thread waiting in mir_close() to be signaled.
3072*7c478bd9Sstevel@tonic-gate 		 */
3073*7c478bd9Sstevel@tonic-gate 		mir->mir_inwservice = 0;
3074*7c478bd9Sstevel@tonic-gate 
3075*7c478bd9Sstevel@tonic-gate 	if (mir->mir_type != RPC_SERVER) {
3076*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
3077*7c478bd9Sstevel@tonic-gate 		return;
3078*7c478bd9Sstevel@tonic-gate 	}
3079*7c478bd9Sstevel@tonic-gate 
3080*7c478bd9Sstevel@tonic-gate 	/*
3081*7c478bd9Sstevel@tonic-gate 	 * If idle we call mir_svc_idle_start to start the timer (or wakeup
3082*7c478bd9Sstevel@tonic-gate 	 * a close). Also make sure not to start the idle timer on the
3083*7c478bd9Sstevel@tonic-gate 	 * listener stream. This can cause nfsd to send an orderly release
3084*7c478bd9Sstevel@tonic-gate 	 * command on the listener stream.
3085*7c478bd9Sstevel@tonic-gate 	 */
3086*7c478bd9Sstevel@tonic-gate 	if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) {
3087*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p "
3088*7c478bd9Sstevel@tonic-gate 		    "because mir slot is idle\n", (void *)q);
3089*7c478bd9Sstevel@tonic-gate 		mir_svc_idle_start(q, mir);
3090*7c478bd9Sstevel@tonic-gate 	}
3091*7c478bd9Sstevel@tonic-gate 
3092*7c478bd9Sstevel@tonic-gate 	/*
3093*7c478bd9Sstevel@tonic-gate 	 * If outbound flow control has been relieved, then allow new
3094*7c478bd9Sstevel@tonic-gate 	 * inbound requests to be processed.
3095*7c478bd9Sstevel@tonic-gate 	 */
3096*7c478bd9Sstevel@tonic-gate 	if (mir->mir_hold_inbound) {
3097*7c478bd9Sstevel@tonic-gate 		mir->mir_hold_inbound = 0;
3098*7c478bd9Sstevel@tonic-gate 		qenable(RD(q));
3099*7c478bd9Sstevel@tonic-gate 	}
3100*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mir->mir_mutex);
3101*7c478bd9Sstevel@tonic-gate }
3102*7c478bd9Sstevel@tonic-gate 
3103*7c478bd9Sstevel@tonic-gate static void
3104*7c478bd9Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir)
3105*7c478bd9Sstevel@tonic-gate {
3106*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mir->mir_mutex));
3107*7c478bd9Sstevel@tonic-gate 
3108*7c478bd9Sstevel@tonic-gate 	switch (mir->mir_type) {
3109*7c478bd9Sstevel@tonic-gate 	case RPC_CLIENT:
3110*7c478bd9Sstevel@tonic-gate 		/*
3111*7c478bd9Sstevel@tonic-gate 		 * We are disconnecting, but not necessarily
3112*7c478bd9Sstevel@tonic-gate 		 * closing. By not closing, we will fail to
3113*7c478bd9Sstevel@tonic-gate 		 * pick up a possibly changed global timeout value,
3114*7c478bd9Sstevel@tonic-gate 		 * unless we store it now.
3115*7c478bd9Sstevel@tonic-gate 		 */
3116*7c478bd9Sstevel@tonic-gate 		mir->mir_idle_timeout = clnt_idle_timeout;
3117*7c478bd9Sstevel@tonic-gate 		mir_clnt_idle_start(WR(q), mir);
3118*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
3119*7c478bd9Sstevel@tonic-gate 
3120*7c478bd9Sstevel@tonic-gate 		/*
3121*7c478bd9Sstevel@tonic-gate 		 * T_DISCON_REQ is passed to KRPC as an integer value
3122*7c478bd9Sstevel@tonic-gate 		 * (this is not a TPI message).  It is used as a
3123*7c478bd9Sstevel@tonic-gate 		 * convenient value to indicate a sanity check
3124*7c478bd9Sstevel@tonic-gate 		 * failure -- the same KRPC routine is also called
3125*7c478bd9Sstevel@tonic-gate 		 * for T_DISCON_INDs and T_ORDREL_INDs.
3126*7c478bd9Sstevel@tonic-gate 		 */
3127*7c478bd9Sstevel@tonic-gate 		clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0);
3128*7c478bd9Sstevel@tonic-gate 		break;
3129*7c478bd9Sstevel@tonic-gate 
3130*7c478bd9Sstevel@tonic-gate 	case RPC_SERVER:
3131*7c478bd9Sstevel@tonic-gate 		mir->mir_svc_no_more_msgs = 1;
3132*7c478bd9Sstevel@tonic-gate 		mir_svc_idle_stop(WR(q), mir);
3133*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
3134*7c478bd9Sstevel@tonic-gate 		RPCLOG(16, "mir_disconnect: telling "
3135*7c478bd9Sstevel@tonic-gate 			"stream head listener to disconnect stream "
3136*7c478bd9Sstevel@tonic-gate 			"(0x%p)\n", (void *) q);
3137*7c478bd9Sstevel@tonic-gate 		(void) mir_svc_policy_notify(q, 2);
3138*7c478bd9Sstevel@tonic-gate 		break;
3139*7c478bd9Sstevel@tonic-gate 
3140*7c478bd9Sstevel@tonic-gate 	default:
3141*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mir->mir_mutex);
3142*7c478bd9Sstevel@tonic-gate 		break;
3143*7c478bd9Sstevel@tonic-gate 	}
3144*7c478bd9Sstevel@tonic-gate }
3145*7c478bd9Sstevel@tonic-gate 
3146*7c478bd9Sstevel@tonic-gate /*
3147*7c478bd9Sstevel@tonic-gate  * do a sanity check on the length of the fragment.
3148*7c478bd9Sstevel@tonic-gate  * returns 1 if bad else 0.
3149*7c478bd9Sstevel@tonic-gate  */
3150*7c478bd9Sstevel@tonic-gate static int
3151*7c478bd9Sstevel@tonic-gate mir_check_len(queue_t *q, int32_t frag_len,
3152*7c478bd9Sstevel@tonic-gate     mblk_t *head_mp)
3153*7c478bd9Sstevel@tonic-gate {
3154*7c478bd9Sstevel@tonic-gate 	mir_t   *mir;
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 	mir = (mir_t *)q->q_ptr;
3157*7c478bd9Sstevel@tonic-gate 
3158*7c478bd9Sstevel@tonic-gate 	/*
3159*7c478bd9Sstevel@tonic-gate 	 * Do a sanity check on the message length.  If this message is
3160*7c478bd9Sstevel@tonic-gate 	 * getting excessively large, shut down the connection.
3161*7c478bd9Sstevel@tonic-gate 	 */
3162*7c478bd9Sstevel@tonic-gate 
3163*7c478bd9Sstevel@tonic-gate 	if ((frag_len <= 0) || (mir->mir_max_msg_sizep == NULL) ||
3164*7c478bd9Sstevel@tonic-gate 		(frag_len <= *mir->mir_max_msg_sizep)) {
3165*7c478bd9Sstevel@tonic-gate 		return (0);
3166*7c478bd9Sstevel@tonic-gate 	}
3167*7c478bd9Sstevel@tonic-gate 
3168*7c478bd9Sstevel@tonic-gate 	freemsg(head_mp);
3169*7c478bd9Sstevel@tonic-gate 	mir->mir_head_mp = (mblk_t *)0;
3170*7c478bd9Sstevel@tonic-gate 	mir->mir_frag_len = -(int)sizeof (uint32_t);
3171*7c478bd9Sstevel@tonic-gate 	if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) {
3172*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
3173*7c478bd9Sstevel@tonic-gate 		"KRPC: record fragment from %s of size(%d) exceeds "
3174*7c478bd9Sstevel@tonic-gate 		"maximum (%u). Disconnecting",
3175*7c478bd9Sstevel@tonic-gate 		(mir->mir_type == RPC_CLIENT) ? "server" :
3176*7c478bd9Sstevel@tonic-gate 		(mir->mir_type == RPC_SERVER) ? "client" :
3177*7c478bd9Sstevel@tonic-gate 		"test tool",
3178*7c478bd9Sstevel@tonic-gate 		frag_len, *mir->mir_max_msg_sizep);
3179*7c478bd9Sstevel@tonic-gate 	}
3180*7c478bd9Sstevel@tonic-gate 
3181*7c478bd9Sstevel@tonic-gate 	mir_disconnect(q, mir);
3182*7c478bd9Sstevel@tonic-gate 	return (1);
3183*7c478bd9Sstevel@tonic-gate }
3184