xref: /illumos-gate/usr/src/uts/common/io/bufmod.c (revision 57198255)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25eb00302cSRyan Zezeski  * Copyright 2018 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * STREAMS Buffering module
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * This streams module collects incoming messages from modules below
327c478bd9Sstevel@tonic-gate  * it on the stream and buffers them up into a smaller number of
337c478bd9Sstevel@tonic-gate  * aggregated messages.  Its main purpose is to reduce overhead by
347c478bd9Sstevel@tonic-gate  * cutting down on the number of read (or getmsg) calls its client
357c478bd9Sstevel@tonic-gate  * user process makes.
367c478bd9Sstevel@tonic-gate  *  - only M_DATA is buffered.
377c478bd9Sstevel@tonic-gate  *  - multithreading assumes configured as D_MTQPAIR
387c478bd9Sstevel@tonic-gate  *  - packets are lost only if flag SB_NO_HEADER is clear and buffer
397c478bd9Sstevel@tonic-gate  *    allocation fails.
407c478bd9Sstevel@tonic-gate  *  - in order message transmission. This is enforced for messages other
417c478bd9Sstevel@tonic-gate  *    than high priority messages.
427c478bd9Sstevel@tonic-gate  *  - zero length messages on the read side are not passed up the
437c478bd9Sstevel@tonic-gate  *    stream but used internally for synchronization.
447c478bd9Sstevel@tonic-gate  * FLAGS:
457c478bd9Sstevel@tonic-gate  * - SB_NO_PROTO_CVT - no conversion of M_PROTO messages to M_DATA.
467c478bd9Sstevel@tonic-gate  *   (conversion is the default for backwards compatibility
477c478bd9Sstevel@tonic-gate  *    hence the negative logic).
487c478bd9Sstevel@tonic-gate  * - SB_NO_HEADER - no headers in buffered data.
497c478bd9Sstevel@tonic-gate  *   (adding headers is the default for backwards compatibility
507c478bd9Sstevel@tonic-gate  *    hence the negative logic).
517c478bd9Sstevel@tonic-gate  * - SB_DEFER_CHUNK - provides improved response time in question-answer
527c478bd9Sstevel@tonic-gate  *   applications. Buffering is not enabled until the second message
537c478bd9Sstevel@tonic-gate  *   is received on the read side within the sb_ticks interval.
547c478bd9Sstevel@tonic-gate  *   This option will often be used in combination with flag SB_SEND_ON_WRITE.
557c478bd9Sstevel@tonic-gate  * - SB_SEND_ON_WRITE - a write message results in any pending buffered read
567c478bd9Sstevel@tonic-gate  *   data being immediately sent upstream.
577c478bd9Sstevel@tonic-gate  * - SB_NO_DROPS - bufmod behaves transparently in flow control and propagates
587c478bd9Sstevel@tonic-gate  *   the blocked flow condition downstream. If this flag is clear (default)
597c478bd9Sstevel@tonic-gate  *   messages will be dropped if the upstream flow is blocked.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #include	<sys/types.h>
647c478bd9Sstevel@tonic-gate #include	<sys/errno.h>
657c478bd9Sstevel@tonic-gate #include	<sys/debug.h>
667c478bd9Sstevel@tonic-gate #include	<sys/stropts.h>
677c478bd9Sstevel@tonic-gate #include	<sys/time.h>
687c478bd9Sstevel@tonic-gate #include	<sys/stream.h>
697c478bd9Sstevel@tonic-gate #include	<sys/conf.h>
707c478bd9Sstevel@tonic-gate #include	<sys/ddi.h>
717c478bd9Sstevel@tonic-gate #include	<sys/sunddi.h>
727c478bd9Sstevel@tonic-gate #include	<sys/kmem.h>
737c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
747c478bd9Sstevel@tonic-gate #include	<sys/bufmod.h>
757c478bd9Sstevel@tonic-gate #include	<sys/modctl.h>
767c478bd9Sstevel@tonic-gate #include	<sys/isa_defs.h>
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Per-Stream state information.
807c478bd9Sstevel@tonic-gate  *
817c478bd9Sstevel@tonic-gate  * If sb_ticks is negative, we don't deliver chunks until they're
827c478bd9Sstevel@tonic-gate  * full.  If it's zero, we deliver every packet as it arrives.  (In
837c478bd9Sstevel@tonic-gate  * this case we force sb_chunk to zero, to make the implementation
847c478bd9Sstevel@tonic-gate  * easier.)  Otherwise, sb_ticks gives the number of ticks in a
857c478bd9Sstevel@tonic-gate  * buffering interval. The interval begins when the a read side data
867c478bd9Sstevel@tonic-gate  * message is received and a timeout is not active. If sb_snap is
877c478bd9Sstevel@tonic-gate  * zero, no truncation of the msg is done.
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate struct sb {
907c478bd9Sstevel@tonic-gate 	queue_t	*sb_rq;		/* our rq */
917c478bd9Sstevel@tonic-gate 	mblk_t	*sb_mp;		/* partial chunk */
927c478bd9Sstevel@tonic-gate 	mblk_t  *sb_head;	/* pre-allocated space for the next header */
937c478bd9Sstevel@tonic-gate 	mblk_t	*sb_tail;	/* first mblk of last message appended */
947c478bd9Sstevel@tonic-gate 	uint_t	sb_mlen;	/* sb_mp length */
957c478bd9Sstevel@tonic-gate 	uint_t	sb_mcount;	/* input msg count in sb_mp */
967c478bd9Sstevel@tonic-gate 	uint_t	sb_chunk;	/* max chunk size */
977c478bd9Sstevel@tonic-gate 	clock_t	sb_ticks;	/* timeout interval */
987c478bd9Sstevel@tonic-gate 	timeout_id_t sb_timeoutid; /* qtimeout() id */
997c478bd9Sstevel@tonic-gate 	uint_t	sb_drops;	/* cumulative # discarded msgs */
1007c478bd9Sstevel@tonic-gate 	uint_t	sb_snap;	/* snapshot length */
1017c478bd9Sstevel@tonic-gate 	uint_t	sb_flags;	/* flags field */
1027c478bd9Sstevel@tonic-gate 	uint_t	sb_state;	/* state variable */
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Function prototypes.
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static	int	sbopen(queue_t *, dev_t *, int, int, cred_t *);
1097c478bd9Sstevel@tonic-gate static	int	sbclose(queue_t *, int, cred_t *);
110*57198255SToomas Soome static	int	sbwput(queue_t *, mblk_t *);
111*57198255SToomas Soome static	int	sbrput(queue_t *, mblk_t *);
112*57198255SToomas Soome static	int	sbrsrv(queue_t *);
1137c478bd9Sstevel@tonic-gate static	void	sbioctl(queue_t *, mblk_t *);
1147c478bd9Sstevel@tonic-gate static	void	sbaddmsg(queue_t *, mblk_t *);
1157c478bd9Sstevel@tonic-gate static	void	sbtick(void *);
1167c478bd9Sstevel@tonic-gate static	void	sbclosechunk(struct sb *);
1177c478bd9Sstevel@tonic-gate static	void	sbsendit(queue_t *, mblk_t *);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static struct module_info	sb_minfo = {
1207c478bd9Sstevel@tonic-gate 	21,		/* mi_idnum */
1217c478bd9Sstevel@tonic-gate 	"bufmod",	/* mi_idname */
1227c478bd9Sstevel@tonic-gate 	0,		/* mi_minpsz */
1237c478bd9Sstevel@tonic-gate 	INFPSZ,		/* mi_maxpsz */
1247c478bd9Sstevel@tonic-gate 	1,		/* mi_hiwat */
1257c478bd9Sstevel@tonic-gate 	0		/* mi_lowat */
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static struct qinit	sb_rinit = {
129*57198255SToomas Soome 	sbrput,			/* qi_putp */
130*57198255SToomas Soome 	sbrsrv,			/* qi_srvp */
1317c478bd9Sstevel@tonic-gate 	sbopen,			/* qi_qopen */
1327c478bd9Sstevel@tonic-gate 	sbclose,		/* qi_qclose */
1337c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1347c478bd9Sstevel@tonic-gate 	&sb_minfo,		/* qi_minfo */
1357c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1367c478bd9Sstevel@tonic-gate };
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static struct qinit	sb_winit = {
139*57198255SToomas Soome 	sbwput,			/* qi_putp */
1407c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
1417c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
1427c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
1437c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1447c478bd9Sstevel@tonic-gate 	&sb_minfo,		/* qi_minfo */
1457c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1467c478bd9Sstevel@tonic-gate };
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static struct streamtab	sb_info = {
1497c478bd9Sstevel@tonic-gate 	&sb_rinit,	/* st_rdinit */
1507c478bd9Sstevel@tonic-gate 	&sb_winit,	/* st_wrinit */
1517c478bd9Sstevel@tonic-gate 	NULL,		/* st_muxrinit */
1527c478bd9Sstevel@tonic-gate 	NULL		/* st_muxwinit */
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
1617c478bd9Sstevel@tonic-gate 	"bufmod",
1627c478bd9Sstevel@tonic-gate 	&sb_info,
1637c478bd9Sstevel@tonic-gate 	D_MTQPAIR | D_MP
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
1717c478bd9Sstevel@tonic-gate 	&mod_strmodops, "streams buffer mod", &fsw
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1757c478bd9Sstevel@tonic-gate 	MODREV_1, &modlstrmod, NULL
1767c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate int
_init(void)1807c478bd9Sstevel@tonic-gate _init(void)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate int
_fini(void)1867c478bd9Sstevel@tonic-gate _fini(void)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1927c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /* ARGSUSED */
1997c478bd9Sstevel@tonic-gate static int
sbopen(queue_t * rq,dev_t * dev,int oflag,int sflag,cred_t * crp)2007c478bd9Sstevel@tonic-gate sbopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	struct sb	*sbp;
2037c478bd9Sstevel@tonic-gate 	ASSERT(rq);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (sflag != MODOPEN)
2067c478bd9Sstevel@tonic-gate 		return (EINVAL);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (rq->q_ptr)
2097c478bd9Sstevel@tonic-gate 		return (0);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/*
2127c478bd9Sstevel@tonic-gate 	 * Allocate and initialize per-Stream structure.
2137c478bd9Sstevel@tonic-gate 	 */
2147c478bd9Sstevel@tonic-gate 	sbp = kmem_alloc(sizeof (struct sb), KM_SLEEP);
2157c478bd9Sstevel@tonic-gate 	sbp->sb_rq = rq;
2167c478bd9Sstevel@tonic-gate 	sbp->sb_ticks = -1;
2177c478bd9Sstevel@tonic-gate 	sbp->sb_chunk = SB_DFLT_CHUNK;
2187c478bd9Sstevel@tonic-gate 	sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
2197c478bd9Sstevel@tonic-gate 	sbp->sb_mlen = 0;
2207c478bd9Sstevel@tonic-gate 	sbp->sb_mcount = 0;
2217c478bd9Sstevel@tonic-gate 	sbp->sb_timeoutid = 0;
2227c478bd9Sstevel@tonic-gate 	sbp->sb_drops = 0;
2237c478bd9Sstevel@tonic-gate 	sbp->sb_snap = 0;
2247c478bd9Sstevel@tonic-gate 	sbp->sb_flags = 0;
2257c478bd9Sstevel@tonic-gate 	sbp->sb_state = 0;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	rq->q_ptr = WR(rq)->q_ptr = sbp;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	qprocson(rq);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (0);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
2367c478bd9Sstevel@tonic-gate static int
sbclose(queue_t * rq,int flag,cred_t * credp)2377c478bd9Sstevel@tonic-gate sbclose(queue_t *rq, int flag, cred_t *credp)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	struct	sb	*sbp = (struct sb *)rq->q_ptr;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	qprocsoff(rq);
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * Cancel an outstanding timeout
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (sbp->sb_timeoutid != 0) {
2487c478bd9Sstevel@tonic-gate 		(void) quntimeout(rq, sbp->sb_timeoutid);
2497c478bd9Sstevel@tonic-gate 		sbp->sb_timeoutid = 0;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	/*
2527c478bd9Sstevel@tonic-gate 	 * Free the current chunk.
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if (sbp->sb_mp) {
2557c478bd9Sstevel@tonic-gate 		freemsg(sbp->sb_mp);
2567c478bd9Sstevel@tonic-gate 		sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
2577c478bd9Sstevel@tonic-gate 		sbp->sb_mlen = 0;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * Free the per-Stream structure.
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)sbp, sizeof (struct sb));
2647c478bd9Sstevel@tonic-gate 	rq->q_ptr = WR(rq)->q_ptr = NULL;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	return (0);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate  * the correction factor is introduced to compensate for
2717c478bd9Sstevel@tonic-gate  * whatever assumptions the modules below have made about
2727c478bd9Sstevel@tonic-gate  * how much traffic is flowing through the stream and the fact
2737c478bd9Sstevel@tonic-gate  * that bufmod may be snipping messages with the sb_snap length.
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate #define	SNIT_HIWAT(msgsize, fudge)	((4 * msgsize * fudge) + 512)
2767c478bd9Sstevel@tonic-gate #define	SNIT_LOWAT(msgsize, fudge)	((2 * msgsize * fudge) + 256)
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate static void
sbioc(queue_t * wq,mblk_t * mp)2807c478bd9Sstevel@tonic-gate sbioc(queue_t *wq, mblk_t *mp)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
2837c478bd9Sstevel@tonic-gate 	struct sb *sbp = (struct sb *)wq->q_ptr;
2847c478bd9Sstevel@tonic-gate 	clock_t	ticks;
2857c478bd9Sstevel@tonic-gate 	mblk_t	*mop;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
2907c478bd9Sstevel@tonic-gate 	case SBIOCGCHUNK:
2917c478bd9Sstevel@tonic-gate 	case SBIOCGSNAP:
2927c478bd9Sstevel@tonic-gate 	case SBIOCGFLAGS:
2937c478bd9Sstevel@tonic-gate 	case SBIOCGTIME:
2947c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
2957c478bd9Sstevel@tonic-gate 		return;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	case SBIOCSTIME:
2987c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2997c478bd9Sstevel@tonic-gate 		if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
3007c478bd9Sstevel@tonic-gate 			struct timeval32 *t32;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 			t32 = (struct timeval32 *)mp->b_cont->b_rptr;
3037c478bd9Sstevel@tonic-gate 			if (t32->tv_sec < 0 || t32->tv_usec < 0) {
3047c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, EINVAL);
3057c478bd9Sstevel@tonic-gate 				break;
3067c478bd9Sstevel@tonic-gate 			}
3077c478bd9Sstevel@tonic-gate 			ticks = TIMEVAL_TO_TICK(t32);
3087c478bd9Sstevel@tonic-gate 		} else
3097c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
3107c478bd9Sstevel@tonic-gate 		{
3117c478bd9Sstevel@tonic-gate 			struct timeval *tb;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 			tb = (struct timeval *)mp->b_cont->b_rptr;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 			if (tb->tv_sec < 0 || tb->tv_usec < 0) {
3167c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, EINVAL);
3177c478bd9Sstevel@tonic-gate 				break;
3187c478bd9Sstevel@tonic-gate 			}
3197c478bd9Sstevel@tonic-gate 			ticks = TIMEVAL_TO_TICK(tb);
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 		sbp->sb_ticks = ticks;
3227c478bd9Sstevel@tonic-gate 		if (ticks == 0)
3237c478bd9Sstevel@tonic-gate 			sbp->sb_chunk = 0;
3247c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
3257c478bd9Sstevel@tonic-gate 		sbclosechunk(sbp);
3267c478bd9Sstevel@tonic-gate 		return;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	case SBIOCSCHUNK:
3297c478bd9Sstevel@tonic-gate 		/*
3307c478bd9Sstevel@tonic-gate 		 * set up hi/lo water marks on stream head read queue.
3317c478bd9Sstevel@tonic-gate 		 * unlikely to run out of resources. Fix at later date.
3327c478bd9Sstevel@tonic-gate 		 */
3337c478bd9Sstevel@tonic-gate 		if ((mop = allocb(sizeof (struct stroptions),
3347c478bd9Sstevel@tonic-gate 		    BPRI_MED)) != NULL) {
3357c478bd9Sstevel@tonic-gate 			struct stroptions *sop;
3367c478bd9Sstevel@tonic-gate 			uint_t chunk;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			chunk = *(uint_t *)mp->b_cont->b_rptr;
3397c478bd9Sstevel@tonic-gate 			mop->b_datap->db_type = M_SETOPTS;
3407c478bd9Sstevel@tonic-gate 			mop->b_wptr += sizeof (struct stroptions);
3417c478bd9Sstevel@tonic-gate 			sop = (struct stroptions *)mop->b_rptr;
3427c478bd9Sstevel@tonic-gate 			sop->so_flags = SO_HIWAT | SO_LOWAT;
3437c478bd9Sstevel@tonic-gate 			sop->so_hiwat = SNIT_HIWAT(chunk, 1);
3447c478bd9Sstevel@tonic-gate 			sop->so_lowat = SNIT_LOWAT(chunk, 1);
3457c478bd9Sstevel@tonic-gate 			qreply(wq, mop);
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 		sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
3497c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
3507c478bd9Sstevel@tonic-gate 		sbclosechunk(sbp);
3517c478bd9Sstevel@tonic-gate 		return;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	case SBIOCSFLAGS:
3547c478bd9Sstevel@tonic-gate 		sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
3557c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
3567c478bd9Sstevel@tonic-gate 		return;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	case SBIOCSSNAP:
3597c478bd9Sstevel@tonic-gate 		/*
3607c478bd9Sstevel@tonic-gate 		 * if chunking dont worry about effects of
3617c478bd9Sstevel@tonic-gate 		 * snipping of message size on head flow control
3627c478bd9Sstevel@tonic-gate 		 * since it has a relatively small bearing on the
3637c478bd9Sstevel@tonic-gate 		 * data rate onto the streamn head.
3647c478bd9Sstevel@tonic-gate 		 */
3657c478bd9Sstevel@tonic-gate 		if (!sbp->sb_chunk) {
3667c478bd9Sstevel@tonic-gate 			/*
3677c478bd9Sstevel@tonic-gate 			 * set up hi/lo water marks on stream head read queue.
3687c478bd9Sstevel@tonic-gate 			 * unlikely to run out of resources. Fix at later date.
3697c478bd9Sstevel@tonic-gate 			 */
3707c478bd9Sstevel@tonic-gate 			if ((mop = allocb(sizeof (struct stroptions),
3717c478bd9Sstevel@tonic-gate 			    BPRI_MED)) != NULL) {
3727c478bd9Sstevel@tonic-gate 				struct stroptions *sop;
3737c478bd9Sstevel@tonic-gate 				uint_t snap;
3747c478bd9Sstevel@tonic-gate 				int fudge;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 				snap = *(uint_t *)mp->b_cont->b_rptr;
3777c478bd9Sstevel@tonic-gate 				mop->b_datap->db_type = M_SETOPTS;
3787c478bd9Sstevel@tonic-gate 				mop->b_wptr += sizeof (struct stroptions);
3797c478bd9Sstevel@tonic-gate 				sop = (struct stroptions *)mop->b_rptr;
3807c478bd9Sstevel@tonic-gate 				sop->so_flags = SO_HIWAT | SO_LOWAT;
3817c478bd9Sstevel@tonic-gate 				fudge = snap <= 100 ?   4 :
3827c478bd9Sstevel@tonic-gate 				    snap <= 400 ?   2 :
3837c478bd9Sstevel@tonic-gate 				    1;
3847c478bd9Sstevel@tonic-gate 				sop->so_hiwat = SNIT_HIWAT(snap, fudge);
3857c478bd9Sstevel@tonic-gate 				sop->so_lowat = SNIT_LOWAT(snap, fudge);
3867c478bd9Sstevel@tonic-gate 				qreply(wq, mop);
3877c478bd9Sstevel@tonic-gate 			}
3887c478bd9Sstevel@tonic-gate 		}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
3917c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
3927c478bd9Sstevel@tonic-gate 		return;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	default:
3957c478bd9Sstevel@tonic-gate 		ASSERT(0);
3967c478bd9Sstevel@tonic-gate 		return;
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Write-side put procedure.  Its main task is to detect ioctls
4027c478bd9Sstevel@tonic-gate  * for manipulating the buffering state and hand them to sbioctl.
4037c478bd9Sstevel@tonic-gate  * Other message types are passed on through.
4047c478bd9Sstevel@tonic-gate  */
405*57198255SToomas Soome static int
sbwput(queue_t * wq,mblk_t * mp)4067c478bd9Sstevel@tonic-gate sbwput(queue_t *wq, mblk_t *mp)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	struct	sb	*sbp = (struct sb *)wq->q_ptr;
4097c478bd9Sstevel@tonic-gate 	struct copyresp *resp;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (sbp->sb_flags & SB_SEND_ON_WRITE)
4127c478bd9Sstevel@tonic-gate 		sbclosechunk(sbp);
4137c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4147c478bd9Sstevel@tonic-gate 	case M_IOCTL:
4157c478bd9Sstevel@tonic-gate 		sbioctl(wq, mp);
4167c478bd9Sstevel@tonic-gate 		break;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	case M_IOCDATA:
4197c478bd9Sstevel@tonic-gate 		resp = (struct copyresp *)mp->b_rptr;
4207c478bd9Sstevel@tonic-gate 		if (resp->cp_rval) {
4217c478bd9Sstevel@tonic-gate 			/*
4227c478bd9Sstevel@tonic-gate 			 * Just free message on failure.
4237c478bd9Sstevel@tonic-gate 			 */
4247c478bd9Sstevel@tonic-gate 			freemsg(mp);
4257c478bd9Sstevel@tonic-gate 			break;
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		switch (resp->cp_cmd) {
4297c478bd9Sstevel@tonic-gate 		case SBIOCSTIME:
4307c478bd9Sstevel@tonic-gate 		case SBIOCSCHUNK:
4317c478bd9Sstevel@tonic-gate 		case SBIOCSFLAGS:
4327c478bd9Sstevel@tonic-gate 		case SBIOCSSNAP:
4337c478bd9Sstevel@tonic-gate 		case SBIOCGTIME:
4347c478bd9Sstevel@tonic-gate 		case SBIOCGCHUNK:
4357c478bd9Sstevel@tonic-gate 		case SBIOCGSNAP:
4367c478bd9Sstevel@tonic-gate 		case SBIOCGFLAGS:
4377c478bd9Sstevel@tonic-gate 			sbioc(wq, mp);
4387c478bd9Sstevel@tonic-gate 			break;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		default:
4417c478bd9Sstevel@tonic-gate 			putnext(wq, mp);
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 		break;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	default:
4477c478bd9Sstevel@tonic-gate 		putnext(wq, mp);
4487c478bd9Sstevel@tonic-gate 		break;
4497c478bd9Sstevel@tonic-gate 	}
450*57198255SToomas Soome 	return (0);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate  * Read-side put procedure.  It's responsible for buffering up incoming
4557c478bd9Sstevel@tonic-gate  * messages and grouping them into aggregates according to the current
4567c478bd9Sstevel@tonic-gate  * buffering parameters.
4577c478bd9Sstevel@tonic-gate  */
458*57198255SToomas Soome static int
sbrput(queue_t * rq,mblk_t * mp)4597c478bd9Sstevel@tonic-gate sbrput(queue_t *rq, mblk_t *mp)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	struct	sb	*sbp = (struct sb *)rq->q_ptr;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4667c478bd9Sstevel@tonic-gate 	case M_PROTO:
4677c478bd9Sstevel@tonic-gate 		if (sbp->sb_flags & SB_NO_PROTO_CVT) {
4687c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
4697c478bd9Sstevel@tonic-gate 			sbsendit(rq, mp);
4707c478bd9Sstevel@tonic-gate 			break;
4717c478bd9Sstevel@tonic-gate 		} else {
4727c478bd9Sstevel@tonic-gate 			/*
4737c478bd9Sstevel@tonic-gate 			 * Convert M_PROTO to M_DATA.
4747c478bd9Sstevel@tonic-gate 			 */
4757c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_DATA;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	case M_DATA:
4807c478bd9Sstevel@tonic-gate 		if ((sbp->sb_flags & SB_DEFER_CHUNK) &&
4817c478bd9Sstevel@tonic-gate 		    !(sbp->sb_state & SB_FRCVD)) {
4827c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
4837c478bd9Sstevel@tonic-gate 			sbsendit(rq, mp);
4847c478bd9Sstevel@tonic-gate 			sbp->sb_state |= SB_FRCVD;
4857c478bd9Sstevel@tonic-gate 		} else
4867c478bd9Sstevel@tonic-gate 			sbaddmsg(rq, mp);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		if ((sbp->sb_ticks > 0) && !(sbp->sb_timeoutid))
4897c478bd9Sstevel@tonic-gate 			sbp->sb_timeoutid = qtimeout(sbp->sb_rq, sbtick,
4907c478bd9Sstevel@tonic-gate 			    sbp, sbp->sb_ticks);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		break;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	case M_FLUSH:
4957c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
4967c478bd9Sstevel@tonic-gate 			/*
4977c478bd9Sstevel@tonic-gate 			 * Reset timeout, flush the chunk currently in
4987c478bd9Sstevel@tonic-gate 			 * progress, and start a new chunk.
4997c478bd9Sstevel@tonic-gate 			 */
5007c478bd9Sstevel@tonic-gate 			if (sbp->sb_timeoutid) {
5017c478bd9Sstevel@tonic-gate 				(void) quntimeout(sbp->sb_rq,
5027c478bd9Sstevel@tonic-gate 				    sbp->sb_timeoutid);
5037c478bd9Sstevel@tonic-gate 				sbp->sb_timeoutid = 0;
5047c478bd9Sstevel@tonic-gate 			}
5057c478bd9Sstevel@tonic-gate 			if (sbp->sb_mp) {
5067c478bd9Sstevel@tonic-gate 				freemsg(sbp->sb_mp);
5077c478bd9Sstevel@tonic-gate 				sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
5087c478bd9Sstevel@tonic-gate 				sbp->sb_mlen = 0;
5097c478bd9Sstevel@tonic-gate 				sbp->sb_mcount = 0;
5107c478bd9Sstevel@tonic-gate 			}
5117c478bd9Sstevel@tonic-gate 			flushq(rq, FLUSHALL);
5127c478bd9Sstevel@tonic-gate 		}
5137c478bd9Sstevel@tonic-gate 		putnext(rq, mp);
5147c478bd9Sstevel@tonic-gate 		break;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	case M_CTL:
5177c478bd9Sstevel@tonic-gate 		/*
5187c478bd9Sstevel@tonic-gate 		 * Zero-length M_CTL means our timeout() popped.
5197c478bd9Sstevel@tonic-gate 		 */
5207c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) == 0) {
5217c478bd9Sstevel@tonic-gate 			freemsg(mp);
5227c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
5237c478bd9Sstevel@tonic-gate 		} else {
5247c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
5257c478bd9Sstevel@tonic-gate 			sbsendit(rq, mp);
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 		break;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	default:
5307c478bd9Sstevel@tonic-gate 		if (mp->b_datap->db_type <= QPCTL) {
5317c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
5327c478bd9Sstevel@tonic-gate 			sbsendit(rq, mp);
5337c478bd9Sstevel@tonic-gate 		} else {
5347c478bd9Sstevel@tonic-gate 			/* Note: out of band */
5357c478bd9Sstevel@tonic-gate 			putnext(rq, mp);
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 		break;
5387c478bd9Sstevel@tonic-gate 	}
539*57198255SToomas Soome 	return (0);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  *  read service procedure.
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate /* ARGSUSED */
546*57198255SToomas Soome static int
sbrsrv(queue_t * rq)5477c478bd9Sstevel@tonic-gate sbrsrv(queue_t *rq)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	/*
5527c478bd9Sstevel@tonic-gate 	 * High priority messages shouldn't get here but if
5537c478bd9Sstevel@tonic-gate 	 * one does, jam it through to avoid infinite loop.
5547c478bd9Sstevel@tonic-gate 	 */
5557c478bd9Sstevel@tonic-gate 	while ((mp = getq(rq)) != NULL) {
5567c478bd9Sstevel@tonic-gate 		if (!canputnext(rq) && (mp->b_datap->db_type <= QPCTL)) {
5577c478bd9Sstevel@tonic-gate 			/* should only get here if SB_NO_SROPS */
5587c478bd9Sstevel@tonic-gate 			(void) putbq(rq, mp);
559*57198255SToomas Soome 			return (0);
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 		putnext(rq, mp);
5627c478bd9Sstevel@tonic-gate 	}
563*57198255SToomas Soome 	return (0);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate  * Handle write-side M_IOCTL messages.
5687c478bd9Sstevel@tonic-gate  */
5697c478bd9Sstevel@tonic-gate static void
sbioctl(queue_t * wq,mblk_t * mp)5707c478bd9Sstevel@tonic-gate sbioctl(queue_t *wq, mblk_t *mp)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	struct	sb	*sbp = (struct sb *)wq->q_ptr;
5737c478bd9Sstevel@tonic-gate 	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
5747c478bd9Sstevel@tonic-gate 	struct	timeval	*t;
5757c478bd9Sstevel@tonic-gate 	clock_t	ticks;
5767c478bd9Sstevel@tonic-gate 	mblk_t	*mop;
5777c478bd9Sstevel@tonic-gate 	int	transparent = iocp->ioc_count;
5787c478bd9Sstevel@tonic-gate 	mblk_t	*datamp;
5797c478bd9Sstevel@tonic-gate 	int	error;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
5827c478bd9Sstevel@tonic-gate 	case SBIOCSTIME:
5837c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count == TRANSPARENT) {
5847c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
5857c478bd9Sstevel@tonic-gate 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
5867c478bd9Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (struct timeval32),
5877c478bd9Sstevel@tonic-gate 				    NULL);
5887c478bd9Sstevel@tonic-gate 			} else
5897c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
5907c478bd9Sstevel@tonic-gate 			{
5917c478bd9Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (*t), NULL);
5927c478bd9Sstevel@tonic-gate 			}
5937c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
5947c478bd9Sstevel@tonic-gate 		} else {
5957c478bd9Sstevel@tonic-gate 			/*
5967c478bd9Sstevel@tonic-gate 			 * Verify argument length.
5977c478bd9Sstevel@tonic-gate 			 */
5987c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
5997c478bd9Sstevel@tonic-gate 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6007c478bd9Sstevel@tonic-gate 				struct timeval32 *t32;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 				error = miocpullup(mp,
6037c478bd9Sstevel@tonic-gate 				    sizeof (struct timeval32));
6047c478bd9Sstevel@tonic-gate 				if (error != 0) {
6057c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, error);
6067c478bd9Sstevel@tonic-gate 					break;
6077c478bd9Sstevel@tonic-gate 				}
6087c478bd9Sstevel@tonic-gate 				t32 = (struct timeval32 *)mp->b_cont->b_rptr;
6097c478bd9Sstevel@tonic-gate 				if (t32->tv_sec < 0 || t32->tv_usec < 0) {
6107c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, EINVAL);
6117c478bd9Sstevel@tonic-gate 					break;
6127c478bd9Sstevel@tonic-gate 				}
6137c478bd9Sstevel@tonic-gate 				ticks = TIMEVAL_TO_TICK(t32);
6147c478bd9Sstevel@tonic-gate 			} else
6157c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6167c478bd9Sstevel@tonic-gate 			{
6177c478bd9Sstevel@tonic-gate 				error = miocpullup(mp, sizeof (struct timeval));
6187c478bd9Sstevel@tonic-gate 				if (error != 0) {
6197c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, error);
6207c478bd9Sstevel@tonic-gate 					break;
6217c478bd9Sstevel@tonic-gate 				}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 				t = (struct timeval *)mp->b_cont->b_rptr;
6247c478bd9Sstevel@tonic-gate 				if (t->tv_sec < 0 || t->tv_usec < 0) {
6257c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, EINVAL);
6267c478bd9Sstevel@tonic-gate 					break;
6277c478bd9Sstevel@tonic-gate 				}
6287c478bd9Sstevel@tonic-gate 				ticks = TIMEVAL_TO_TICK(t);
6297c478bd9Sstevel@tonic-gate 			}
6307c478bd9Sstevel@tonic-gate 			sbp->sb_ticks = ticks;
6317c478bd9Sstevel@tonic-gate 			if (ticks == 0)
6327c478bd9Sstevel@tonic-gate 				sbp->sb_chunk = 0;
6337c478bd9Sstevel@tonic-gate 			miocack(wq, mp, 0, 0);
6347c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	case SBIOCGTIME: {
6397c478bd9Sstevel@tonic-gate 		struct timeval *t;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		/*
6427c478bd9Sstevel@tonic-gate 		 * Verify argument length.
6437c478bd9Sstevel@tonic-gate 		 */
6447c478bd9Sstevel@tonic-gate 		if (transparent != TRANSPARENT) {
6457c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6467c478bd9Sstevel@tonic-gate 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6477c478bd9Sstevel@tonic-gate 				error = miocpullup(mp,
6487c478bd9Sstevel@tonic-gate 				    sizeof (struct timeval32));
6497c478bd9Sstevel@tonic-gate 				if (error != 0) {
6507c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, error);
6517c478bd9Sstevel@tonic-gate 					break;
6527c478bd9Sstevel@tonic-gate 				}
6537c478bd9Sstevel@tonic-gate 			} else
6547c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6557c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct timeval));
6567c478bd9Sstevel@tonic-gate 			if (error != 0) {
6577c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
6587c478bd9Sstevel@tonic-gate 				break;
6597c478bd9Sstevel@tonic-gate 			}
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		/*
6637c478bd9Sstevel@tonic-gate 		 * If infinite timeout, return range error
6647c478bd9Sstevel@tonic-gate 		 * for the ioctl.
6657c478bd9Sstevel@tonic-gate 		 */
6667c478bd9Sstevel@tonic-gate 		if (sbp->sb_ticks < 0) {
6677c478bd9Sstevel@tonic-gate 			miocnak(wq, mp, 0, ERANGE);
6687c478bd9Sstevel@tonic-gate 			break;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6727c478bd9Sstevel@tonic-gate 		if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6737c478bd9Sstevel@tonic-gate 			struct timeval32 *t32;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 			if (transparent == TRANSPARENT) {
6767c478bd9Sstevel@tonic-gate 				datamp = allocb(sizeof (*t32), BPRI_MED);
6777c478bd9Sstevel@tonic-gate 				if (datamp == NULL) {
6787c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, EAGAIN);
6797c478bd9Sstevel@tonic-gate 					break;
6807c478bd9Sstevel@tonic-gate 				}
6817c478bd9Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (*t32), NULL, datamp);
6827c478bd9Sstevel@tonic-gate 			}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			t32 = (struct timeval32 *)mp->b_cont->b_rptr;
6857c478bd9Sstevel@tonic-gate 			TICK_TO_TIMEVAL32(sbp->sb_ticks, t32);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 			if (transparent == TRANSPARENT)
6887c478bd9Sstevel@tonic-gate 				qreply(wq, mp);
6897c478bd9Sstevel@tonic-gate 			else
6907c478bd9Sstevel@tonic-gate 				miocack(wq, mp, sizeof (*t32), 0);
6917c478bd9Sstevel@tonic-gate 		} else
6927c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6937c478bd9Sstevel@tonic-gate 		{
6947c478bd9Sstevel@tonic-gate 			if (transparent == TRANSPARENT) {
6957c478bd9Sstevel@tonic-gate 				datamp = allocb(sizeof (*t), BPRI_MED);
6967c478bd9Sstevel@tonic-gate 				if (datamp == NULL) {
6977c478bd9Sstevel@tonic-gate 					miocnak(wq, mp, 0, EAGAIN);
6987c478bd9Sstevel@tonic-gate 					break;
6997c478bd9Sstevel@tonic-gate 				}
7007c478bd9Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (*t), NULL, datamp);
7017c478bd9Sstevel@tonic-gate 			}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 			t = (struct timeval *)mp->b_cont->b_rptr;
7047c478bd9Sstevel@tonic-gate 			TICK_TO_TIMEVAL(sbp->sb_ticks, t);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 			if (transparent == TRANSPARENT)
7077c478bd9Sstevel@tonic-gate 				qreply(wq, mp);
7087c478bd9Sstevel@tonic-gate 			else
7097c478bd9Sstevel@tonic-gate 				miocack(wq, mp, sizeof (*t), 0);
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 		break;
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	case SBIOCCTIME:
7157c478bd9Sstevel@tonic-gate 		sbp->sb_ticks = -1;
7167c478bd9Sstevel@tonic-gate 		miocack(wq, mp, 0, 0);
7177c478bd9Sstevel@tonic-gate 		break;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	case SBIOCSCHUNK:
7207c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count == TRANSPARENT) {
7217c478bd9Sstevel@tonic-gate 			mcopyin(mp, NULL, sizeof (uint_t), NULL);
7227c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
7237c478bd9Sstevel@tonic-gate 		} else {
7247c478bd9Sstevel@tonic-gate 			/*
7257c478bd9Sstevel@tonic-gate 			 * Verify argument length.
7267c478bd9Sstevel@tonic-gate 			 */
7277c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
7287c478bd9Sstevel@tonic-gate 			if (error != 0) {
7297c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
7307c478bd9Sstevel@tonic-gate 				break;
7317c478bd9Sstevel@tonic-gate 			}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 			/*
7347c478bd9Sstevel@tonic-gate 			 * set up hi/lo water marks on stream head read queue.
7357c478bd9Sstevel@tonic-gate 			 * unlikely to run out of resources. Fix at later date.
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			if ((mop = allocb(sizeof (struct stroptions),
7387c478bd9Sstevel@tonic-gate 			    BPRI_MED)) != NULL) {
7397c478bd9Sstevel@tonic-gate 				struct stroptions *sop;
7407c478bd9Sstevel@tonic-gate 				uint_t chunk;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 				chunk = *(uint_t *)mp->b_cont->b_rptr;
7437c478bd9Sstevel@tonic-gate 				mop->b_datap->db_type = M_SETOPTS;
7447c478bd9Sstevel@tonic-gate 				mop->b_wptr += sizeof (struct stroptions);
7457c478bd9Sstevel@tonic-gate 				sop = (struct stroptions *)mop->b_rptr;
7467c478bd9Sstevel@tonic-gate 				sop->so_flags = SO_HIWAT | SO_LOWAT;
7477c478bd9Sstevel@tonic-gate 				sop->so_hiwat = SNIT_HIWAT(chunk, 1);
7487c478bd9Sstevel@tonic-gate 				sop->so_lowat = SNIT_LOWAT(chunk, 1);
7497c478bd9Sstevel@tonic-gate 				qreply(wq, mop);
7507c478bd9Sstevel@tonic-gate 			}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 			sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
7537c478bd9Sstevel@tonic-gate 			miocack(wq, mp, 0, 0);
7547c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	case SBIOCGCHUNK:
7597c478bd9Sstevel@tonic-gate 		/*
7607c478bd9Sstevel@tonic-gate 		 * Verify argument length.
7617c478bd9Sstevel@tonic-gate 		 */
7627c478bd9Sstevel@tonic-gate 		if (transparent != TRANSPARENT) {
7637c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
7647c478bd9Sstevel@tonic-gate 			if (error != 0) {
7657c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
7667c478bd9Sstevel@tonic-gate 				break;
7677c478bd9Sstevel@tonic-gate 			}
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT) {
7717c478bd9Sstevel@tonic-gate 			datamp = allocb(sizeof (uint_t), BPRI_MED);
7727c478bd9Sstevel@tonic-gate 			if (datamp == NULL) {
7737c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, EAGAIN);
7747c478bd9Sstevel@tonic-gate 				break;
7757c478bd9Sstevel@tonic-gate 			}
7767c478bd9Sstevel@tonic-gate 			mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
7777c478bd9Sstevel@tonic-gate 		}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 		*(uint_t *)mp->b_cont->b_rptr = sbp->sb_chunk;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT)
7827c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
7837c478bd9Sstevel@tonic-gate 		else
7847c478bd9Sstevel@tonic-gate 			miocack(wq, mp, sizeof (uint_t), 0);
7857c478bd9Sstevel@tonic-gate 		break;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	case SBIOCSSNAP:
7887c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count == TRANSPARENT) {
7897c478bd9Sstevel@tonic-gate 			mcopyin(mp, NULL, sizeof (uint_t), NULL);
7907c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
7917c478bd9Sstevel@tonic-gate 		} else {
7927c478bd9Sstevel@tonic-gate 			/*
7937c478bd9Sstevel@tonic-gate 			 * Verify argument length.
7947c478bd9Sstevel@tonic-gate 			 */
7957c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
7967c478bd9Sstevel@tonic-gate 			if (error != 0) {
7977c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
7987c478bd9Sstevel@tonic-gate 				break;
7997c478bd9Sstevel@tonic-gate 			}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 			/*
8027c478bd9Sstevel@tonic-gate 			 * if chunking dont worry about effects of
8037c478bd9Sstevel@tonic-gate 			 * snipping of message size on head flow control
8047c478bd9Sstevel@tonic-gate 			 * since it has a relatively small bearing on the
8057c478bd9Sstevel@tonic-gate 			 * data rate onto the streamn head.
8067c478bd9Sstevel@tonic-gate 			 */
8077c478bd9Sstevel@tonic-gate 			if (!sbp->sb_chunk) {
8087c478bd9Sstevel@tonic-gate 				/*
8097c478bd9Sstevel@tonic-gate 				 * set up hi/lo water marks on stream
8107c478bd9Sstevel@tonic-gate 				 * head read queue.  unlikely to run out
8117c478bd9Sstevel@tonic-gate 				 * of resources. Fix at later date.
8127c478bd9Sstevel@tonic-gate 				 */
8137c478bd9Sstevel@tonic-gate 				if ((mop = allocb(sizeof (struct stroptions),
8147c478bd9Sstevel@tonic-gate 				    BPRI_MED)) != NULL) {
8157c478bd9Sstevel@tonic-gate 					struct stroptions *sop;
8167c478bd9Sstevel@tonic-gate 					uint_t snap;
8177c478bd9Sstevel@tonic-gate 					int fudge;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 					snap = *(uint_t *)mp->b_cont->b_rptr;
8207c478bd9Sstevel@tonic-gate 					mop->b_datap->db_type = M_SETOPTS;
8217c478bd9Sstevel@tonic-gate 					mop->b_wptr += sizeof (*sop);
8227c478bd9Sstevel@tonic-gate 					sop = (struct stroptions *)mop->b_rptr;
8237c478bd9Sstevel@tonic-gate 					sop->so_flags = SO_HIWAT | SO_LOWAT;
8247c478bd9Sstevel@tonic-gate 					fudge = (snap <= 100) ? 4 :
8257c478bd9Sstevel@tonic-gate 					    (snap <= 400) ? 2 : 1;
8267c478bd9Sstevel@tonic-gate 					sop->so_hiwat = SNIT_HIWAT(snap, fudge);
8277c478bd9Sstevel@tonic-gate 					sop->so_lowat = SNIT_LOWAT(snap, fudge);
8287c478bd9Sstevel@tonic-gate 					qreply(wq, mop);
8297c478bd9Sstevel@tonic-gate 				}
8307c478bd9Sstevel@tonic-gate 			}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 			sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 			miocack(wq, mp, 0, 0);
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 		break;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	case SBIOCGSNAP:
8397c478bd9Sstevel@tonic-gate 		/*
8407c478bd9Sstevel@tonic-gate 		 * Verify argument length
8417c478bd9Sstevel@tonic-gate 		 */
8427c478bd9Sstevel@tonic-gate 		if (transparent != TRANSPARENT) {
8437c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
8447c478bd9Sstevel@tonic-gate 			if (error != 0) {
8457c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
8467c478bd9Sstevel@tonic-gate 				break;
8477c478bd9Sstevel@tonic-gate 			}
8487c478bd9Sstevel@tonic-gate 		}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT) {
8517c478bd9Sstevel@tonic-gate 			datamp = allocb(sizeof (uint_t), BPRI_MED);
8527c478bd9Sstevel@tonic-gate 			if (datamp == NULL) {
8537c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, EAGAIN);
8547c478bd9Sstevel@tonic-gate 				break;
8557c478bd9Sstevel@tonic-gate 			}
8567c478bd9Sstevel@tonic-gate 			mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		*(uint_t *)mp->b_cont->b_rptr = sbp->sb_snap;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT)
8627c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
8637c478bd9Sstevel@tonic-gate 		else
8647c478bd9Sstevel@tonic-gate 			miocack(wq, mp, sizeof (uint_t), 0);
8657c478bd9Sstevel@tonic-gate 		break;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	case SBIOCSFLAGS:
8687c478bd9Sstevel@tonic-gate 		/*
8697c478bd9Sstevel@tonic-gate 		 * set the flags.
8707c478bd9Sstevel@tonic-gate 		 */
8717c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count == TRANSPARENT) {
8727c478bd9Sstevel@tonic-gate 			mcopyin(mp, NULL, sizeof (uint_t), NULL);
8737c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
8747c478bd9Sstevel@tonic-gate 		} else {
8757c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
8767c478bd9Sstevel@tonic-gate 			if (error != 0) {
8777c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
8787c478bd9Sstevel@tonic-gate 				break;
8797c478bd9Sstevel@tonic-gate 			}
8807c478bd9Sstevel@tonic-gate 			sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
8817c478bd9Sstevel@tonic-gate 			miocack(wq, mp, 0, 0);
8827c478bd9Sstevel@tonic-gate 		}
8837c478bd9Sstevel@tonic-gate 		break;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	case SBIOCGFLAGS:
8867c478bd9Sstevel@tonic-gate 		/*
8877c478bd9Sstevel@tonic-gate 		 * Verify argument length
8887c478bd9Sstevel@tonic-gate 		 */
8897c478bd9Sstevel@tonic-gate 		if (transparent != TRANSPARENT) {
8907c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (uint_t));
8917c478bd9Sstevel@tonic-gate 			if (error != 0) {
8927c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, error);
8937c478bd9Sstevel@tonic-gate 				break;
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT) {
8987c478bd9Sstevel@tonic-gate 			datamp = allocb(sizeof (uint_t), BPRI_MED);
8997c478bd9Sstevel@tonic-gate 			if (datamp == NULL) {
9007c478bd9Sstevel@tonic-gate 				miocnak(wq, mp, 0, EAGAIN);
9017c478bd9Sstevel@tonic-gate 				break;
9027c478bd9Sstevel@tonic-gate 			}
9037c478bd9Sstevel@tonic-gate 			mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
9047c478bd9Sstevel@tonic-gate 		}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		*(uint_t *)mp->b_cont->b_rptr = sbp->sb_flags;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 		if (transparent == TRANSPARENT)
9097c478bd9Sstevel@tonic-gate 			qreply(wq, mp);
9107c478bd9Sstevel@tonic-gate 		else
9117c478bd9Sstevel@tonic-gate 			miocack(wq, mp, sizeof (uint_t), 0);
9127c478bd9Sstevel@tonic-gate 		break;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	default:
9167c478bd9Sstevel@tonic-gate 		putnext(wq, mp);
9177c478bd9Sstevel@tonic-gate 		break;
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate  * Given a length l, calculate the amount of extra storage
9237c478bd9Sstevel@tonic-gate  * required to round it up to the next multiple of the alignment a.
9247c478bd9Sstevel@tonic-gate  */
9257c478bd9Sstevel@tonic-gate #define	RoundUpAmt(l, a)	((l) % (a) ? (a) - ((l) % (a)) : 0)
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate  * Calculate additional amount of space required for alignment.
9287c478bd9Sstevel@tonic-gate  */
9297c478bd9Sstevel@tonic-gate #define	Align(l)		RoundUpAmt(l, sizeof (ulong_t))
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate  * Smallest possible message size when headers are enabled.
9327c478bd9Sstevel@tonic-gate  * This is used to calculate whether a chunk is nearly full.
9337c478bd9Sstevel@tonic-gate  */
9347c478bd9Sstevel@tonic-gate #define	SMALLEST_MESSAGE	sizeof (struct sb_hdr) + _POINTER_ALIGNMENT
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate  * Process a read-side M_DATA message.
9387c478bd9Sstevel@tonic-gate  *
9397c478bd9Sstevel@tonic-gate  * If the currently accumulating chunk doesn't have enough room
9407c478bd9Sstevel@tonic-gate  * for the message, close off the chunk, pass it upward, and start
9417c478bd9Sstevel@tonic-gate  * a new one.  Then add the message to the current chunk, taking
9427c478bd9Sstevel@tonic-gate  * account of the possibility that the message's size exceeds the
9437c478bd9Sstevel@tonic-gate  * chunk size.
9447c478bd9Sstevel@tonic-gate  *
9457c478bd9Sstevel@tonic-gate  * If headers are enabled add an sb_hdr header and trailing alignment padding.
9467c478bd9Sstevel@tonic-gate  *
9477c478bd9Sstevel@tonic-gate  * To optimise performance the total number of msgbs should be kept
9487c478bd9Sstevel@tonic-gate  * to a minimum. This is achieved by using any remaining space in message N
9497c478bd9Sstevel@tonic-gate  * for both its own padding as well as the header of message N+1 if possible.
9507c478bd9Sstevel@tonic-gate  * If there's insufficient space we allocate one message to hold this 'wrapper'.
9517c478bd9Sstevel@tonic-gate  * (there's likely to be space beyond message N, since allocb would have
9527c478bd9Sstevel@tonic-gate  * rounded up the required size to one of the dblk_sizes).
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  */
9557c478bd9Sstevel@tonic-gate static void
sbaddmsg(queue_t * rq,mblk_t * mp)9567c478bd9Sstevel@tonic-gate sbaddmsg(queue_t *rq, mblk_t *mp)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	struct sb	*sbp;
9597c478bd9Sstevel@tonic-gate 	struct timeval	t;
9607c478bd9Sstevel@tonic-gate 	struct sb_hdr	hp;
9617c478bd9Sstevel@tonic-gate 	mblk_t *wrapper;	/* padding for msg N, header for msg N+1 */
9627c478bd9Sstevel@tonic-gate 	mblk_t *last;		/* last mblk of current message */
9637c478bd9Sstevel@tonic-gate 	size_t wrapperlen;	/* length of header + padding */
9647c478bd9Sstevel@tonic-gate 	size_t origlen;		/* data length before truncation */
9657c478bd9Sstevel@tonic-gate 	size_t pad;		/* bytes required to align header */
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	sbp = (struct sb *)rq->q_ptr;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	origlen = msgdsize(mp);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/*
9727c478bd9Sstevel@tonic-gate 	 * Truncate the message.
9737c478bd9Sstevel@tonic-gate 	 */
9747c478bd9Sstevel@tonic-gate 	if ((sbp->sb_snap > 0) && (origlen > sbp->sb_snap) &&
975*57198255SToomas Soome 	    (adjmsg(mp, -(origlen - sbp->sb_snap)) == 1))
9767c478bd9Sstevel@tonic-gate 		hp.sbh_totlen = hp.sbh_msglen = sbp->sb_snap;
9777c478bd9Sstevel@tonic-gate 	else
9787c478bd9Sstevel@tonic-gate 		hp.sbh_totlen = hp.sbh_msglen = origlen;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (sbp->sb_flags & SB_NO_HEADER) {
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		/*
9837c478bd9Sstevel@tonic-gate 		 * Would the inclusion of this message overflow the current
9847c478bd9Sstevel@tonic-gate 		 * chunk? If so close the chunk off and start a new one.
9857c478bd9Sstevel@tonic-gate 		 */
9867c478bd9Sstevel@tonic-gate 		if ((hp.sbh_totlen + sbp->sb_mlen) > sbp->sb_chunk)
9877c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * First message too big for chunk - just send it up.
9907c478bd9Sstevel@tonic-gate 		 * This will always be true when we're not chunking.
9917c478bd9Sstevel@tonic-gate 		 */
9927c478bd9Sstevel@tonic-gate 		if (hp.sbh_totlen > sbp->sb_chunk) {
9937c478bd9Sstevel@tonic-gate 			sbsendit(rq, mp);
9947c478bd9Sstevel@tonic-gate 			return;
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		/*
9987c478bd9Sstevel@tonic-gate 		 * We now know that the msg will fit in the chunk.
9997c478bd9Sstevel@tonic-gate 		 * Link it onto the end of the chunk.
10007c478bd9Sstevel@tonic-gate 		 * Since linkb() walks the entire chain, we keep a pointer to
10017c478bd9Sstevel@tonic-gate 		 * the first mblk of the last msgb added and call linkb on that
10027c478bd9Sstevel@tonic-gate 		 * that last message, rather than performing the
10037c478bd9Sstevel@tonic-gate 		 * O(n) linkb() operation on the whole chain.
10047c478bd9Sstevel@tonic-gate 		 * sb_head isn't needed in this SB_NO_HEADER mode.
10057c478bd9Sstevel@tonic-gate 		 */
10067c478bd9Sstevel@tonic-gate 		if (sbp->sb_mp)
10077c478bd9Sstevel@tonic-gate 			linkb(sbp->sb_tail, mp);
10087c478bd9Sstevel@tonic-gate 		else
10097c478bd9Sstevel@tonic-gate 			sbp->sb_mp = mp;
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 		sbp->sb_tail = mp;
10127c478bd9Sstevel@tonic-gate 		sbp->sb_mlen += hp.sbh_totlen;
10137c478bd9Sstevel@tonic-gate 		sbp->sb_mcount++;
10147c478bd9Sstevel@tonic-gate 	} else {
10157c478bd9Sstevel@tonic-gate 		/* Timestamp must be done immediately */
10167c478bd9Sstevel@tonic-gate 		uniqtime(&t);
10177c478bd9Sstevel@tonic-gate 		TIMEVAL_TO_TIMEVAL32(&hp.sbh_timestamp, &t);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 		pad = Align(hp.sbh_totlen);
10207c478bd9Sstevel@tonic-gate 		hp.sbh_totlen += sizeof (hp);
1021eb00302cSRyan Zezeski 
1022eb00302cSRyan Zezeski 		/* We can't fit this message on the current chunk. */
1023eb00302cSRyan Zezeski 		if ((sbp->sb_mlen + hp.sbh_totlen) > sbp->sb_chunk)
1024eb00302cSRyan Zezeski 			sbclosechunk(sbp);
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		/*
1027eb00302cSRyan Zezeski 		 * If we closed it (just now or during a previous
1028eb00302cSRyan Zezeski 		 * call) then allocate the head of a new chunk.
10297c478bd9Sstevel@tonic-gate 		 */
10307c478bd9Sstevel@tonic-gate 		if (sbp->sb_head == NULL) {
10317c478bd9Sstevel@tonic-gate 			/* Allocate leading header of new chunk */
10327c478bd9Sstevel@tonic-gate 			sbp->sb_head = allocb(sizeof (hp), BPRI_MED);
10337c478bd9Sstevel@tonic-gate 			if (sbp->sb_head == NULL) {
10347c478bd9Sstevel@tonic-gate 				/*
10357c478bd9Sstevel@tonic-gate 				 * Memory allocation failure.
10367c478bd9Sstevel@tonic-gate 				 * This will need to be revisited
10377c478bd9Sstevel@tonic-gate 				 * since using certain flag combinations
10387c478bd9Sstevel@tonic-gate 				 * can result in messages being dropped
10397c478bd9Sstevel@tonic-gate 				 * silently.
10407c478bd9Sstevel@tonic-gate 				 */
10417c478bd9Sstevel@tonic-gate 				freemsg(mp);
10427c478bd9Sstevel@tonic-gate 				sbp->sb_drops++;
10437c478bd9Sstevel@tonic-gate 				return;
10447c478bd9Sstevel@tonic-gate 			}
10457c478bd9Sstevel@tonic-gate 			sbp->sb_mp = sbp->sb_head;
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		/*
1049eb00302cSRyan Zezeski 		 * Set the header values and join the message to the
1050eb00302cSRyan Zezeski 		 * chunk. The header values are copied into the chunk
1051eb00302cSRyan Zezeski 		 * after we adjust for padding below.
10527c478bd9Sstevel@tonic-gate 		 */
10537c478bd9Sstevel@tonic-gate 		hp.sbh_drops = sbp->sb_drops;
10547c478bd9Sstevel@tonic-gate 		hp.sbh_origlen = origlen;
10557c478bd9Sstevel@tonic-gate 		linkb(sbp->sb_head, mp);
10567c478bd9Sstevel@tonic-gate 		sbp->sb_mcount++;
10577c478bd9Sstevel@tonic-gate 		sbp->sb_mlen += hp.sbh_totlen;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		/*
1060eb00302cSRyan Zezeski 		 * There's no chance to fit another message on the
1061eb00302cSRyan Zezeski 		 * chunk -- forgo the padding and close the chunk.
10627c478bd9Sstevel@tonic-gate 		 */
1063eb00302cSRyan Zezeski 		if ((sbp->sb_mlen + pad + SMALLEST_MESSAGE) > sbp->sb_chunk) {
1064eb00302cSRyan Zezeski 			(void) memcpy(sbp->sb_head->b_wptr, (char *)&hp,
1065eb00302cSRyan Zezeski 			    sizeof (hp));
1066eb00302cSRyan Zezeski 			sbp->sb_head->b_wptr += sizeof (hp);
1067eb00302cSRyan Zezeski 			ASSERT(sbp->sb_head->b_wptr <=
1068eb00302cSRyan Zezeski 			    sbp->sb_head->b_datap->db_lim);
10697c478bd9Sstevel@tonic-gate 			sbclosechunk(sbp);
10707c478bd9Sstevel@tonic-gate 			return;
10717c478bd9Sstevel@tonic-gate 		}
10727c478bd9Sstevel@tonic-gate 
1073eb00302cSRyan Zezeski 		/*
1074eb00302cSRyan Zezeski 		 * We may add another message to this chunk -- adjust
1075eb00302cSRyan Zezeski 		 * the headers for padding to be added below.
1076eb00302cSRyan Zezeski 		 */
1077eb00302cSRyan Zezeski 		hp.sbh_totlen += pad;
1078eb00302cSRyan Zezeski 		(void) memcpy(sbp->sb_head->b_wptr, (char *)&hp, sizeof (hp));
1079eb00302cSRyan Zezeski 		sbp->sb_head->b_wptr += sizeof (hp);
1080eb00302cSRyan Zezeski 		ASSERT(sbp->sb_head->b_wptr <= sbp->sb_head->b_datap->db_lim);
1081eb00302cSRyan Zezeski 		sbp->sb_mlen += pad;
1082eb00302cSRyan Zezeski 
10837c478bd9Sstevel@tonic-gate 		/*
10847c478bd9Sstevel@tonic-gate 		 * Find space for the wrapper. The wrapper consists of:
10857c478bd9Sstevel@tonic-gate 		 *
10867c478bd9Sstevel@tonic-gate 		 * 1) Padding for this message (this is to ensure each header
10877c478bd9Sstevel@tonic-gate 		 * begins on an 8 byte boundary in the userland buffer).
10887c478bd9Sstevel@tonic-gate 		 *
10897c478bd9Sstevel@tonic-gate 		 * 2) Space for the next message's header, in case the next
10907c478bd9Sstevel@tonic-gate 		 * next message will fit in this chunk.
10917c478bd9Sstevel@tonic-gate 		 *
10927c478bd9Sstevel@tonic-gate 		 * It may be possible to append the wrapper to the last mblk
10937c478bd9Sstevel@tonic-gate 		 * of the message, but only if we 'own' the data. If the dblk
10947c478bd9Sstevel@tonic-gate 		 * has been shared through dupmsg() we mustn't alter it.
10957c478bd9Sstevel@tonic-gate 		 */
10967c478bd9Sstevel@tonic-gate 		wrapperlen = (sizeof (hp) + pad);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		/* Is there space for the wrapper beyond the message's data ? */
10997c478bd9Sstevel@tonic-gate 		for (last = mp; last->b_cont; last = last->b_cont)
11007c478bd9Sstevel@tonic-gate 			;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		if ((wrapperlen <= MBLKTAIL(last)) &&
1103*57198255SToomas Soome 		    (last->b_datap->db_ref == 1)) {
11047c478bd9Sstevel@tonic-gate 			if (pad > 0) {
11057c478bd9Sstevel@tonic-gate 				/*
11067c478bd9Sstevel@tonic-gate 				 * Pad with zeroes to the next pointer boundary
11077c478bd9Sstevel@tonic-gate 				 * (we don't want to disclose kernel data to
11087c478bd9Sstevel@tonic-gate 				 * users), then advance wptr.
11097c478bd9Sstevel@tonic-gate 				 */
11107c478bd9Sstevel@tonic-gate 				(void) memset(last->b_wptr, 0, pad);
11117c478bd9Sstevel@tonic-gate 				last->b_wptr += pad;
11127c478bd9Sstevel@tonic-gate 			}
11137c478bd9Sstevel@tonic-gate 			/* Remember where to write the header information */
11147c478bd9Sstevel@tonic-gate 			sbp->sb_head = last;
11157c478bd9Sstevel@tonic-gate 		} else {
11167c478bd9Sstevel@tonic-gate 			/* Have to allocate additional space for the wrapper */
11177c478bd9Sstevel@tonic-gate 			wrapper = allocb(wrapperlen, BPRI_MED);
11187c478bd9Sstevel@tonic-gate 			if (wrapper == NULL) {
11197c478bd9Sstevel@tonic-gate 				sbclosechunk(sbp);
11207c478bd9Sstevel@tonic-gate 				return;
11217c478bd9Sstevel@tonic-gate 			}
11227c478bd9Sstevel@tonic-gate 			if (pad > 0) {
11237c478bd9Sstevel@tonic-gate 				/*
11247c478bd9Sstevel@tonic-gate 				 * Pad with zeroes (we don't want to disclose
11257c478bd9Sstevel@tonic-gate 				 * kernel data to users).
11267c478bd9Sstevel@tonic-gate 				 */
11277c478bd9Sstevel@tonic-gate 				(void) memset(wrapper->b_wptr, 0, pad);
11287c478bd9Sstevel@tonic-gate 				wrapper->b_wptr += pad;
11297c478bd9Sstevel@tonic-gate 			}
11307c478bd9Sstevel@tonic-gate 			/* Link the wrapper msg onto the end of the chunk */
11317c478bd9Sstevel@tonic-gate 			linkb(mp, wrapper);
11327c478bd9Sstevel@tonic-gate 			/* Remember to write the next header in this wrapper */
11337c478bd9Sstevel@tonic-gate 			sbp->sb_head = wrapper;
11347c478bd9Sstevel@tonic-gate 		}
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate  * Called from timeout().
11407c478bd9Sstevel@tonic-gate  * Signal a timeout by passing a zero-length M_CTL msg in the read-side
11417c478bd9Sstevel@tonic-gate  * to synchronize with any active module threads (open, close, wput, rput).
11427c478bd9Sstevel@tonic-gate  */
11437c478bd9Sstevel@tonic-gate static void
sbtick(void * arg)11447c478bd9Sstevel@tonic-gate sbtick(void *arg)
11457c478bd9Sstevel@tonic-gate {
11467c478bd9Sstevel@tonic-gate 	struct sb *sbp = arg;
11477c478bd9Sstevel@tonic-gate 	queue_t	*rq;
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	rq = sbp->sb_rq;
11527c478bd9Sstevel@tonic-gate 	sbp->sb_timeoutid = 0;		/* timeout has fired */
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	if (putctl(rq, M_CTL) == 0)	/* failure */
11557c478bd9Sstevel@tonic-gate 		sbp->sb_timeoutid = qtimeout(rq, sbtick, sbp, sbp->sb_ticks);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate  * Close off the currently accumulating chunk and pass
11607c478bd9Sstevel@tonic-gate  * it upward.  Takes care of resetting timers as well.
11617c478bd9Sstevel@tonic-gate  *
11627c478bd9Sstevel@tonic-gate  * This routine is called both directly and as a result
11637c478bd9Sstevel@tonic-gate  * of the chunk timeout expiring.
11647c478bd9Sstevel@tonic-gate  */
11657c478bd9Sstevel@tonic-gate static void
sbclosechunk(struct sb * sbp)11667c478bd9Sstevel@tonic-gate sbclosechunk(struct sb *sbp)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
11697c478bd9Sstevel@tonic-gate 	queue_t	*rq;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	ASSERT(sbp);
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	if (sbp->sb_timeoutid) {
11747c478bd9Sstevel@tonic-gate 		(void) quntimeout(sbp->sb_rq, sbp->sb_timeoutid);
11757c478bd9Sstevel@tonic-gate 		sbp->sb_timeoutid = 0;
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	mp = sbp->sb_mp;
11797c478bd9Sstevel@tonic-gate 	rq = sbp->sb_rq;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	/*
11827c478bd9Sstevel@tonic-gate 	 * If there's currently a chunk in progress, close it off
11837c478bd9Sstevel@tonic-gate 	 * and try to send it up.
11847c478bd9Sstevel@tonic-gate 	 */
11857c478bd9Sstevel@tonic-gate 	if (mp) {
11867c478bd9Sstevel@tonic-gate 		sbsendit(rq, mp);
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/*
11907c478bd9Sstevel@tonic-gate 	 * Clear old chunk.  Ready for new msgs.
11917c478bd9Sstevel@tonic-gate 	 */
11927c478bd9Sstevel@tonic-gate 	sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
11937c478bd9Sstevel@tonic-gate 	sbp->sb_mlen = 0;
11947c478bd9Sstevel@tonic-gate 	sbp->sb_mcount = 0;
11957c478bd9Sstevel@tonic-gate 	if (sbp->sb_flags & SB_DEFER_CHUNK)
11967c478bd9Sstevel@tonic-gate 		sbp->sb_state &= ~SB_FRCVD;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate static void
sbsendit(queue_t * rq,mblk_t * mp)12017c478bd9Sstevel@tonic-gate sbsendit(queue_t *rq, mblk_t *mp)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	struct	sb	*sbp = (struct sb *)rq->q_ptr;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	if (!canputnext(rq)) {
12067c478bd9Sstevel@tonic-gate 		if (sbp->sb_flags & SB_NO_DROPS)
12077c478bd9Sstevel@tonic-gate 			(void) putq(rq, mp);
12087c478bd9Sstevel@tonic-gate 		else {
12097c478bd9Sstevel@tonic-gate 			freemsg(mp);
12107c478bd9Sstevel@tonic-gate 			sbp->sb_drops += sbp->sb_mcount;
12117c478bd9Sstevel@tonic-gate 		}
12127c478bd9Sstevel@tonic-gate 		return;
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 	/*
12157c478bd9Sstevel@tonic-gate 	 * If there are messages on the q already, keep
12167c478bd9Sstevel@tonic-gate 	 * queueing them since they need to be processed in order.
12177c478bd9Sstevel@tonic-gate 	 */
12187c478bd9Sstevel@tonic-gate 	if (qsize(rq) > 0) {
12197c478bd9Sstevel@tonic-gate 		/* should only get here if SB_NO_DROPS */
12207c478bd9Sstevel@tonic-gate 		(void) putq(rq, mp);
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 	else
12237c478bd9Sstevel@tonic-gate 		putnext(rq, mp);
12247c478bd9Sstevel@tonic-gate }
1225