xref: /titanic_54/usr/src/uts/common/inet/mi.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 2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
31*7c478bd9Sstevel@tonic-gate #include <inet/common.h>	/* for various inet/mi.h and inet/nd.h needs */
32*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
36*7c478bd9Sstevel@tonic-gate #include <inet/nd.h>
37*7c478bd9Sstevel@tonic-gate #include <inet/mi.h>
38*7c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
39*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/timod.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #define	ISDIGIT(ch)	((ch) >= '0' && (ch) <= '9')
52*7c478bd9Sstevel@tonic-gate #define	ISUPPER(ch)	((ch) >= 'A' && (ch) <= 'Z')
53*7c478bd9Sstevel@tonic-gate #define	tolower(ch)	('a' + ((ch) - 'A'))
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define	MI_IS_TRANSPARENT(mp)	(mp->b_cont && \
56*7c478bd9Sstevel@tonic-gate 	(mp->b_cont->b_rptr != mp->b_cont->b_wptr))
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below),
60*7c478bd9Sstevel@tonic-gate  * the size of the requested allocation is increased by one word.  This extra
61*7c478bd9Sstevel@tonic-gate  * word is used to store the size of the object being allocated, and is located
62*7c478bd9Sstevel@tonic-gate  * at the beginning of the allocated block.  The pointer returned to the caller
63*7c478bd9Sstevel@tonic-gate  * is a pointer to the *second* word in the newly-allocated block.  The IP
64*7c478bd9Sstevel@tonic-gate  * module of mdb is aware of this, and will need to be changed if this
65*7c478bd9Sstevel@tonic-gate  * allocation strategy is changed.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate typedef	struct stroptions *STROPTP;
69*7c478bd9Sstevel@tonic-gate typedef union T_primitives *TPRIMP;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /* Timer block states. */
72*7c478bd9Sstevel@tonic-gate #define	TB_RUNNING	1
73*7c478bd9Sstevel@tonic-gate #define	TB_IDLE		2
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate  * Could not stop/free before putq
76*7c478bd9Sstevel@tonic-gate  */
77*7c478bd9Sstevel@tonic-gate #define	TB_RESCHED	3	/* mtb_time_left contains tick count */
78*7c478bd9Sstevel@tonic-gate #define	TB_CANCELLED	4
79*7c478bd9Sstevel@tonic-gate #define	TB_TO_BE_FREED	5
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate typedef struct mtb_s {
82*7c478bd9Sstevel@tonic-gate 	int		mtb_state;
83*7c478bd9Sstevel@tonic-gate 	timeout_id_t	mtb_tid;
84*7c478bd9Sstevel@tonic-gate 	queue_t		*mtb_q;
85*7c478bd9Sstevel@tonic-gate 	MBLKP		mtb_mp;
86*7c478bd9Sstevel@tonic-gate 	clock_t		mtb_time_left;
87*7c478bd9Sstevel@tonic-gate } MTB, *MTBP;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static int mi_timer_fire(MTBP);
90*7c478bd9Sstevel@tonic-gate static int mi_iprintf(char *, va_list, pfi_t, char *);
91*7c478bd9Sstevel@tonic-gate static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t);
92*7c478bd9Sstevel@tonic-gate static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t);
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
95*7c478bd9Sstevel@tonic-gate void *
96*7c478bd9Sstevel@tonic-gate mi_alloc(size_t size, uint_t pri)
97*7c478bd9Sstevel@tonic-gate {
98*7c478bd9Sstevel@tonic-gate 	size_t *ptr;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	size += sizeof (size);
101*7c478bd9Sstevel@tonic-gate 	if (ptr = kmem_alloc(size, KM_NOSLEEP)) {
102*7c478bd9Sstevel@tonic-gate 		*ptr = size;
103*7c478bd9Sstevel@tonic-gate 		return (ptr + 1);
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 	return (NULL);
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
109*7c478bd9Sstevel@tonic-gate void *
110*7c478bd9Sstevel@tonic-gate mi_alloc_sleep(size_t size, uint_t pri)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	size_t *ptr;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	size += sizeof (size);
115*7c478bd9Sstevel@tonic-gate 	ptr = kmem_alloc(size, KM_SLEEP);
116*7c478bd9Sstevel@tonic-gate 	*ptr = size;
117*7c478bd9Sstevel@tonic-gate 	return (ptr + 1);
118*7c478bd9Sstevel@tonic-gate }
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate int
121*7c478bd9Sstevel@tonic-gate mi_close_comm(void **mi_headp, queue_t *q)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	IDP ptr;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	ptr = q->q_ptr;
126*7c478bd9Sstevel@tonic-gate 	mi_close_unlink(mi_headp, ptr);
127*7c478bd9Sstevel@tonic-gate 	mi_close_free(ptr);
128*7c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
129*7c478bd9Sstevel@tonic-gate 	return (0);
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate void
133*7c478bd9Sstevel@tonic-gate mi_close_unlink(void **mi_headp, IDP ptr)
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
136*7c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
137*7c478bd9Sstevel@tonic-gate 	dev_t		dev;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
140*7c478bd9Sstevel@tonic-gate 	if (!mi_o)
141*7c478bd9Sstevel@tonic-gate 		return;
142*7c478bd9Sstevel@tonic-gate 	mi_o--;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (mi_o->mi_o_next == NULL) {
145*7c478bd9Sstevel@tonic-gate 		/* Not in list */
146*7c478bd9Sstevel@tonic-gate 		ASSERT(mi_o->mi_o_prev == NULL);
147*7c478bd9Sstevel@tonic-gate 		return;
148*7c478bd9Sstevel@tonic-gate 	}
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	/* Free minor number */
151*7c478bd9Sstevel@tonic-gate 	dev = mi_o->mi_o_dev;
152*7c478bd9Sstevel@tonic-gate 	if ((dev != OPENFAIL) && (dev != 0) && (dev <= MAXMIN))
153*7c478bd9Sstevel@tonic-gate 		inet_minor_free(mi_head->mh_arena, dev);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/* Unlink from list */
156*7c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next != NULL);
157*7c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_prev != NULL);
158*7c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next->mi_o_prev == mi_o);
159*7c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_prev->mi_o_next == mi_o);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next->mi_o_prev = mi_o->mi_o_prev;
162*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_prev->mi_o_next = mi_o->mi_o_next;
163*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next = mi_o->mi_o_prev = NULL;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_dev = (dev_t)OPENFAIL;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/* If list now empty free the list head */
168*7c478bd9Sstevel@tonic-gate 	if (mi_head->mh_o.mi_o_next == &mi_head->mh_o) {
169*7c478bd9Sstevel@tonic-gate 		ASSERT(mi_head->mh_o.mi_o_prev == &mi_head->mh_o);
170*7c478bd9Sstevel@tonic-gate 		if (mi_head->mh_arena != NULL)
171*7c478bd9Sstevel@tonic-gate 			inet_minor_destroy(mi_head->mh_arena);
172*7c478bd9Sstevel@tonic-gate 		mi_free((IDP)mi_head);
173*7c478bd9Sstevel@tonic-gate 		*mi_headp = NULL;
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate void
178*7c478bd9Sstevel@tonic-gate mi_close_free(IDP ptr)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
183*7c478bd9Sstevel@tonic-gate 	if (!mi_o)
184*7c478bd9Sstevel@tonic-gate 		return;
185*7c478bd9Sstevel@tonic-gate 	mi_o--;
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next == NULL && mi_o->mi_o_prev == NULL);
188*7c478bd9Sstevel@tonic-gate 	mi_free((IDP)mi_o);
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /*
192*7c478bd9Sstevel@tonic-gate  * mi_copyin - takes care of transparent or non-transparent ioctl for the
193*7c478bd9Sstevel@tonic-gate  * calling function so that they have to deal with just M_IOCDATA type
194*7c478bd9Sstevel@tonic-gate  * and not worry about M_COPYIN.
195*7c478bd9Sstevel@tonic-gate  *
196*7c478bd9Sstevel@tonic-gate  * mi_copyin checks to see if the ioctl is transparent or non transparent.
197*7c478bd9Sstevel@tonic-gate  * In case of a non_transparent ioctl, it packs the data into a M_IOCDATA
198*7c478bd9Sstevel@tonic-gate  * message and puts it back onto the current queue for further processing.
199*7c478bd9Sstevel@tonic-gate  * In case of transparent ioctl, it sends a M_COPYIN message up to the
200*7c478bd9Sstevel@tonic-gate  * streamhead so that a M_IOCDATA with the information comes back down.
201*7c478bd9Sstevel@tonic-gate  */
202*7c478bd9Sstevel@tonic-gate void
203*7c478bd9Sstevel@tonic-gate mi_copyin(queue_t *q, MBLKP mp, char *uaddr, size_t len)
204*7c478bd9Sstevel@tonic-gate {
205*7c478bd9Sstevel@tonic-gate 	struct 	iocblk *iocp = (struct iocblk *)mp->b_rptr;
206*7c478bd9Sstevel@tonic-gate 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
207*7c478bd9Sstevel@tonic-gate 	struct 	copyresp *cp = (struct copyresp *)mp->b_rptr;
208*7c478bd9Sstevel@tonic-gate 	int    	err;
209*7c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_IOCTL && !uaddr);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	/* A transparent ioctl. Send a M_COPYIN message to the streamhead. */
214*7c478bd9Sstevel@tonic-gate 	if (iocp->ioc_count == TRANSPARENT) {
215*7c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 1;
216*7c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_IN;
217*7c478bd9Sstevel@tonic-gate 		cq->cq_private = mp->b_cont;
218*7c478bd9Sstevel@tonic-gate 		cq->cq_size = len;
219*7c478bd9Sstevel@tonic-gate 		cq->cq_flag = 0;
220*7c478bd9Sstevel@tonic-gate 		bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
221*7c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
222*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_COPYIN;
223*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
224*7c478bd9Sstevel@tonic-gate 		return;
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	/*
228*7c478bd9Sstevel@tonic-gate 	 * A non-transparent ioctl. Need to convert into M_IOCDATA message.
229*7c478bd9Sstevel@tonic-gate 	 *
230*7c478bd9Sstevel@tonic-gate 	 * We allocate a 0 byte message block and put its address in
231*7c478bd9Sstevel@tonic-gate 	 * cp_private. It also makes the b_prev field = 1 and b_next
232*7c478bd9Sstevel@tonic-gate 	 * field = MI_COPY_IN for this 0 byte block. This is done to
233*7c478bd9Sstevel@tonic-gate 	 * maintain compatibility with old code in mi_copy_state
234*7c478bd9Sstevel@tonic-gate 	 * (which removes the empty block).
235*7c478bd9Sstevel@tonic-gate 	 */
236*7c478bd9Sstevel@tonic-gate 	err = miocpullup(mp, len);
237*7c478bd9Sstevel@tonic-gate 	if (err != 0)
238*7c478bd9Sstevel@tonic-gate 		goto err_ret;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	mp1 = allocb(0, BPRI_MED);
241*7c478bd9Sstevel@tonic-gate 	if (mp1 == NULL) {
242*7c478bd9Sstevel@tonic-gate 		err = ENOMEM;
243*7c478bd9Sstevel@tonic-gate 		goto err_ret;
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	/*
247*7c478bd9Sstevel@tonic-gate 	 * Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so
248*7c478bd9Sstevel@tonic-gate 	 * that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros.
249*7c478bd9Sstevel@tonic-gate 	 */
250*7c478bd9Sstevel@tonic-gate 	mp1->b_cont = mp->b_cont;
251*7c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1;
252*7c478bd9Sstevel@tonic-gate 	MI_COPY_COUNT(mp) = 1;
253*7c478bd9Sstevel@tonic-gate 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
254*7c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1->b_cont;
255*7c478bd9Sstevel@tonic-gate 	mp1->b_cont = NULL;
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	/*
258*7c478bd9Sstevel@tonic-gate 	 * Leave a pointer to the 0 byte block in cp_private field for
259*7c478bd9Sstevel@tonic-gate 	 * future use by the mi_copy_* routines.
260*7c478bd9Sstevel@tonic-gate 	 */
261*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCDATA;
262*7c478bd9Sstevel@tonic-gate 	cp->cp_private = mp1;
263*7c478bd9Sstevel@tonic-gate 	cp->cp_rval = NULL;
264*7c478bd9Sstevel@tonic-gate 	put(q, mp);
265*7c478bd9Sstevel@tonic-gate 	return;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate err_ret:
268*7c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
269*7c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
270*7c478bd9Sstevel@tonic-gate 	if (mp->b_cont) {
271*7c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
272*7c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
273*7c478bd9Sstevel@tonic-gate 	}
274*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
275*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate /*
279*7c478bd9Sstevel@tonic-gate  * Allows transparent IOCTLs to have multiple copyins.  This is needed
280*7c478bd9Sstevel@tonic-gate  * for some variable-length structures, where the total size is only known
281*7c478bd9Sstevel@tonic-gate  * after the first part is copied in. Rather than setting MI_COPY_COUNT to
282*7c478bd9Sstevel@tonic-gate  * 1, as in mi_coypin(), it is simply incremented here.  This value can
283*7c478bd9Sstevel@tonic-gate  * then be checked in the returned IOCBLK.
284*7c478bd9Sstevel@tonic-gate  *
285*7c478bd9Sstevel@tonic-gate  * As this deals with copyins that follow the initial copyin, the byte
286*7c478bd9Sstevel@tonic-gate  * offset into the user buffer from which copying should begin must be
287*7c478bd9Sstevel@tonic-gate  * passed in in the offset parameter.
288*7c478bd9Sstevel@tonic-gate  *
289*7c478bd9Sstevel@tonic-gate  * Unlike mi_coypin(), this function expects to be passed an mblk chain
290*7c478bd9Sstevel@tonic-gate  * headed by an M_IOCBLK, as that's the chain that will be in use for
291*7c478bd9Sstevel@tonic-gate  * copies after the first one (copies where n != 1).
292*7c478bd9Sstevel@tonic-gate  */
293*7c478bd9Sstevel@tonic-gate void
294*7c478bd9Sstevel@tonic-gate mi_copyin_n(queue_t *q, MBLKP mp, size_t offset, size_t len)
295*7c478bd9Sstevel@tonic-gate {
296*7c478bd9Sstevel@tonic-gate 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_IOCDATA);
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	MI_COPY_COUNT(mp)++;
301*7c478bd9Sstevel@tonic-gate 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
302*7c478bd9Sstevel@tonic-gate 	cq->cq_private = mp->b_cont;
303*7c478bd9Sstevel@tonic-gate 	cq->cq_size = len;
304*7c478bd9Sstevel@tonic-gate 	cq->cq_flag = 0;
305*7c478bd9Sstevel@tonic-gate 	bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
306*7c478bd9Sstevel@tonic-gate 	cq->cq_addr += offset;
307*7c478bd9Sstevel@tonic-gate 	mp->b_cont = NULL;
308*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_COPYIN;
309*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate void
313*7c478bd9Sstevel@tonic-gate mi_copyout(queue_t *q, MBLKP mp)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
316*7c478bd9Sstevel@tonic-gate 	struct copyreq *cq = (struct copyreq *)iocp;
317*7c478bd9Sstevel@tonic-gate 	struct copyresp *cp = (struct copyresp *)cq;
318*7c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
319*7c478bd9Sstevel@tonic-gate 	MBLKP	mp2;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_IOCDATA || !mp->b_cont) {
322*7c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, EPROTO);
323*7c478bd9Sstevel@tonic-gate 		return;
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 	/* Check completion of previous copyout operation. */
326*7c478bd9Sstevel@tonic-gate 	mp1 = mp->b_cont;
327*7c478bd9Sstevel@tonic-gate 	if ((int)(uintptr_t)cp->cp_rval || !mp1->b_cont) {
328*7c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
329*7c478bd9Sstevel@tonic-gate 		return;
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 	if (!mp1->b_cont->b_cont && !MI_IS_TRANSPARENT(mp)) {
332*7c478bd9Sstevel@tonic-gate 		mp1->b_next = NULL;
333*7c478bd9Sstevel@tonic-gate 		mp1->b_prev = NULL;
334*7c478bd9Sstevel@tonic-gate 		mp->b_cont = mp1->b_cont;
335*7c478bd9Sstevel@tonic-gate 		freeb(mp1);
336*7c478bd9Sstevel@tonic-gate 		mp1 = mp->b_cont;
337*7c478bd9Sstevel@tonic-gate 		mp1->b_next = NULL;
338*7c478bd9Sstevel@tonic-gate 		mp1->b_prev = NULL;
339*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = mp1->b_wptr - mp1->b_rptr;
340*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = 0;
341*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
342*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
343*7c478bd9Sstevel@tonic-gate 		return;
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate 	if (MI_COPY_DIRECTION(mp) == MI_COPY_IN) {
346*7c478bd9Sstevel@tonic-gate 		/* Set up for first copyout. */
347*7c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
348*7c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 1;
349*7c478bd9Sstevel@tonic-gate 	} else {
350*7c478bd9Sstevel@tonic-gate 		++MI_COPY_COUNT(mp);
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate 	cq->cq_private = mp1;
353*7c478bd9Sstevel@tonic-gate 	/* Find message preceding last. */
354*7c478bd9Sstevel@tonic-gate 	for (mp2 = mp1; mp2->b_cont->b_cont; mp2 = mp2->b_cont)
355*7c478bd9Sstevel@tonic-gate 		;
356*7c478bd9Sstevel@tonic-gate 	if (mp2 == mp1)
357*7c478bd9Sstevel@tonic-gate 		bcopy((char *)mp1->b_rptr, (char *)&cq->cq_addr,
358*7c478bd9Sstevel@tonic-gate 		    sizeof (cq->cq_addr));
359*7c478bd9Sstevel@tonic-gate 	else
360*7c478bd9Sstevel@tonic-gate 		cq->cq_addr = (char *)mp2->b_cont->b_next;
361*7c478bd9Sstevel@tonic-gate 	mp1 = mp2->b_cont;
362*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_COPYOUT;
363*7c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1;
364*7c478bd9Sstevel@tonic-gate 	mp2->b_cont = NULL;
365*7c478bd9Sstevel@tonic-gate 	mp1->b_next = NULL;
366*7c478bd9Sstevel@tonic-gate 	cq->cq_size = mp1->b_wptr - mp1->b_rptr;
367*7c478bd9Sstevel@tonic-gate 	cq->cq_flag = 0;
368*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
369*7c478bd9Sstevel@tonic-gate }
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate MBLKP
372*7c478bd9Sstevel@tonic-gate mi_copyout_alloc(queue_t *q, MBLKP mp, char *uaddr, size_t len,
373*7c478bd9Sstevel@tonic-gate     boolean_t free_on_error)
374*7c478bd9Sstevel@tonic-gate {
375*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
376*7c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type == M_IOCTL) {
379*7c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
380*7c478bd9Sstevel@tonic-gate 			mp1 = allocb(0, BPRI_MED);
381*7c478bd9Sstevel@tonic-gate 			if (mp1 == NULL) {
382*7c478bd9Sstevel@tonic-gate 				if (free_on_error) {
383*7c478bd9Sstevel@tonic-gate 					iocp->ioc_error = ENOMEM;
384*7c478bd9Sstevel@tonic-gate 					iocp->ioc_count = 0;
385*7c478bd9Sstevel@tonic-gate 					freemsg(mp->b_cont);
386*7c478bd9Sstevel@tonic-gate 					mp->b_cont = NULL;
387*7c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_IOCACK;
388*7c478bd9Sstevel@tonic-gate 					qreply(q, mp);
389*7c478bd9Sstevel@tonic-gate 				}
390*7c478bd9Sstevel@tonic-gate 				return (NULL);
391*7c478bd9Sstevel@tonic-gate 			}
392*7c478bd9Sstevel@tonic-gate 			mp1->b_cont = mp->b_cont;
393*7c478bd9Sstevel@tonic-gate 			mp->b_cont = mp1;
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 0;
396*7c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
397*7c478bd9Sstevel@tonic-gate 		/* Make sure it looks clean to mi_copyout. */
398*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCDATA;
399*7c478bd9Sstevel@tonic-gate 		((struct copyresp *)iocp)->cp_rval = NULL;
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 	mp1 = allocb(len, BPRI_MED);
402*7c478bd9Sstevel@tonic-gate 	if (mp1 == NULL) {
403*7c478bd9Sstevel@tonic-gate 		if (free_on_error)
404*7c478bd9Sstevel@tonic-gate 			mi_copy_done(q, mp, ENOMEM);
405*7c478bd9Sstevel@tonic-gate 		return (NULL);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 	linkb(mp, mp1);
408*7c478bd9Sstevel@tonic-gate 	mp1->b_next = (MBLKP)uaddr;
409*7c478bd9Sstevel@tonic-gate 	return (mp1);
410*7c478bd9Sstevel@tonic-gate }
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate void
413*7c478bd9Sstevel@tonic-gate mi_copy_done(queue_t *q, MBLKP mp, int err)
414*7c478bd9Sstevel@tonic-gate {
415*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
416*7c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	if (!mp)
419*7c478bd9Sstevel@tonic-gate 		return;
420*7c478bd9Sstevel@tonic-gate 	if (!q || (mp->b_wptr - mp->b_rptr) < sizeof (struct iocblk)) {
421*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
422*7c478bd9Sstevel@tonic-gate 		return;
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
425*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
426*7c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
429*7c478bd9Sstevel@tonic-gate 	if ((mp1 = mp->b_cont) != NULL) {
430*7c478bd9Sstevel@tonic-gate 		for (; mp1; mp1 = mp1->b_cont) {
431*7c478bd9Sstevel@tonic-gate 			mp1->b_prev = NULL;
432*7c478bd9Sstevel@tonic-gate 			mp1->b_next = NULL;
433*7c478bd9Sstevel@tonic-gate 		}
434*7c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
435*7c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate int
441*7c478bd9Sstevel@tonic-gate mi_copy_state(queue_t *q, MBLKP mp, MBLKP *mpp)
442*7c478bd9Sstevel@tonic-gate {
443*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
444*7c478bd9Sstevel@tonic-gate 	struct copyresp *cp = (struct copyresp *)iocp;
445*7c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	mp1 = mp->b_cont;
448*7c478bd9Sstevel@tonic-gate 	mp->b_cont = cp->cp_private;
449*7c478bd9Sstevel@tonic-gate 	if (mp1) {
450*7c478bd9Sstevel@tonic-gate 		if (mp1->b_cont && !pullupmsg(mp1, -1)) {
451*7c478bd9Sstevel@tonic-gate 			mi_copy_done(q, mp, ENOMEM);
452*7c478bd9Sstevel@tonic-gate 			return (-1);
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		linkb(mp->b_cont, mp1);
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 	if ((int)(uintptr_t)cp->cp_rval) {
457*7c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
458*7c478bd9Sstevel@tonic-gate 		return (-1);
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 	if (mpp && MI_COPY_DIRECTION(mp) == MI_COPY_IN)
461*7c478bd9Sstevel@tonic-gate 		*mpp = mp1;
462*7c478bd9Sstevel@tonic-gate 	return (MI_COPY_STATE(mp));
463*7c478bd9Sstevel@tonic-gate }
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate void
466*7c478bd9Sstevel@tonic-gate mi_free(void *ptr)
467*7c478bd9Sstevel@tonic-gate {
468*7c478bd9Sstevel@tonic-gate 	size_t	size;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	if (!ptr)
471*7c478bd9Sstevel@tonic-gate 		return;
472*7c478bd9Sstevel@tonic-gate 	if ((size = ((size_t *)ptr)[-1]) <= 0)
473*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "mi_free");
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	kmem_free((void *) ((size_t *)ptr - 1), size);
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate static int
479*7c478bd9Sstevel@tonic-gate mi_iprintf(char *fmt, va_list ap, pfi_t putc_func, char *cookie)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	int	base;
482*7c478bd9Sstevel@tonic-gate 	char	buf[(sizeof (long) * 3) + 1];
483*7c478bd9Sstevel@tonic-gate 	static char	hex_val[] = "0123456789abcdef";
484*7c478bd9Sstevel@tonic-gate 	int	ch;
485*7c478bd9Sstevel@tonic-gate 	int	count;
486*7c478bd9Sstevel@tonic-gate 	char	*cp1;
487*7c478bd9Sstevel@tonic-gate 	int	digits;
488*7c478bd9Sstevel@tonic-gate 	char	*fcp;
489*7c478bd9Sstevel@tonic-gate 	boolean_t	is_long;
490*7c478bd9Sstevel@tonic-gate 	ulong_t	uval;
491*7c478bd9Sstevel@tonic-gate 	long	val;
492*7c478bd9Sstevel@tonic-gate 	boolean_t	zero_filled;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	if (!fmt)
495*7c478bd9Sstevel@tonic-gate 		return (-1);
496*7c478bd9Sstevel@tonic-gate 	count = 0;
497*7c478bd9Sstevel@tonic-gate 	while (*fmt) {
498*7c478bd9Sstevel@tonic-gate 		if (*fmt != '%' || *++fmt == '%') {
499*7c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, *fmt++);
500*7c478bd9Sstevel@tonic-gate 			continue;
501*7c478bd9Sstevel@tonic-gate 		}
502*7c478bd9Sstevel@tonic-gate 		if (*fmt == '0') {
503*7c478bd9Sstevel@tonic-gate 			zero_filled = B_TRUE;
504*7c478bd9Sstevel@tonic-gate 			fmt++;
505*7c478bd9Sstevel@tonic-gate 			if (!*fmt)
506*7c478bd9Sstevel@tonic-gate 				break;
507*7c478bd9Sstevel@tonic-gate 		} else
508*7c478bd9Sstevel@tonic-gate 			zero_filled = B_FALSE;
509*7c478bd9Sstevel@tonic-gate 		base = 0;
510*7c478bd9Sstevel@tonic-gate 		for (digits = 0; ISDIGIT(*fmt); fmt++) {
511*7c478bd9Sstevel@tonic-gate 			digits *= 10;
512*7c478bd9Sstevel@tonic-gate 			digits += (*fmt - '0');
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 		if (!*fmt)
515*7c478bd9Sstevel@tonic-gate 			break;
516*7c478bd9Sstevel@tonic-gate 		is_long = B_FALSE;
517*7c478bd9Sstevel@tonic-gate 		if (*fmt == 'l') {
518*7c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
519*7c478bd9Sstevel@tonic-gate 			fmt++;
520*7c478bd9Sstevel@tonic-gate 		}
521*7c478bd9Sstevel@tonic-gate 		if (!*fmt)
522*7c478bd9Sstevel@tonic-gate 			break;
523*7c478bd9Sstevel@tonic-gate 		ch = *fmt++;
524*7c478bd9Sstevel@tonic-gate 		if (ISUPPER(ch)) {
525*7c478bd9Sstevel@tonic-gate 			ch = tolower(ch);
526*7c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		switch (ch) {
529*7c478bd9Sstevel@tonic-gate 		case 'c':
530*7c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, va_arg(ap, int *));
531*7c478bd9Sstevel@tonic-gate 			continue;
532*7c478bd9Sstevel@tonic-gate 		case 'd':
533*7c478bd9Sstevel@tonic-gate 			base = 10;
534*7c478bd9Sstevel@tonic-gate 			break;
535*7c478bd9Sstevel@tonic-gate 		case 'm':	/* Print out memory, 2 hex chars per byte */
536*7c478bd9Sstevel@tonic-gate 			if (is_long)
537*7c478bd9Sstevel@tonic-gate 				fcp = va_arg(ap, char *);
538*7c478bd9Sstevel@tonic-gate 			else {
539*7c478bd9Sstevel@tonic-gate 				if ((cp1 = va_arg(ap, char *)) != NULL)
540*7c478bd9Sstevel@tonic-gate 					fcp = (char *)cp1;
541*7c478bd9Sstevel@tonic-gate 				else
542*7c478bd9Sstevel@tonic-gate 					fcp = NULL;
543*7c478bd9Sstevel@tonic-gate 			}
544*7c478bd9Sstevel@tonic-gate 			if (!fcp) {
545*7c478bd9Sstevel@tonic-gate 				for (fcp = (char *)"(NULL)"; *fcp; fcp++)
546*7c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie, *fcp);
547*7c478bd9Sstevel@tonic-gate 			} else {
548*7c478bd9Sstevel@tonic-gate 				while (digits--) {
549*7c478bd9Sstevel@tonic-gate 					int u1 = *fcp++ & 0xFF;
550*7c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie,
551*7c478bd9Sstevel@tonic-gate 					    hex_val[(u1>>4)& 0xF]);
552*7c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie,
553*7c478bd9Sstevel@tonic-gate 					    hex_val[u1& 0xF]);
554*7c478bd9Sstevel@tonic-gate 				}
555*7c478bd9Sstevel@tonic-gate 			}
556*7c478bd9Sstevel@tonic-gate 			continue;
557*7c478bd9Sstevel@tonic-gate 		case 'o':
558*7c478bd9Sstevel@tonic-gate 			base = 8;
559*7c478bd9Sstevel@tonic-gate 			break;
560*7c478bd9Sstevel@tonic-gate 		case 'p':
561*7c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
562*7c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
563*7c478bd9Sstevel@tonic-gate 		case 'x':
564*7c478bd9Sstevel@tonic-gate 			base = 16;
565*7c478bd9Sstevel@tonic-gate 			break;
566*7c478bd9Sstevel@tonic-gate 		case 's':
567*7c478bd9Sstevel@tonic-gate 			if (is_long)
568*7c478bd9Sstevel@tonic-gate 				fcp = va_arg(ap, char *);
569*7c478bd9Sstevel@tonic-gate 			else {
570*7c478bd9Sstevel@tonic-gate 				if ((cp1 = va_arg(ap, char *)) != NULL)
571*7c478bd9Sstevel@tonic-gate 					fcp = (char *)cp1;
572*7c478bd9Sstevel@tonic-gate 				else
573*7c478bd9Sstevel@tonic-gate 					fcp = NULL;
574*7c478bd9Sstevel@tonic-gate 			}
575*7c478bd9Sstevel@tonic-gate 			if (!fcp)
576*7c478bd9Sstevel@tonic-gate 				fcp = (char *)"(NULL)";
577*7c478bd9Sstevel@tonic-gate 			while (*fcp) {
578*7c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, *fcp++);
579*7c478bd9Sstevel@tonic-gate 				if (digits && --digits == 0)
580*7c478bd9Sstevel@tonic-gate 					break;
581*7c478bd9Sstevel@tonic-gate 			}
582*7c478bd9Sstevel@tonic-gate 			while (digits > 0) {
583*7c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, ' ');
584*7c478bd9Sstevel@tonic-gate 				digits--;
585*7c478bd9Sstevel@tonic-gate 			}
586*7c478bd9Sstevel@tonic-gate 			continue;
587*7c478bd9Sstevel@tonic-gate 		case 'u':
588*7c478bd9Sstevel@tonic-gate 			base = 10;
589*7c478bd9Sstevel@tonic-gate 			break;
590*7c478bd9Sstevel@tonic-gate 		default:
591*7c478bd9Sstevel@tonic-gate 			return (count);
592*7c478bd9Sstevel@tonic-gate 		}
593*7c478bd9Sstevel@tonic-gate 		if (is_long)
594*7c478bd9Sstevel@tonic-gate 			val = va_arg(ap, long);
595*7c478bd9Sstevel@tonic-gate 		else
596*7c478bd9Sstevel@tonic-gate 			val = va_arg(ap, int);
597*7c478bd9Sstevel@tonic-gate 		if (base == 10 && ch != 'u') {
598*7c478bd9Sstevel@tonic-gate 			if (val < 0) {
599*7c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, '-');
600*7c478bd9Sstevel@tonic-gate 				val = -val;
601*7c478bd9Sstevel@tonic-gate 			}
602*7c478bd9Sstevel@tonic-gate 			uval = val;
603*7c478bd9Sstevel@tonic-gate 		} else {
604*7c478bd9Sstevel@tonic-gate 			if (is_long)
605*7c478bd9Sstevel@tonic-gate 				uval = val;
606*7c478bd9Sstevel@tonic-gate 			else
607*7c478bd9Sstevel@tonic-gate 				uval = (uint_t)val;
608*7c478bd9Sstevel@tonic-gate 		}
609*7c478bd9Sstevel@tonic-gate 		/* Hand overload/restore the register variable 'fmt' */
610*7c478bd9Sstevel@tonic-gate 		cp1 = fmt;
611*7c478bd9Sstevel@tonic-gate 		fmt = A_END(buf);
612*7c478bd9Sstevel@tonic-gate 		*--fmt = '\0';
613*7c478bd9Sstevel@tonic-gate 		do {
614*7c478bd9Sstevel@tonic-gate 			if (fmt > buf)
615*7c478bd9Sstevel@tonic-gate 				*--fmt = hex_val[uval % base];
616*7c478bd9Sstevel@tonic-gate 			if (digits && --digits == 0)
617*7c478bd9Sstevel@tonic-gate 				break;
618*7c478bd9Sstevel@tonic-gate 		} while (uval /= base);
619*7c478bd9Sstevel@tonic-gate 		if (zero_filled) {
620*7c478bd9Sstevel@tonic-gate 			while (digits > 0 && fmt > buf) {
621*7c478bd9Sstevel@tonic-gate 				*--fmt = '0';
622*7c478bd9Sstevel@tonic-gate 				digits--;
623*7c478bd9Sstevel@tonic-gate 			}
624*7c478bd9Sstevel@tonic-gate 		}
625*7c478bd9Sstevel@tonic-gate 		while (*fmt)
626*7c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, *fmt++);
627*7c478bd9Sstevel@tonic-gate 		fmt = cp1;
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 	return (count);
630*7c478bd9Sstevel@tonic-gate }
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
633*7c478bd9Sstevel@tonic-gate int
634*7c478bd9Sstevel@tonic-gate mi_mpprintf(MBLKP mp, char *fmt, ...)
635*7c478bd9Sstevel@tonic-gate {
636*7c478bd9Sstevel@tonic-gate 	va_list	ap;
637*7c478bd9Sstevel@tonic-gate 	int	count = -1;
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
640*7c478bd9Sstevel@tonic-gate 	if (mp) {
641*7c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
642*7c478bd9Sstevel@tonic-gate 		    (char *)mp);
643*7c478bd9Sstevel@tonic-gate 		if (count != -1)
644*7c478bd9Sstevel@tonic-gate 			(void) mi_mpprintf_putc((char *)mp, '\0');
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 	va_end(ap);
647*7c478bd9Sstevel@tonic-gate 	return (count);
648*7c478bd9Sstevel@tonic-gate }
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
651*7c478bd9Sstevel@tonic-gate int
652*7c478bd9Sstevel@tonic-gate mi_mpprintf_nr(MBLKP mp, char *fmt, ...)
653*7c478bd9Sstevel@tonic-gate {
654*7c478bd9Sstevel@tonic-gate 	va_list	ap;
655*7c478bd9Sstevel@tonic-gate 	int	count = -1;
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
658*7c478bd9Sstevel@tonic-gate 	if (mp) {
659*7c478bd9Sstevel@tonic-gate 		(void) adjmsg(mp, -1);
660*7c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
661*7c478bd9Sstevel@tonic-gate 		    (char *)mp);
662*7c478bd9Sstevel@tonic-gate 		if (count != -1)
663*7c478bd9Sstevel@tonic-gate 			(void) mi_mpprintf_putc((char *)mp, '\0');
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 	va_end(ap);
666*7c478bd9Sstevel@tonic-gate 	return (count);
667*7c478bd9Sstevel@tonic-gate }
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate int
670*7c478bd9Sstevel@tonic-gate mi_mpprintf_putc(char *cookie, int ch)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	MBLKP	mp = (MBLKP)cookie;
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	while (mp->b_cont)
675*7c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
676*7c478bd9Sstevel@tonic-gate 	if (mp->b_wptr >= mp->b_datap->db_lim) {
677*7c478bd9Sstevel@tonic-gate 		mp->b_cont = allocb(1024, BPRI_HI);
678*7c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
679*7c478bd9Sstevel@tonic-gate 		if (!mp)
680*7c478bd9Sstevel@tonic-gate 			return (0);
681*7c478bd9Sstevel@tonic-gate 	}
682*7c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = (unsigned char)ch;
683*7c478bd9Sstevel@tonic-gate 	return (1);
684*7c478bd9Sstevel@tonic-gate }
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate IDP
687*7c478bd9Sstevel@tonic-gate mi_first_ptr(void **mi_headp)
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
690*7c478bd9Sstevel@tonic-gate 	MI_OP	mi_op;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	mi_op = mi_head->mh_o.mi_o_next;
693*7c478bd9Sstevel@tonic-gate 	if (mi_op && mi_op != &mi_head->mh_o)
694*7c478bd9Sstevel@tonic-gate 		return ((IDP)&mi_op[1]);
695*7c478bd9Sstevel@tonic-gate 	return (NULL);
696*7c478bd9Sstevel@tonic-gate }
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate /*
699*7c478bd9Sstevel@tonic-gate  * Clients can choose to have both module instances and device instances
700*7c478bd9Sstevel@tonic-gate  * in the same list. Return the first device instance in the list.
701*7c478bd9Sstevel@tonic-gate  */
702*7c478bd9Sstevel@tonic-gate IDP
703*7c478bd9Sstevel@tonic-gate mi_first_dev_ptr(void **mi_headp)
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
706*7c478bd9Sstevel@tonic-gate 	MI_OP	mi_op;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	mi_op = mi_head->mh_o.mi_o_next;
709*7c478bd9Sstevel@tonic-gate 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
710*7c478bd9Sstevel@tonic-gate 		if (mi_op->mi_o_isdev)
711*7c478bd9Sstevel@tonic-gate 			return ((IDP)&mi_op[1]);
712*7c478bd9Sstevel@tonic-gate 		mi_op = mi_op->mi_o_next;
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 	return (NULL);
715*7c478bd9Sstevel@tonic-gate }
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate IDP
718*7c478bd9Sstevel@tonic-gate mi_next_ptr(void **mi_headp, IDP ptr)
719*7c478bd9Sstevel@tonic-gate {
720*7c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
721*7c478bd9Sstevel@tonic-gate 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	if ((mi_op = mi_op->mi_o_next) != NULL && mi_op != &mi_head->mh_o)
724*7c478bd9Sstevel@tonic-gate 		return ((IDP)&mi_op[1]);
725*7c478bd9Sstevel@tonic-gate 	return (NULL);
726*7c478bd9Sstevel@tonic-gate }
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate /*
729*7c478bd9Sstevel@tonic-gate  * Clients can choose to have both module instances and device instances
730*7c478bd9Sstevel@tonic-gate  * in the same list. Return the next device instance in the list.
731*7c478bd9Sstevel@tonic-gate  */
732*7c478bd9Sstevel@tonic-gate IDP
733*7c478bd9Sstevel@tonic-gate mi_next_dev_ptr(void **mi_headp, IDP ptr)
734*7c478bd9Sstevel@tonic-gate {
735*7c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
736*7c478bd9Sstevel@tonic-gate 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	mi_op = mi_op->mi_o_next;
739*7c478bd9Sstevel@tonic-gate 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
740*7c478bd9Sstevel@tonic-gate 		if (mi_op->mi_o_isdev)
741*7c478bd9Sstevel@tonic-gate 			return ((IDP)&mi_op[1]);
742*7c478bd9Sstevel@tonic-gate 		mi_op = mi_op->mi_o_next;
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 	return (NULL);
745*7c478bd9Sstevel@tonic-gate }
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate /*
748*7c478bd9Sstevel@tonic-gate  * Self clone the device
749*7c478bd9Sstevel@tonic-gate  * XXX - should we still support clone device
750*7c478bd9Sstevel@tonic-gate  */
751*7c478bd9Sstevel@tonic-gate /* ARGSUSED4 */
752*7c478bd9Sstevel@tonic-gate int
753*7c478bd9Sstevel@tonic-gate mi_open_comm(void **mi_headp, size_t size, queue_t *q, dev_t *devp,
754*7c478bd9Sstevel@tonic-gate     int flag, int sflag, cred_t *credp)
755*7c478bd9Sstevel@tonic-gate {
756*7c478bd9Sstevel@tonic-gate 	int error;
757*7c478bd9Sstevel@tonic-gate 	IDP ptr;
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
760*7c478bd9Sstevel@tonic-gate 		return (0);
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	ptr = mi_open_alloc_sleep(size);
763*7c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = ptr;
764*7c478bd9Sstevel@tonic-gate 	error = mi_open_link(mi_headp, ptr, devp, flag, sflag, credp);
765*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
766*7c478bd9Sstevel@tonic-gate 		q->q_ptr = WR(q)->q_ptr = NULL;
767*7c478bd9Sstevel@tonic-gate 		mi_close_free(ptr);
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 	return (error);
770*7c478bd9Sstevel@tonic-gate }
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate IDP
773*7c478bd9Sstevel@tonic-gate mi_open_alloc_sleep(size_t size)
774*7c478bd9Sstevel@tonic-gate {
775*7c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	if (size > (UINT_MAX - sizeof (MI_O)))
778*7c478bd9Sstevel@tonic-gate 		return (NULL);
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)mi_zalloc_sleep(size + sizeof (MI_O));
781*7c478bd9Sstevel@tonic-gate 	mi_o++;
782*7c478bd9Sstevel@tonic-gate 	return ((IDP)mi_o);
783*7c478bd9Sstevel@tonic-gate }
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate IDP
786*7c478bd9Sstevel@tonic-gate mi_open_alloc(size_t size)
787*7c478bd9Sstevel@tonic-gate {
788*7c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	if (size > (UINT_MAX - sizeof (MI_O)))
791*7c478bd9Sstevel@tonic-gate 		return (NULL);
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	if ((mi_o = (MI_OP)mi_zalloc(size + sizeof (MI_O))) == NULL)
794*7c478bd9Sstevel@tonic-gate 		return (NULL);
795*7c478bd9Sstevel@tonic-gate 	mi_o++;
796*7c478bd9Sstevel@tonic-gate 	return ((IDP)mi_o);
797*7c478bd9Sstevel@tonic-gate }
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate /*
800*7c478bd9Sstevel@tonic-gate  * MODOPEN means just link in without respect of mi_o_dev.
801*7c478bd9Sstevel@tonic-gate  * A NULL devp can be used to create a detached instance
802*7c478bd9Sstevel@tonic-gate  * Otherwise self-clone the device.
803*7c478bd9Sstevel@tonic-gate  */
804*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
805*7c478bd9Sstevel@tonic-gate int
806*7c478bd9Sstevel@tonic-gate mi_open_link(void **mi_headp, IDP ptr, dev_t *devp, int flag, int sflag,
807*7c478bd9Sstevel@tonic-gate     cred_t *credp)
808*7c478bd9Sstevel@tonic-gate {
809*7c478bd9Sstevel@tonic-gate 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
810*7c478bd9Sstevel@tonic-gate 	MI_OP		insert;
811*7c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
812*7c478bd9Sstevel@tonic-gate 	dev_t		dev;
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	if (mi_head == NULL) {
815*7c478bd9Sstevel@tonic-gate 		char arena_name[50];
816*7c478bd9Sstevel@tonic-gate 		char *head_name;
817*7c478bd9Sstevel@tonic-gate 		ulong_t offset;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 		head_name = kobj_getsymname((uintptr_t)mi_headp, &offset);
820*7c478bd9Sstevel@tonic-gate 		if (head_name != NULL && offset == 0)
821*7c478bd9Sstevel@tonic-gate 			(void) sprintf(arena_name, "%s_", head_name);
822*7c478bd9Sstevel@tonic-gate 		else
823*7c478bd9Sstevel@tonic-gate 			(void) sprintf(arena_name, "0x%p_", (void *)mi_headp);
824*7c478bd9Sstevel@tonic-gate 		(void) sprintf(strchr(arena_name, '_') + 1, "minor");
825*7c478bd9Sstevel@tonic-gate 		mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t));
826*7c478bd9Sstevel@tonic-gate 		*mi_headp = (void *)mi_head;
827*7c478bd9Sstevel@tonic-gate 		/* Setup doubly linked list */
828*7c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_next = &mi_head->mh_o;
829*7c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_prev = &mi_head->mh_o;
830*7c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_dev = 0;	/* For asserts only */
831*7c478bd9Sstevel@tonic-gate 		mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name,
832*7c478bd9Sstevel@tonic-gate 		    INET_MIN_DEV, KM_SLEEP);
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 	ASSERT(ptr != NULL);
835*7c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
836*7c478bd9Sstevel@tonic-gate 	mi_o--;
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	if (sflag == MODOPEN) {
839*7c478bd9Sstevel@tonic-gate 		devp = NULL;
840*7c478bd9Sstevel@tonic-gate 		/*
841*7c478bd9Sstevel@tonic-gate 		 * Set device number to MAXMIN + incrementing number.
842*7c478bd9Sstevel@tonic-gate 		 */
843*7c478bd9Sstevel@tonic-gate 		dev = MAXMIN + ++mi_head->mh_module_dev;
844*7c478bd9Sstevel@tonic-gate 		/* check for wraparound */
845*7c478bd9Sstevel@tonic-gate 		if (dev <= MAXMIN) {
846*7c478bd9Sstevel@tonic-gate 			dev = MAXMIN + 1;
847*7c478bd9Sstevel@tonic-gate 			mi_head->mh_module_dev = 1;
848*7c478bd9Sstevel@tonic-gate 		}
849*7c478bd9Sstevel@tonic-gate 	} else if (devp == NULL) {
850*7c478bd9Sstevel@tonic-gate 		/* Detached open */
851*7c478bd9Sstevel@tonic-gate 		dev = (dev_t)OPENFAIL;
852*7c478bd9Sstevel@tonic-gate 	} else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) {
853*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
854*7c478bd9Sstevel@tonic-gate 	}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_dev = dev;
857*7c478bd9Sstevel@tonic-gate 	insert = (&mi_head->mh_o);
858*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next = insert;
859*7c478bd9Sstevel@tonic-gate 	insert->mi_o_prev->mi_o_next = mi_o;
860*7c478bd9Sstevel@tonic-gate 	mi_o->mi_o_prev = insert->mi_o_prev;
861*7c478bd9Sstevel@tonic-gate 	insert->mi_o_prev = mi_o;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	if (sflag == MODOPEN)
864*7c478bd9Sstevel@tonic-gate 		mi_o->mi_o_isdev = B_FALSE;
865*7c478bd9Sstevel@tonic-gate 	else
866*7c478bd9Sstevel@tonic-gate 		mi_o->mi_o_isdev = B_TRUE;
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	if (devp)
869*7c478bd9Sstevel@tonic-gate 		*devp = makedevice(getemajor(*devp), (minor_t)dev);
870*7c478bd9Sstevel@tonic-gate 	return (0);
871*7c478bd9Sstevel@tonic-gate }
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate uint8_t *
874*7c478bd9Sstevel@tonic-gate mi_offset_param(mblk_t *mp, size_t offset, size_t len)
875*7c478bd9Sstevel@tonic-gate {
876*7c478bd9Sstevel@tonic-gate 	size_t	msg_len;
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	if (!mp)
879*7c478bd9Sstevel@tonic-gate 		return (NULL);
880*7c478bd9Sstevel@tonic-gate 	msg_len = mp->b_wptr - mp->b_rptr;
881*7c478bd9Sstevel@tonic-gate 	if (msg_len == 0 || offset > msg_len || len > msg_len ||
882*7c478bd9Sstevel@tonic-gate 	    (offset + len) > msg_len || len == 0)
883*7c478bd9Sstevel@tonic-gate 		return (NULL);
884*7c478bd9Sstevel@tonic-gate 	return (&mp->b_rptr[offset]);
885*7c478bd9Sstevel@tonic-gate }
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate uint8_t *
888*7c478bd9Sstevel@tonic-gate mi_offset_paramc(mblk_t *mp, size_t offset, size_t len)
889*7c478bd9Sstevel@tonic-gate {
890*7c478bd9Sstevel@tonic-gate 	uint8_t	*param;
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	for (; mp; mp = mp->b_cont) {
893*7c478bd9Sstevel@tonic-gate 		int type = mp->b_datap->db_type;
894*7c478bd9Sstevel@tonic-gate 		if (datamsg(type)) {
895*7c478bd9Sstevel@tonic-gate 			if (param = mi_offset_param(mp, offset, len))
896*7c478bd9Sstevel@tonic-gate 				return (param);
897*7c478bd9Sstevel@tonic-gate 			if (offset < mp->b_wptr - mp->b_rptr)
898*7c478bd9Sstevel@tonic-gate 				break;
899*7c478bd9Sstevel@tonic-gate 			offset -= mp->b_wptr - mp->b_rptr;
900*7c478bd9Sstevel@tonic-gate 		}
901*7c478bd9Sstevel@tonic-gate 	}
902*7c478bd9Sstevel@tonic-gate 	return (NULL);
903*7c478bd9Sstevel@tonic-gate }
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate boolean_t
907*7c478bd9Sstevel@tonic-gate mi_set_sth_hiwat(queue_t *q, size_t size)
908*7c478bd9Sstevel@tonic-gate {
909*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
910*7c478bd9Sstevel@tonic-gate 	STROPTP stropt;
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
913*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
914*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
915*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
916*7c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
917*7c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_HIWAT;
918*7c478bd9Sstevel@tonic-gate 	stropt->so_hiwat = size;
919*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
920*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
921*7c478bd9Sstevel@tonic-gate }
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate boolean_t
924*7c478bd9Sstevel@tonic-gate mi_set_sth_lowat(queue_t *q, size_t size)
925*7c478bd9Sstevel@tonic-gate {
926*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
927*7c478bd9Sstevel@tonic-gate 	STROPTP stropt;
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
930*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
931*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
932*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
933*7c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
934*7c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_LOWAT;
935*7c478bd9Sstevel@tonic-gate 	stropt->so_lowat = size;
936*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
937*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
941*7c478bd9Sstevel@tonic-gate boolean_t
942*7c478bd9Sstevel@tonic-gate mi_set_sth_maxblk(queue_t *q, ssize_t size)
943*7c478bd9Sstevel@tonic-gate {
944*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
945*7c478bd9Sstevel@tonic-gate 	STROPTP stropt;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
948*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
949*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
950*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
951*7c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
952*7c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_MAXBLK;
953*7c478bd9Sstevel@tonic-gate 	stropt->so_maxblk = size;
954*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
955*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate boolean_t
959*7c478bd9Sstevel@tonic-gate mi_set_sth_copyopt(queue_t *q, int copyopt)
960*7c478bd9Sstevel@tonic-gate {
961*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
962*7c478bd9Sstevel@tonic-gate 	STROPTP stropt;
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
965*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
966*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
967*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
968*7c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
969*7c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_COPYOPT;
970*7c478bd9Sstevel@tonic-gate 	stropt->so_copyopt = (ushort_t)copyopt;
971*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
972*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
973*7c478bd9Sstevel@tonic-gate }
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate boolean_t
976*7c478bd9Sstevel@tonic-gate mi_set_sth_wroff(queue_t *q, size_t size)
977*7c478bd9Sstevel@tonic-gate {
978*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
979*7c478bd9Sstevel@tonic-gate 	STROPTP stropt;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
982*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
983*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
984*7c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
985*7c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
986*7c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_WROFF;
987*7c478bd9Sstevel@tonic-gate 	stropt->so_wroff = (ushort_t)size;
988*7c478bd9Sstevel@tonic-gate 	putnext(q, mp);
989*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
990*7c478bd9Sstevel@tonic-gate }
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate int
993*7c478bd9Sstevel@tonic-gate mi_sprintf(char *buf, char *fmt, ...)
994*7c478bd9Sstevel@tonic-gate {
995*7c478bd9Sstevel@tonic-gate 	va_list	ap;
996*7c478bd9Sstevel@tonic-gate 	int	count = -1;
997*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
998*7c478bd9Sstevel@tonic-gate 	if (buf) {
999*7c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc,
1000*7c478bd9Sstevel@tonic-gate 		    (char *)&buf);
1001*7c478bd9Sstevel@tonic-gate 		if (count != -1)
1002*7c478bd9Sstevel@tonic-gate 			(void) mi_sprintf_putc((char *)&buf, '\0');
1003*7c478bd9Sstevel@tonic-gate 	}
1004*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1005*7c478bd9Sstevel@tonic-gate 	return (count);
1006*7c478bd9Sstevel@tonic-gate }
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate /* Used to count without writing data */
1009*7c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
1010*7c478bd9Sstevel@tonic-gate static int
1011*7c478bd9Sstevel@tonic-gate mi_sprintf_noop(char *cookie, int ch)
1012*7c478bd9Sstevel@tonic-gate {
1013*7c478bd9Sstevel@tonic-gate 	char	**cpp = (char **)cookie;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	(*cpp)++;
1016*7c478bd9Sstevel@tonic-gate 	return (1);
1017*7c478bd9Sstevel@tonic-gate }
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate int
1020*7c478bd9Sstevel@tonic-gate mi_sprintf_putc(char *cookie, int ch)
1021*7c478bd9Sstevel@tonic-gate {
1022*7c478bd9Sstevel@tonic-gate 	char	**cpp = (char **)cookie;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	**cpp = (char)ch;
1025*7c478bd9Sstevel@tonic-gate 	(*cpp)++;
1026*7c478bd9Sstevel@tonic-gate 	return (1);
1027*7c478bd9Sstevel@tonic-gate }
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate int
1030*7c478bd9Sstevel@tonic-gate mi_strcmp(const char *cp1, const char *cp2)
1031*7c478bd9Sstevel@tonic-gate {
1032*7c478bd9Sstevel@tonic-gate 	while (*cp1++ == *cp2++) {
1033*7c478bd9Sstevel@tonic-gate 		if (!cp2[-1])
1034*7c478bd9Sstevel@tonic-gate 			return (0);
1035*7c478bd9Sstevel@tonic-gate 	}
1036*7c478bd9Sstevel@tonic-gate 	return ((uint_t)cp2[-1]  & 0xFF) - ((uint_t)cp1[-1] & 0xFF);
1037*7c478bd9Sstevel@tonic-gate }
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate size_t
1040*7c478bd9Sstevel@tonic-gate mi_strlen(const char *str)
1041*7c478bd9Sstevel@tonic-gate {
1042*7c478bd9Sstevel@tonic-gate 	const char *cp = str;
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0')
1045*7c478bd9Sstevel@tonic-gate 		cp++;
1046*7c478bd9Sstevel@tonic-gate 	return ((int)(cp - str));
1047*7c478bd9Sstevel@tonic-gate }
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate int
1050*7c478bd9Sstevel@tonic-gate mi_strlog(queue_t *q, char level, ushort_t flags, char *fmt, ...)
1051*7c478bd9Sstevel@tonic-gate {
1052*7c478bd9Sstevel@tonic-gate 	va_list	ap;
1053*7c478bd9Sstevel@tonic-gate 	char	buf[200];
1054*7c478bd9Sstevel@tonic-gate 	char	*alloc_buf = buf;
1055*7c478bd9Sstevel@tonic-gate 	int	count = -1;
1056*7c478bd9Sstevel@tonic-gate 	char	*cp;
1057*7c478bd9Sstevel@tonic-gate 	short	mid;
1058*7c478bd9Sstevel@tonic-gate 	int	ret;
1059*7c478bd9Sstevel@tonic-gate 	short	sid;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	sid = 0;
1062*7c478bd9Sstevel@tonic-gate 	mid = 0;
1063*7c478bd9Sstevel@tonic-gate 	if (q != NULL) {
1064*7c478bd9Sstevel@tonic-gate 		mid = q->q_qinfo->qi_minfo->mi_idnum;
1065*7c478bd9Sstevel@tonic-gate 	}
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	/* Find out how many bytes we need and allocate if necesary */
1068*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1069*7c478bd9Sstevel@tonic-gate 	cp = buf;
1070*7c478bd9Sstevel@tonic-gate 	count = mi_iprintf(fmt, ap, mi_sprintf_noop, (char *)&cp);
1071*7c478bd9Sstevel@tonic-gate 	if (count > sizeof (buf) &&
1072*7c478bd9Sstevel@tonic-gate 	    !(alloc_buf = mi_alloc((uint_t)count + 2, BPRI_MED))) {
1073*7c478bd9Sstevel@tonic-gate 		va_end(ap);
1074*7c478bd9Sstevel@tonic-gate 		return (-1);
1075*7c478bd9Sstevel@tonic-gate 	}
1076*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1079*7c478bd9Sstevel@tonic-gate 	cp = alloc_buf;
1080*7c478bd9Sstevel@tonic-gate 	count = mi_iprintf(fmt, ap, mi_sprintf_putc, (char *)&cp);
1081*7c478bd9Sstevel@tonic-gate 	if (count != -1)
1082*7c478bd9Sstevel@tonic-gate 		(void) mi_sprintf_putc((char *)&cp, '\0');
1083*7c478bd9Sstevel@tonic-gate 	else
1084*7c478bd9Sstevel@tonic-gate 		alloc_buf[0] = '\0';
1085*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	ret = strlog(mid, sid, level, flags, alloc_buf);
1088*7c478bd9Sstevel@tonic-gate 	if (alloc_buf != buf)
1089*7c478bd9Sstevel@tonic-gate 		mi_free(alloc_buf);
1090*7c478bd9Sstevel@tonic-gate 	return (ret);
1091*7c478bd9Sstevel@tonic-gate }
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate long
1094*7c478bd9Sstevel@tonic-gate mi_strtol(const char *str, char **ptr, int base)
1095*7c478bd9Sstevel@tonic-gate {
1096*7c478bd9Sstevel@tonic-gate 	const char *cp;
1097*7c478bd9Sstevel@tonic-gate 	int	digits;
1098*7c478bd9Sstevel@tonic-gate 	long	value;
1099*7c478bd9Sstevel@tonic-gate 	boolean_t	is_negative;
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 	cp = str;
1102*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t' || *cp == '\n')
1103*7c478bd9Sstevel@tonic-gate 		cp++;
1104*7c478bd9Sstevel@tonic-gate 	is_negative = (*cp == '-');
1105*7c478bd9Sstevel@tonic-gate 	if (is_negative)
1106*7c478bd9Sstevel@tonic-gate 		cp++;
1107*7c478bd9Sstevel@tonic-gate 	if (base == 0) {
1108*7c478bd9Sstevel@tonic-gate 		base = 10;
1109*7c478bd9Sstevel@tonic-gate 		if (*cp == '0') {
1110*7c478bd9Sstevel@tonic-gate 			base = 8;
1111*7c478bd9Sstevel@tonic-gate 			cp++;
1112*7c478bd9Sstevel@tonic-gate 			if (*cp == 'x' || *cp == 'X') {
1113*7c478bd9Sstevel@tonic-gate 				base = 16;
1114*7c478bd9Sstevel@tonic-gate 				cp++;
1115*7c478bd9Sstevel@tonic-gate 			}
1116*7c478bd9Sstevel@tonic-gate 		}
1117*7c478bd9Sstevel@tonic-gate 	}
1118*7c478bd9Sstevel@tonic-gate 	value = 0;
1119*7c478bd9Sstevel@tonic-gate 	for (; *cp != '\0'; cp++) {
1120*7c478bd9Sstevel@tonic-gate 		if (*cp >= '0' && *cp <= '9')
1121*7c478bd9Sstevel@tonic-gate 			digits = *cp - '0';
1122*7c478bd9Sstevel@tonic-gate 		else if (*cp >= 'a' && *cp <= 'f')
1123*7c478bd9Sstevel@tonic-gate 			digits = *cp - 'a' + 10;
1124*7c478bd9Sstevel@tonic-gate 		else if (*cp >= 'A' && *cp <= 'F')
1125*7c478bd9Sstevel@tonic-gate 			digits = *cp - 'A' + 10;
1126*7c478bd9Sstevel@tonic-gate 		else
1127*7c478bd9Sstevel@tonic-gate 			break;
1128*7c478bd9Sstevel@tonic-gate 		if (digits >= base)
1129*7c478bd9Sstevel@tonic-gate 			break;
1130*7c478bd9Sstevel@tonic-gate 		value = (value * base) + digits;
1131*7c478bd9Sstevel@tonic-gate 	}
1132*7c478bd9Sstevel@tonic-gate 	/* Note: we cast away const here deliberately */
1133*7c478bd9Sstevel@tonic-gate 	if (ptr != NULL)
1134*7c478bd9Sstevel@tonic-gate 		*ptr = (char *)cp;
1135*7c478bd9Sstevel@tonic-gate 	if (is_negative)
1136*7c478bd9Sstevel@tonic-gate 		value = -value;
1137*7c478bd9Sstevel@tonic-gate 	return (value);
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate /*
1141*7c478bd9Sstevel@tonic-gate  *		mi_timer mechanism.
1142*7c478bd9Sstevel@tonic-gate  *
1143*7c478bd9Sstevel@tonic-gate  * Each timer is represented by a timer mblk and a (streams) queue. When the
1144*7c478bd9Sstevel@tonic-gate  * timer fires the timer mblk will be put on the associated streams queue
1145*7c478bd9Sstevel@tonic-gate  * so that the streams module can process the timer even in its service
1146*7c478bd9Sstevel@tonic-gate  * procedure.
1147*7c478bd9Sstevel@tonic-gate  *
1148*7c478bd9Sstevel@tonic-gate  * The interface consists of 4 entry points:
1149*7c478bd9Sstevel@tonic-gate  *	mi_timer_alloc		- create a timer mblk
1150*7c478bd9Sstevel@tonic-gate  *	mi_timer_free		- free a timer mblk
1151*7c478bd9Sstevel@tonic-gate  *	mi_timer		- start, restart, stop, or move the
1152*7c478bd9Sstevel@tonic-gate  *				  timer to a different queue
1153*7c478bd9Sstevel@tonic-gate  *	mi_timer_valid		- called by streams module to verify that
1154*7c478bd9Sstevel@tonic-gate  *				  the timer did indeed fire.
1155*7c478bd9Sstevel@tonic-gate  */
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate /*
1161*7c478bd9Sstevel@tonic-gate  * Start, restart, stop, or move the timer to a new queue.
1162*7c478bd9Sstevel@tonic-gate  * If "tim" is -2 the timer is moved to a different queue.
1163*7c478bd9Sstevel@tonic-gate  * If "tim" is -1 the timer is stopped.
1164*7c478bd9Sstevel@tonic-gate  * Otherwise, the timer is stopped if it is already running, and
1165*7c478bd9Sstevel@tonic-gate  * set to fire tim milliseconds from now.
1166*7c478bd9Sstevel@tonic-gate  */
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate void
1169*7c478bd9Sstevel@tonic-gate mi_timer(queue_t *q, MBLKP mp, clock_t tim)
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1172*7c478bd9Sstevel@tonic-gate 	int	state;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	ASSERT(tim >= -2);
1175*7c478bd9Sstevel@tonic-gate 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1176*7c478bd9Sstevel@tonic-gate 		return;
1177*7c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
1178*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
1179*7c478bd9Sstevel@tonic-gate 	if (tim >= 0) {
1180*7c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
1181*7c478bd9Sstevel@tonic-gate 		state = mtb->mtb_state;
1182*7c478bd9Sstevel@tonic-gate 		tim = MSEC_TO_TICK(tim);
1183*7c478bd9Sstevel@tonic-gate 		if (state == TB_RUNNING) {
1184*7c478bd9Sstevel@tonic-gate 			if (untimeout(mtb->mtb_tid) < 0) {
1185*7c478bd9Sstevel@tonic-gate 				/* Message has already been putq */
1186*7c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
1187*7c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
1188*7c478bd9Sstevel@tonic-gate 				mtb->mtb_state = TB_RESCHED;
1189*7c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
1190*7c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
1191*7c478bd9Sstevel@tonic-gate 				return;
1192*7c478bd9Sstevel@tonic-gate 			}
1193*7c478bd9Sstevel@tonic-gate 		} else if (state != TB_IDLE) {
1194*7c478bd9Sstevel@tonic-gate 			ASSERT(state != TB_TO_BE_FREED);
1195*7c478bd9Sstevel@tonic-gate 			if (state == TB_CANCELLED) {
1196*7c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
1197*7c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
1198*7c478bd9Sstevel@tonic-gate 				mtb->mtb_state = TB_RESCHED;
1199*7c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
1200*7c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
1201*7c478bd9Sstevel@tonic-gate 				return;
1202*7c478bd9Sstevel@tonic-gate 			}
1203*7c478bd9Sstevel@tonic-gate 			if (state == TB_RESCHED) {
1204*7c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
1205*7c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
1206*7c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
1207*7c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
1208*7c478bd9Sstevel@tonic-gate 				return;
1209*7c478bd9Sstevel@tonic-gate 			}
1210*7c478bd9Sstevel@tonic-gate 		}
1211*7c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_RUNNING;
1212*7c478bd9Sstevel@tonic-gate 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
1213*7c478bd9Sstevel@tonic-gate 		return;
1214*7c478bd9Sstevel@tonic-gate 	}
1215*7c478bd9Sstevel@tonic-gate 	switch (tim) {
1216*7c478bd9Sstevel@tonic-gate 	case -1:
1217*7c478bd9Sstevel@tonic-gate 		mi_timer_stop(mp);
1218*7c478bd9Sstevel@tonic-gate 		break;
1219*7c478bd9Sstevel@tonic-gate 	case -2:
1220*7c478bd9Sstevel@tonic-gate 		mi_timer_move(q, mp);
1221*7c478bd9Sstevel@tonic-gate 		break;
1222*7c478bd9Sstevel@tonic-gate 	}
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate /*
1226*7c478bd9Sstevel@tonic-gate  * Allocate an M_PCSIG timer message. The space between db_base and
1227*7c478bd9Sstevel@tonic-gate  * b_rptr is used by the mi_timer mechanism, and after b_rptr there are
1228*7c478bd9Sstevel@tonic-gate  * "size" bytes that the caller can use for its own purposes.
1229*7c478bd9Sstevel@tonic-gate  *
1230*7c478bd9Sstevel@tonic-gate  * Note that db_type has to be a priority message since otherwise
1231*7c478bd9Sstevel@tonic-gate  * the putq will not cause the service procedure to run when
1232*7c478bd9Sstevel@tonic-gate  * there is flow control.
1233*7c478bd9Sstevel@tonic-gate  */
1234*7c478bd9Sstevel@tonic-gate MBLKP
1235*7c478bd9Sstevel@tonic-gate mi_timer_alloc(size_t size)
1236*7c478bd9Sstevel@tonic-gate {
1237*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1238*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size + sizeof (MTB), BPRI_HI)) != NULL) {
1241*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PCSIG;
1242*7c478bd9Sstevel@tonic-gate 		mtb = (MTBP)mp->b_datap->db_base;
1243*7c478bd9Sstevel@tonic-gate 		mp->b_rptr = (uchar_t *)&mtb[1];
1244*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + size;
1245*7c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_IDLE;
1246*7c478bd9Sstevel@tonic-gate 		mtb->mtb_mp = mp;
1247*7c478bd9Sstevel@tonic-gate 		mtb->mtb_q = NULL;
1248*7c478bd9Sstevel@tonic-gate 		return (mp);
1249*7c478bd9Sstevel@tonic-gate 	}
1250*7c478bd9Sstevel@tonic-gate 	return (NULL);
1251*7c478bd9Sstevel@tonic-gate }
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate /*
1254*7c478bd9Sstevel@tonic-gate  * timeout() callback function.
1255*7c478bd9Sstevel@tonic-gate  * Put the message on the current queue.
1256*7c478bd9Sstevel@tonic-gate  * If the timer is stopped or moved to a different queue after
1257*7c478bd9Sstevel@tonic-gate  * it has fired then mi_timer() and mi_timer_valid() will clean
1258*7c478bd9Sstevel@tonic-gate  * things up.
1259*7c478bd9Sstevel@tonic-gate  */
1260*7c478bd9Sstevel@tonic-gate static int
1261*7c478bd9Sstevel@tonic-gate mi_timer_fire(MTBP mtb)
1262*7c478bd9Sstevel@tonic-gate {
1263*7c478bd9Sstevel@tonic-gate 	ASSERT(mtb == (MTBP)mtb->mtb_mp->b_datap->db_base);
1264*7c478bd9Sstevel@tonic-gate 	ASSERT(mtb->mtb_mp->b_datap->db_type == M_PCSIG);
1265*7c478bd9Sstevel@tonic-gate 	return (putq(mtb->mtb_q, mtb->mtb_mp));
1266*7c478bd9Sstevel@tonic-gate }
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate /*
1269*7c478bd9Sstevel@tonic-gate  * Logically free a timer mblk (that might have a pending timeout().)
1270*7c478bd9Sstevel@tonic-gate  * If the timer has fired and the mblk has been put on the queue then
1271*7c478bd9Sstevel@tonic-gate  * mi_timer_valid will free the mblk.
1272*7c478bd9Sstevel@tonic-gate  */
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate void
1275*7c478bd9Sstevel@tonic-gate mi_timer_free(MBLKP mp)
1276*7c478bd9Sstevel@tonic-gate {
1277*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1278*7c478bd9Sstevel@tonic-gate 	int	state;
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1281*7c478bd9Sstevel@tonic-gate 		return;
1282*7c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
1283*7c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
1284*7c478bd9Sstevel@tonic-gate 	if (state == TB_RUNNING) {
1285*7c478bd9Sstevel@tonic-gate 		if (untimeout(mtb->mtb_tid) < 0) {
1286*7c478bd9Sstevel@tonic-gate 			/* Message has already been putq */
1287*7c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
1288*7c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
1289*7c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_TO_BE_FREED;
1290*7c478bd9Sstevel@tonic-gate 			/* mi_timer_valid will free the mblk */
1291*7c478bd9Sstevel@tonic-gate 			return;
1292*7c478bd9Sstevel@tonic-gate 		}
1293*7c478bd9Sstevel@tonic-gate 	} else if (state != TB_IDLE) {
1294*7c478bd9Sstevel@tonic-gate 		/* Message has already been putq */
1295*7c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
1296*7c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
1297*7c478bd9Sstevel@tonic-gate 		ASSERT(state != TB_TO_BE_FREED);
1298*7c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_TO_BE_FREED;
1299*7c478bd9Sstevel@tonic-gate 		/* mi_timer_valid will free the mblk */
1300*7c478bd9Sstevel@tonic-gate 		return;
1301*7c478bd9Sstevel@tonic-gate 	}
1302*7c478bd9Sstevel@tonic-gate 	ASSERT(mtb->mtb_q ==  NULL || mtb->mtb_q->q_first != mp);
1303*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
1304*7c478bd9Sstevel@tonic-gate }
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate /*
1307*7c478bd9Sstevel@tonic-gate  * Called from mi_timer(,,-2)
1308*7c478bd9Sstevel@tonic-gate  */
1309*7c478bd9Sstevel@tonic-gate void
1310*7c478bd9Sstevel@tonic-gate mi_timer_move(queue_t *q, MBLKP mp)
1311*7c478bd9Sstevel@tonic-gate {
1312*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1313*7c478bd9Sstevel@tonic-gate 	clock_t	tim;
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1316*7c478bd9Sstevel@tonic-gate 		return;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
1319*7c478bd9Sstevel@tonic-gate 	/*
1320*7c478bd9Sstevel@tonic-gate 	 * Need to untimeout and restart to make
1321*7c478bd9Sstevel@tonic-gate 	 * sure that the mblk is not about to be putq on the old queue
1322*7c478bd9Sstevel@tonic-gate 	 * by mi_timer_fire.
1323*7c478bd9Sstevel@tonic-gate 	 */
1324*7c478bd9Sstevel@tonic-gate 	if (mtb->mtb_state == TB_RUNNING) {
1325*7c478bd9Sstevel@tonic-gate 		if ((tim = untimeout(mtb->mtb_tid)) < 0) {
1326*7c478bd9Sstevel@tonic-gate 			/*
1327*7c478bd9Sstevel@tonic-gate 			 * Message has already been putq. Move from old queue
1328*7c478bd9Sstevel@tonic-gate 			 * to new queue.
1329*7c478bd9Sstevel@tonic-gate 			 */
1330*7c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
1331*7c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
1332*7c478bd9Sstevel@tonic-gate 			rmvq(mtb->mtb_q, mp);
1333*7c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first != mp &&
1334*7c478bd9Sstevel@tonic-gate 			    mp->b_prev == NULL && mp->b_next == NULL);
1335*7c478bd9Sstevel@tonic-gate 			mtb->mtb_q = q;
1336*7c478bd9Sstevel@tonic-gate 			(void) putq(mtb->mtb_q, mp);
1337*7c478bd9Sstevel@tonic-gate 			return;
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
1340*7c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_RUNNING;
1341*7c478bd9Sstevel@tonic-gate 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
1342*7c478bd9Sstevel@tonic-gate 	} else if (mtb->mtb_state != TB_IDLE) {
1343*7c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_state != TB_TO_BE_FREED);
1344*7c478bd9Sstevel@tonic-gate 		/*
1345*7c478bd9Sstevel@tonic-gate 		 * Message is already sitting on queue. Move to new queue.
1346*7c478bd9Sstevel@tonic-gate 		 */
1347*7c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
1348*7c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
1349*7c478bd9Sstevel@tonic-gate 		rmvq(mtb->mtb_q, mp);
1350*7c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first != mp &&
1351*7c478bd9Sstevel@tonic-gate 		    mp->b_prev == NULL && mp->b_next == NULL);
1352*7c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
1353*7c478bd9Sstevel@tonic-gate 		(void) putq(mtb->mtb_q, mp);
1354*7c478bd9Sstevel@tonic-gate 	} else
1355*7c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
1356*7c478bd9Sstevel@tonic-gate }
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate /*
1359*7c478bd9Sstevel@tonic-gate  * Called from mi_timer(,,-1)
1360*7c478bd9Sstevel@tonic-gate  */
1361*7c478bd9Sstevel@tonic-gate void
1362*7c478bd9Sstevel@tonic-gate mi_timer_stop(MBLKP mp)
1363*7c478bd9Sstevel@tonic-gate {
1364*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1365*7c478bd9Sstevel@tonic-gate 	int	state;
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1368*7c478bd9Sstevel@tonic-gate 		return;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
1371*7c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
1372*7c478bd9Sstevel@tonic-gate 	if (state == TB_RUNNING) {
1373*7c478bd9Sstevel@tonic-gate 		if (untimeout(mtb->mtb_tid) < 0) {
1374*7c478bd9Sstevel@tonic-gate 			/* Message has already been putq */
1375*7c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
1376*7c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
1377*7c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_CANCELLED;
1378*7c478bd9Sstevel@tonic-gate 		} else {
1379*7c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_IDLE;
1380*7c478bd9Sstevel@tonic-gate 		}
1381*7c478bd9Sstevel@tonic-gate 	} else if (state == TB_RESCHED) {
1382*7c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
1383*7c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
1384*7c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_CANCELLED;
1385*7c478bd9Sstevel@tonic-gate 	}
1386*7c478bd9Sstevel@tonic-gate }
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate /*
1389*7c478bd9Sstevel@tonic-gate  * The user of the mi_timer mechanism is required to call mi_timer_valid() for
1390*7c478bd9Sstevel@tonic-gate  * each M_PCSIG message processed in the service procedures.
1391*7c478bd9Sstevel@tonic-gate  * mi_timer_valid will return "true" if the timer actually did fire.
1392*7c478bd9Sstevel@tonic-gate  */
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate boolean_t
1395*7c478bd9Sstevel@tonic-gate mi_timer_valid(MBLKP mp)
1396*7c478bd9Sstevel@tonic-gate {
1397*7c478bd9Sstevel@tonic-gate 	MTBP	mtb;
1398*7c478bd9Sstevel@tonic-gate 	int	state;
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB) ||
1401*7c478bd9Sstevel@tonic-gate 	    mp->b_datap->db_type != M_PCSIG)
1402*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1403*7c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
1404*7c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
1405*7c478bd9Sstevel@tonic-gate 	if (state != TB_RUNNING) {
1406*7c478bd9Sstevel@tonic-gate 		ASSERT(state != TB_IDLE);
1407*7c478bd9Sstevel@tonic-gate 		if (state == TB_TO_BE_FREED) {
1408*7c478bd9Sstevel@tonic-gate 			/*
1409*7c478bd9Sstevel@tonic-gate 			 * mi_timer_free was called after the message
1410*7c478bd9Sstevel@tonic-gate 			 * was putq'ed.
1411*7c478bd9Sstevel@tonic-gate 			 */
1412*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1413*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1414*7c478bd9Sstevel@tonic-gate 		}
1415*7c478bd9Sstevel@tonic-gate 		if (state == TB_CANCELLED) {
1416*7c478bd9Sstevel@tonic-gate 			/* The timer was stopped after the mblk was putq'ed */
1417*7c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_IDLE;
1418*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1419*7c478bd9Sstevel@tonic-gate 		}
1420*7c478bd9Sstevel@tonic-gate 		if (state == TB_RESCHED) {
1421*7c478bd9Sstevel@tonic-gate 			/*
1422*7c478bd9Sstevel@tonic-gate 			 * The timer was stopped and then restarted after
1423*7c478bd9Sstevel@tonic-gate 			 * the mblk was putq'ed.
1424*7c478bd9Sstevel@tonic-gate 			 * mtb_time_left contains the number of ticks that
1425*7c478bd9Sstevel@tonic-gate 			 * the timer was restarted with.
1426*7c478bd9Sstevel@tonic-gate 			 */
1427*7c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_RUNNING;
1428*7c478bd9Sstevel@tonic-gate 			mtb->mtb_tid = timeout((pfv_t)mi_timer_fire,
1429*7c478bd9Sstevel@tonic-gate 			    mtb, mtb->mtb_time_left);
1430*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1431*7c478bd9Sstevel@tonic-gate 		}
1432*7c478bd9Sstevel@tonic-gate 	}
1433*7c478bd9Sstevel@tonic-gate 	mtb->mtb_state = TB_IDLE;
1434*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
1435*7c478bd9Sstevel@tonic-gate }
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate static void
1438*7c478bd9Sstevel@tonic-gate mi_tpi_addr_and_opt(MBLKP mp, char *addr, t_scalar_t addr_length,
1439*7c478bd9Sstevel@tonic-gate     char *opt, t_scalar_t opt_length)
1440*7c478bd9Sstevel@tonic-gate {
1441*7c478bd9Sstevel@tonic-gate 	struct T_unitdata_ind	*tudi;
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	/*
1444*7c478bd9Sstevel@tonic-gate 	 * This code is used more than just for unitdata ind
1445*7c478bd9Sstevel@tonic-gate 	 * (also for T_CONN_IND and T_CONN_CON) and
1446*7c478bd9Sstevel@tonic-gate 	 * relies on correct functioning on the happy
1447*7c478bd9Sstevel@tonic-gate 	 * coincidence that the the address and option buffers
1448*7c478bd9Sstevel@tonic-gate 	 * represented by length/offset in all these primitives
1449*7c478bd9Sstevel@tonic-gate 	 * are isomorphic in terms of offset from start of data
1450*7c478bd9Sstevel@tonic-gate 	 * structure
1451*7c478bd9Sstevel@tonic-gate 	 */
1452*7c478bd9Sstevel@tonic-gate 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
1453*7c478bd9Sstevel@tonic-gate 	tudi->SRC_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
1454*7c478bd9Sstevel@tonic-gate 	tudi->SRC_length = addr_length;
1455*7c478bd9Sstevel@tonic-gate 	if (addr_length > 0) {
1456*7c478bd9Sstevel@tonic-gate 		bcopy(addr, (char *)mp->b_wptr, addr_length);
1457*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += addr_length;
1458*7c478bd9Sstevel@tonic-gate 	}
1459*7c478bd9Sstevel@tonic-gate 	tudi->OPT_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
1460*7c478bd9Sstevel@tonic-gate 	tudi->OPT_length = opt_length;
1461*7c478bd9Sstevel@tonic-gate 	if (opt_length > 0) {
1462*7c478bd9Sstevel@tonic-gate 		bcopy(opt, (char *)mp->b_wptr, opt_length);
1463*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += opt_length;
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate }
1466*7c478bd9Sstevel@tonic-gate 
1467*7c478bd9Sstevel@tonic-gate MBLKP
1468*7c478bd9Sstevel@tonic-gate mi_tpi_conn_con(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
1469*7c478bd9Sstevel@tonic-gate     t_scalar_t opt_length)
1470*7c478bd9Sstevel@tonic-gate {
1471*7c478bd9Sstevel@tonic-gate 	size_t	len;
1472*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_conn_con) + src_length + opt_length;
1475*7c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_CON)) != NULL) {
1476*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_con)];
1477*7c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1478*7c478bd9Sstevel@tonic-gate 	}
1479*7c478bd9Sstevel@tonic-gate 	return (mp);
1480*7c478bd9Sstevel@tonic-gate }
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate MBLKP
1483*7c478bd9Sstevel@tonic-gate mi_tpi_conn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
1484*7c478bd9Sstevel@tonic-gate     t_scalar_t opt_length, t_scalar_t seqnum)
1485*7c478bd9Sstevel@tonic-gate {
1486*7c478bd9Sstevel@tonic-gate 	size_t	len;
1487*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_conn_ind) + src_length + opt_length;
1490*7c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_IND)) != NULL) {
1491*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_ind)];
1492*7c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1493*7c478bd9Sstevel@tonic-gate 		((struct T_conn_ind *)mp->b_rptr)->SEQ_number = seqnum;
1494*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
1495*7c478bd9Sstevel@tonic-gate 	}
1496*7c478bd9Sstevel@tonic-gate 	return (mp);
1497*7c478bd9Sstevel@tonic-gate }
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate MBLKP
1500*7c478bd9Sstevel@tonic-gate mi_tpi_extconn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length,
1501*7c478bd9Sstevel@tonic-gate     char *opt, t_scalar_t opt_length, char *dst, t_scalar_t dst_length,
1502*7c478bd9Sstevel@tonic-gate     t_scalar_t seqnum)
1503*7c478bd9Sstevel@tonic-gate {
1504*7c478bd9Sstevel@tonic-gate 	size_t	len;
1505*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_extconn_ind) + src_length + opt_length +
1508*7c478bd9Sstevel@tonic-gate 	    dst_length;
1509*7c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_EXTCONN_IND)) !=
1510*7c478bd9Sstevel@tonic-gate 	    NULL) {
1511*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_extconn_ind)];
1512*7c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1513*7c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->DEST_length = dst_length;
1514*7c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->DEST_offset =
1515*7c478bd9Sstevel@tonic-gate 			(t_scalar_t)(mp->b_wptr - mp->b_rptr);
1516*7c478bd9Sstevel@tonic-gate 		if (dst_length > 0) {
1517*7c478bd9Sstevel@tonic-gate 			bcopy(dst, (char *)mp->b_wptr, dst_length);
1518*7c478bd9Sstevel@tonic-gate 			mp->b_wptr += dst_length;
1519*7c478bd9Sstevel@tonic-gate 		}
1520*7c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->SEQ_number = seqnum;
1521*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
1522*7c478bd9Sstevel@tonic-gate 	}
1523*7c478bd9Sstevel@tonic-gate 	return (mp);
1524*7c478bd9Sstevel@tonic-gate }
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate MBLKP
1527*7c478bd9Sstevel@tonic-gate mi_tpi_discon_ind(MBLKP trailer_mp, t_scalar_t reason, t_scalar_t seqnum)
1528*7c478bd9Sstevel@tonic-gate {
1529*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1530*7c478bd9Sstevel@tonic-gate 	struct T_discon_ind	*tdi;
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp,
1533*7c478bd9Sstevel@tonic-gate 	    sizeof (struct T_discon_ind), T_DISCON_IND)) != NULL) {
1534*7c478bd9Sstevel@tonic-gate 		tdi = (struct T_discon_ind *)mp->b_rptr;
1535*7c478bd9Sstevel@tonic-gate 		tdi->DISCON_reason = reason;
1536*7c478bd9Sstevel@tonic-gate 		tdi->SEQ_number = seqnum;
1537*7c478bd9Sstevel@tonic-gate 	}
1538*7c478bd9Sstevel@tonic-gate 	return (mp);
1539*7c478bd9Sstevel@tonic-gate }
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate /*
1542*7c478bd9Sstevel@tonic-gate  * Allocate and fill in a TPI err ack packet using the 'mp' passed in
1543*7c478bd9Sstevel@tonic-gate  * for the 'error_prim' context as well as sacrifice.
1544*7c478bd9Sstevel@tonic-gate  */
1545*7c478bd9Sstevel@tonic-gate MBLKP
1546*7c478bd9Sstevel@tonic-gate mi_tpi_err_ack_alloc(MBLKP mp, t_scalar_t tlierr, int unixerr)
1547*7c478bd9Sstevel@tonic-gate {
1548*7c478bd9Sstevel@tonic-gate 	struct T_error_ack	*teackp;
1549*7c478bd9Sstevel@tonic-gate 	t_scalar_t error_prim;
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	if (!mp)
1552*7c478bd9Sstevel@tonic-gate 		return (NULL);
1553*7c478bd9Sstevel@tonic-gate 	error_prim = ((TPRIMP)mp->b_rptr)->type;
1554*7c478bd9Sstevel@tonic-gate 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack),
1555*7c478bd9Sstevel@tonic-gate 	    M_PCPROTO, T_ERROR_ACK)) != NULL) {
1556*7c478bd9Sstevel@tonic-gate 		teackp = (struct T_error_ack *)mp->b_rptr;
1557*7c478bd9Sstevel@tonic-gate 		teackp->ERROR_prim = error_prim;
1558*7c478bd9Sstevel@tonic-gate 		teackp->TLI_error = tlierr;
1559*7c478bd9Sstevel@tonic-gate 		teackp->UNIX_error = unixerr;
1560*7c478bd9Sstevel@tonic-gate 	}
1561*7c478bd9Sstevel@tonic-gate 	return (mp);
1562*7c478bd9Sstevel@tonic-gate }
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate MBLKP
1565*7c478bd9Sstevel@tonic-gate mi_tpi_ok_ack_alloc_extra(MBLKP mp, int extra)
1566*7c478bd9Sstevel@tonic-gate {
1567*7c478bd9Sstevel@tonic-gate 	t_scalar_t correct_prim;
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 	if (!mp)
1570*7c478bd9Sstevel@tonic-gate 		return (NULL);
1571*7c478bd9Sstevel@tonic-gate 	correct_prim = ((TPRIMP)mp->b_rptr)->type;
1572*7c478bd9Sstevel@tonic-gate 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack) + extra,
1573*7c478bd9Sstevel@tonic-gate 	    M_PCPROTO, T_OK_ACK)) != NULL) {
1574*7c478bd9Sstevel@tonic-gate 		((struct T_ok_ack *)mp->b_rptr)->CORRECT_prim = correct_prim;
1575*7c478bd9Sstevel@tonic-gate 		mp->b_wptr -= extra;
1576*7c478bd9Sstevel@tonic-gate 	}
1577*7c478bd9Sstevel@tonic-gate 	return (mp);
1578*7c478bd9Sstevel@tonic-gate }
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate MBLKP
1581*7c478bd9Sstevel@tonic-gate mi_tpi_ok_ack_alloc(MBLKP mp)
1582*7c478bd9Sstevel@tonic-gate {
1583*7c478bd9Sstevel@tonic-gate 	return (mi_tpi_ok_ack_alloc_extra(mp, 0));
1584*7c478bd9Sstevel@tonic-gate }
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate MBLKP
1587*7c478bd9Sstevel@tonic-gate mi_tpi_ordrel_ind(void)
1588*7c478bd9Sstevel@tonic-gate {
1589*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 	if ((mp = allocb(sizeof (struct T_ordrel_ind), BPRI_HI)) != NULL) {
1592*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
1593*7c478bd9Sstevel@tonic-gate 		((struct T_ordrel_ind *)mp->b_rptr)->PRIM_type = T_ORDREL_IND;
1594*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += sizeof (struct T_ordrel_ind);
1595*7c478bd9Sstevel@tonic-gate 	}
1596*7c478bd9Sstevel@tonic-gate 	return (mp);
1597*7c478bd9Sstevel@tonic-gate }
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate static MBLKP
1600*7c478bd9Sstevel@tonic-gate mi_tpi_trailer_alloc(MBLKP trailer_mp, size_t size, t_scalar_t type)
1601*7c478bd9Sstevel@tonic-gate {
1602*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size, BPRI_MED)) != NULL) {
1605*7c478bd9Sstevel@tonic-gate 		mp->b_cont = trailer_mp;
1606*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
1607*7c478bd9Sstevel@tonic-gate 		((union T_primitives *)mp->b_rptr)->type = type;
1608*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += size;
1609*7c478bd9Sstevel@tonic-gate 	}
1610*7c478bd9Sstevel@tonic-gate 	return (mp);
1611*7c478bd9Sstevel@tonic-gate }
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate MBLKP
1614*7c478bd9Sstevel@tonic-gate mi_tpi_uderror_ind(char *dest, t_scalar_t dest_length, char *opt,
1615*7c478bd9Sstevel@tonic-gate     t_scalar_t opt_length, t_scalar_t error)
1616*7c478bd9Sstevel@tonic-gate {
1617*7c478bd9Sstevel@tonic-gate 	size_t	len;
1618*7c478bd9Sstevel@tonic-gate 	MBLKP	mp;
1619*7c478bd9Sstevel@tonic-gate 	struct T_uderror_ind	*tudei;
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_uderror_ind) + dest_length + opt_length;
1622*7c478bd9Sstevel@tonic-gate 	if ((mp = allocb(len, BPRI_HI)) != NULL) {
1623*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
1624*7c478bd9Sstevel@tonic-gate 		tudei = (struct T_uderror_ind *)mp->b_rptr;
1625*7c478bd9Sstevel@tonic-gate 		tudei->PRIM_type = T_UDERROR_IND;
1626*7c478bd9Sstevel@tonic-gate 		tudei->ERROR_type = error;
1627*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_uderror_ind)];
1628*7c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, dest, dest_length, opt, opt_length);
1629*7c478bd9Sstevel@tonic-gate 	}
1630*7c478bd9Sstevel@tonic-gate 	return (mp);
1631*7c478bd9Sstevel@tonic-gate }
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate IDP
1634*7c478bd9Sstevel@tonic-gate mi_zalloc(size_t size)
1635*7c478bd9Sstevel@tonic-gate {
1636*7c478bd9Sstevel@tonic-gate 	IDP	ptr;
1637*7c478bd9Sstevel@tonic-gate 
1638*7c478bd9Sstevel@tonic-gate 	if (ptr = mi_alloc(size, BPRI_LO))
1639*7c478bd9Sstevel@tonic-gate 		bzero(ptr, size);
1640*7c478bd9Sstevel@tonic-gate 	return (ptr);
1641*7c478bd9Sstevel@tonic-gate }
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate IDP
1644*7c478bd9Sstevel@tonic-gate mi_zalloc_sleep(size_t size)
1645*7c478bd9Sstevel@tonic-gate {
1646*7c478bd9Sstevel@tonic-gate 	IDP	ptr;
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 	if (ptr = mi_alloc_sleep(size, BPRI_LO))
1649*7c478bd9Sstevel@tonic-gate 		bzero(ptr, size);
1650*7c478bd9Sstevel@tonic-gate 	return (ptr);
1651*7c478bd9Sstevel@tonic-gate }
1652