xref: /titanic_51/usr/src/uts/common/inet/mi.c (revision f4b3ec61df05330d25f55a36b975b4d7519fdeb1)
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
5*f4b3ec61Sdh155122  * Common Development and Distribution License (the "License").
6*f4b3ec61Sdh155122  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*f4b3ec61Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <inet/common.h>	/* for various inet/mi.h and inet/nd.h needs */
317c478bd9Sstevel@tonic-gate #include <sys/stream.h>
327c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
337c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <inet/nd.h>
367c478bd9Sstevel@tonic-gate #include <inet/mi.h>
377c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
387c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
397c478bd9Sstevel@tonic-gate #include <sys/timod.h>
407c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
437c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
447c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
457c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
467c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
477c478bd9Sstevel@tonic-gate #include <sys/debug.h>
487c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #define	ISDIGIT(ch)	((ch) >= '0' && (ch) <= '9')
517c478bd9Sstevel@tonic-gate #define	ISUPPER(ch)	((ch) >= 'A' && (ch) <= 'Z')
527c478bd9Sstevel@tonic-gate #define	tolower(ch)	('a' + ((ch) - 'A'))
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	MI_IS_TRANSPARENT(mp)	(mp->b_cont && \
557c478bd9Sstevel@tonic-gate 	(mp->b_cont->b_rptr != mp->b_cont->b_wptr))
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below),
597c478bd9Sstevel@tonic-gate  * the size of the requested allocation is increased by one word.  This extra
607c478bd9Sstevel@tonic-gate  * word is used to store the size of the object being allocated, and is located
617c478bd9Sstevel@tonic-gate  * at the beginning of the allocated block.  The pointer returned to the caller
627c478bd9Sstevel@tonic-gate  * is a pointer to the *second* word in the newly-allocated block.  The IP
637c478bd9Sstevel@tonic-gate  * module of mdb is aware of this, and will need to be changed if this
647c478bd9Sstevel@tonic-gate  * allocation strategy is changed.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate typedef	struct stroptions *STROPTP;
687c478bd9Sstevel@tonic-gate typedef union T_primitives *TPRIMP;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* Timer block states. */
717c478bd9Sstevel@tonic-gate #define	TB_RUNNING	1
727c478bd9Sstevel@tonic-gate #define	TB_IDLE		2
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Could not stop/free before putq
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate #define	TB_RESCHED	3	/* mtb_time_left contains tick count */
777c478bd9Sstevel@tonic-gate #define	TB_CANCELLED	4
787c478bd9Sstevel@tonic-gate #define	TB_TO_BE_FREED	5
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate typedef struct mtb_s {
817c478bd9Sstevel@tonic-gate 	int		mtb_state;
827c478bd9Sstevel@tonic-gate 	timeout_id_t	mtb_tid;
837c478bd9Sstevel@tonic-gate 	queue_t		*mtb_q;
847c478bd9Sstevel@tonic-gate 	MBLKP		mtb_mp;
857c478bd9Sstevel@tonic-gate 	clock_t		mtb_time_left;
867c478bd9Sstevel@tonic-gate } MTB, *MTBP;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int mi_timer_fire(MTBP);
897c478bd9Sstevel@tonic-gate static int mi_iprintf(char *, va_list, pfi_t, char *);
907c478bd9Sstevel@tonic-gate static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t);
917c478bd9Sstevel@tonic-gate static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
947c478bd9Sstevel@tonic-gate void *
957c478bd9Sstevel@tonic-gate mi_alloc(size_t size, uint_t pri)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate 	size_t *ptr;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	size += sizeof (size);
1007c478bd9Sstevel@tonic-gate 	if (ptr = kmem_alloc(size, KM_NOSLEEP)) {
1017c478bd9Sstevel@tonic-gate 		*ptr = size;
1027c478bd9Sstevel@tonic-gate 		return (ptr + 1);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	return (NULL);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
1087c478bd9Sstevel@tonic-gate void *
1097c478bd9Sstevel@tonic-gate mi_alloc_sleep(size_t size, uint_t pri)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	size_t *ptr;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	size += sizeof (size);
1147c478bd9Sstevel@tonic-gate 	ptr = kmem_alloc(size, KM_SLEEP);
1157c478bd9Sstevel@tonic-gate 	*ptr = size;
1167c478bd9Sstevel@tonic-gate 	return (ptr + 1);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int
1207c478bd9Sstevel@tonic-gate mi_close_comm(void **mi_headp, queue_t *q)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	IDP ptr;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	ptr = q->q_ptr;
1257c478bd9Sstevel@tonic-gate 	mi_close_unlink(mi_headp, ptr);
1267c478bd9Sstevel@tonic-gate 	mi_close_free(ptr);
1277c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
1287c478bd9Sstevel@tonic-gate 	return (0);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate void
1327c478bd9Sstevel@tonic-gate mi_close_unlink(void **mi_headp, IDP ptr)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
1357c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
1367c478bd9Sstevel@tonic-gate 	dev_t		dev;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
1397c478bd9Sstevel@tonic-gate 	if (!mi_o)
1407c478bd9Sstevel@tonic-gate 		return;
1417c478bd9Sstevel@tonic-gate 	mi_o--;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if (mi_o->mi_o_next == NULL) {
1447c478bd9Sstevel@tonic-gate 		/* Not in list */
1457c478bd9Sstevel@tonic-gate 		ASSERT(mi_o->mi_o_prev == NULL);
1467c478bd9Sstevel@tonic-gate 		return;
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* Free minor number */
1507c478bd9Sstevel@tonic-gate 	dev = mi_o->mi_o_dev;
1517c478bd9Sstevel@tonic-gate 	if ((dev != OPENFAIL) && (dev != 0) && (dev <= MAXMIN))
1527c478bd9Sstevel@tonic-gate 		inet_minor_free(mi_head->mh_arena, dev);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/* Unlink from list */
1557c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next != NULL);
1567c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_prev != NULL);
1577c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next->mi_o_prev == mi_o);
1587c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_prev->mi_o_next == mi_o);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next->mi_o_prev = mi_o->mi_o_prev;
1617c478bd9Sstevel@tonic-gate 	mi_o->mi_o_prev->mi_o_next = mi_o->mi_o_next;
1627c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next = mi_o->mi_o_prev = NULL;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	mi_o->mi_o_dev = (dev_t)OPENFAIL;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* If list now empty free the list head */
1677c478bd9Sstevel@tonic-gate 	if (mi_head->mh_o.mi_o_next == &mi_head->mh_o) {
1687c478bd9Sstevel@tonic-gate 		ASSERT(mi_head->mh_o.mi_o_prev == &mi_head->mh_o);
1697c478bd9Sstevel@tonic-gate 		if (mi_head->mh_arena != NULL)
1707c478bd9Sstevel@tonic-gate 			inet_minor_destroy(mi_head->mh_arena);
1717c478bd9Sstevel@tonic-gate 		mi_free((IDP)mi_head);
1727c478bd9Sstevel@tonic-gate 		*mi_headp = NULL;
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate void
1777c478bd9Sstevel@tonic-gate mi_close_free(IDP ptr)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
1827c478bd9Sstevel@tonic-gate 	if (!mi_o)
1837c478bd9Sstevel@tonic-gate 		return;
1847c478bd9Sstevel@tonic-gate 	mi_o--;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	ASSERT(mi_o->mi_o_next == NULL && mi_o->mi_o_prev == NULL);
1877c478bd9Sstevel@tonic-gate 	mi_free((IDP)mi_o);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * mi_copyin - takes care of transparent or non-transparent ioctl for the
1927c478bd9Sstevel@tonic-gate  * calling function so that they have to deal with just M_IOCDATA type
1937c478bd9Sstevel@tonic-gate  * and not worry about M_COPYIN.
1947c478bd9Sstevel@tonic-gate  *
1957c478bd9Sstevel@tonic-gate  * mi_copyin checks to see if the ioctl is transparent or non transparent.
1967c478bd9Sstevel@tonic-gate  * In case of a non_transparent ioctl, it packs the data into a M_IOCDATA
1977c478bd9Sstevel@tonic-gate  * message and puts it back onto the current queue for further processing.
1987c478bd9Sstevel@tonic-gate  * In case of transparent ioctl, it sends a M_COPYIN message up to the
1997c478bd9Sstevel@tonic-gate  * streamhead so that a M_IOCDATA with the information comes back down.
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate void
2027c478bd9Sstevel@tonic-gate mi_copyin(queue_t *q, MBLKP mp, char *uaddr, size_t len)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	struct 	iocblk *iocp = (struct iocblk *)mp->b_rptr;
2057c478bd9Sstevel@tonic-gate 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
2067c478bd9Sstevel@tonic-gate 	struct 	copyresp *cp = (struct copyresp *)mp->b_rptr;
2077c478bd9Sstevel@tonic-gate 	int    	err;
2087c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_IOCTL && !uaddr);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* A transparent ioctl. Send a M_COPYIN message to the streamhead. */
2137c478bd9Sstevel@tonic-gate 	if (iocp->ioc_count == TRANSPARENT) {
2147c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 1;
2157c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_IN;
2167c478bd9Sstevel@tonic-gate 		cq->cq_private = mp->b_cont;
2177c478bd9Sstevel@tonic-gate 		cq->cq_size = len;
2187c478bd9Sstevel@tonic-gate 		cq->cq_flag = 0;
2197c478bd9Sstevel@tonic-gate 		bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
2207c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
2217c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_COPYIN;
2227c478bd9Sstevel@tonic-gate 		qreply(q, mp);
2237c478bd9Sstevel@tonic-gate 		return;
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * A non-transparent ioctl. Need to convert into M_IOCDATA message.
2287c478bd9Sstevel@tonic-gate 	 *
2297c478bd9Sstevel@tonic-gate 	 * We allocate a 0 byte message block and put its address in
2307c478bd9Sstevel@tonic-gate 	 * cp_private. It also makes the b_prev field = 1 and b_next
2317c478bd9Sstevel@tonic-gate 	 * field = MI_COPY_IN for this 0 byte block. This is done to
2327c478bd9Sstevel@tonic-gate 	 * maintain compatibility with old code in mi_copy_state
2337c478bd9Sstevel@tonic-gate 	 * (which removes the empty block).
2347c478bd9Sstevel@tonic-gate 	 */
2357c478bd9Sstevel@tonic-gate 	err = miocpullup(mp, len);
2367c478bd9Sstevel@tonic-gate 	if (err != 0)
2377c478bd9Sstevel@tonic-gate 		goto err_ret;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	mp1 = allocb(0, BPRI_MED);
2407c478bd9Sstevel@tonic-gate 	if (mp1 == NULL) {
2417c478bd9Sstevel@tonic-gate 		err = ENOMEM;
2427c478bd9Sstevel@tonic-gate 		goto err_ret;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so
2477c478bd9Sstevel@tonic-gate 	 * that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	mp1->b_cont = mp->b_cont;
2507c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1;
2517c478bd9Sstevel@tonic-gate 	MI_COPY_COUNT(mp) = 1;
2527c478bd9Sstevel@tonic-gate 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
2537c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1->b_cont;
2547c478bd9Sstevel@tonic-gate 	mp1->b_cont = NULL;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * Leave a pointer to the 0 byte block in cp_private field for
2587c478bd9Sstevel@tonic-gate 	 * future use by the mi_copy_* routines.
2597c478bd9Sstevel@tonic-gate 	 */
2607c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCDATA;
2617c478bd9Sstevel@tonic-gate 	cp->cp_private = mp1;
2627c478bd9Sstevel@tonic-gate 	cp->cp_rval = NULL;
2637c478bd9Sstevel@tonic-gate 	put(q, mp);
2647c478bd9Sstevel@tonic-gate 	return;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate err_ret:
2677c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
2687c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
2697c478bd9Sstevel@tonic-gate 	if (mp->b_cont) {
2707c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
2717c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
2747c478bd9Sstevel@tonic-gate 	qreply(q, mp);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * Allows transparent IOCTLs to have multiple copyins.  This is needed
2797c478bd9Sstevel@tonic-gate  * for some variable-length structures, where the total size is only known
2807c478bd9Sstevel@tonic-gate  * after the first part is copied in. Rather than setting MI_COPY_COUNT to
2817c478bd9Sstevel@tonic-gate  * 1, as in mi_coypin(), it is simply incremented here.  This value can
2827c478bd9Sstevel@tonic-gate  * then be checked in the returned IOCBLK.
2837c478bd9Sstevel@tonic-gate  *
2847c478bd9Sstevel@tonic-gate  * As this deals with copyins that follow the initial copyin, the byte
2857c478bd9Sstevel@tonic-gate  * offset into the user buffer from which copying should begin must be
2867c478bd9Sstevel@tonic-gate  * passed in in the offset parameter.
2877c478bd9Sstevel@tonic-gate  *
2887c478bd9Sstevel@tonic-gate  * Unlike mi_coypin(), this function expects to be passed an mblk chain
2897c478bd9Sstevel@tonic-gate  * headed by an M_IOCBLK, as that's the chain that will be in use for
2907c478bd9Sstevel@tonic-gate  * copies after the first one (copies where n != 1).
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate void
2937c478bd9Sstevel@tonic-gate mi_copyin_n(queue_t *q, MBLKP mp, size_t offset, size_t len)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_IOCDATA);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	MI_COPY_COUNT(mp)++;
3007c478bd9Sstevel@tonic-gate 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
3017c478bd9Sstevel@tonic-gate 	cq->cq_private = mp->b_cont;
3027c478bd9Sstevel@tonic-gate 	cq->cq_size = len;
3037c478bd9Sstevel@tonic-gate 	cq->cq_flag = 0;
3047c478bd9Sstevel@tonic-gate 	bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
3057c478bd9Sstevel@tonic-gate 	cq->cq_addr += offset;
3067c478bd9Sstevel@tonic-gate 	mp->b_cont = NULL;
3077c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_COPYIN;
3087c478bd9Sstevel@tonic-gate 	qreply(q, mp);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate void
3127c478bd9Sstevel@tonic-gate mi_copyout(queue_t *q, MBLKP mp)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
3157c478bd9Sstevel@tonic-gate 	struct copyreq *cq = (struct copyreq *)iocp;
3167c478bd9Sstevel@tonic-gate 	struct copyresp *cp = (struct copyresp *)cq;
3177c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
3187c478bd9Sstevel@tonic-gate 	MBLKP	mp2;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_IOCDATA || !mp->b_cont) {
3217c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, EPROTO);
3227c478bd9Sstevel@tonic-gate 		return;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	/* Check completion of previous copyout operation. */
3257c478bd9Sstevel@tonic-gate 	mp1 = mp->b_cont;
3267c478bd9Sstevel@tonic-gate 	if ((int)(uintptr_t)cp->cp_rval || !mp1->b_cont) {
3277c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
3287c478bd9Sstevel@tonic-gate 		return;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 	if (!mp1->b_cont->b_cont && !MI_IS_TRANSPARENT(mp)) {
3317c478bd9Sstevel@tonic-gate 		mp1->b_next = NULL;
3327c478bd9Sstevel@tonic-gate 		mp1->b_prev = NULL;
3337c478bd9Sstevel@tonic-gate 		mp->b_cont = mp1->b_cont;
3347c478bd9Sstevel@tonic-gate 		freeb(mp1);
3357c478bd9Sstevel@tonic-gate 		mp1 = mp->b_cont;
3367c478bd9Sstevel@tonic-gate 		mp1->b_next = NULL;
3377c478bd9Sstevel@tonic-gate 		mp1->b_prev = NULL;
3387c478bd9Sstevel@tonic-gate 		iocp->ioc_count = mp1->b_wptr - mp1->b_rptr;
3397c478bd9Sstevel@tonic-gate 		iocp->ioc_error = 0;
3407c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
3417c478bd9Sstevel@tonic-gate 		qreply(q, mp);
3427c478bd9Sstevel@tonic-gate 		return;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 	if (MI_COPY_DIRECTION(mp) == MI_COPY_IN) {
3457c478bd9Sstevel@tonic-gate 		/* Set up for first copyout. */
3467c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
3477c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 1;
3487c478bd9Sstevel@tonic-gate 	} else {
3497c478bd9Sstevel@tonic-gate 		++MI_COPY_COUNT(mp);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	cq->cq_private = mp1;
3527c478bd9Sstevel@tonic-gate 	/* Find message preceding last. */
3537c478bd9Sstevel@tonic-gate 	for (mp2 = mp1; mp2->b_cont->b_cont; mp2 = mp2->b_cont)
3547c478bd9Sstevel@tonic-gate 		;
3557c478bd9Sstevel@tonic-gate 	if (mp2 == mp1)
3567c478bd9Sstevel@tonic-gate 		bcopy((char *)mp1->b_rptr, (char *)&cq->cq_addr,
3577c478bd9Sstevel@tonic-gate 		    sizeof (cq->cq_addr));
3587c478bd9Sstevel@tonic-gate 	else
3597c478bd9Sstevel@tonic-gate 		cq->cq_addr = (char *)mp2->b_cont->b_next;
3607c478bd9Sstevel@tonic-gate 	mp1 = mp2->b_cont;
3617c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_COPYOUT;
3627c478bd9Sstevel@tonic-gate 	mp->b_cont = mp1;
3637c478bd9Sstevel@tonic-gate 	mp2->b_cont = NULL;
3647c478bd9Sstevel@tonic-gate 	mp1->b_next = NULL;
3657c478bd9Sstevel@tonic-gate 	cq->cq_size = mp1->b_wptr - mp1->b_rptr;
3667c478bd9Sstevel@tonic-gate 	cq->cq_flag = 0;
3677c478bd9Sstevel@tonic-gate 	qreply(q, mp);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate MBLKP
3717c478bd9Sstevel@tonic-gate mi_copyout_alloc(queue_t *q, MBLKP mp, char *uaddr, size_t len,
3727c478bd9Sstevel@tonic-gate     boolean_t free_on_error)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
3757c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type == M_IOCTL) {
3787c478bd9Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
3797c478bd9Sstevel@tonic-gate 			mp1 = allocb(0, BPRI_MED);
3807c478bd9Sstevel@tonic-gate 			if (mp1 == NULL) {
3817c478bd9Sstevel@tonic-gate 				if (free_on_error) {
3827c478bd9Sstevel@tonic-gate 					iocp->ioc_error = ENOMEM;
3837c478bd9Sstevel@tonic-gate 					iocp->ioc_count = 0;
3847c478bd9Sstevel@tonic-gate 					freemsg(mp->b_cont);
3857c478bd9Sstevel@tonic-gate 					mp->b_cont = NULL;
3867c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_IOCACK;
3877c478bd9Sstevel@tonic-gate 					qreply(q, mp);
3887c478bd9Sstevel@tonic-gate 				}
3897c478bd9Sstevel@tonic-gate 				return (NULL);
3907c478bd9Sstevel@tonic-gate 			}
3917c478bd9Sstevel@tonic-gate 			mp1->b_cont = mp->b_cont;
3927c478bd9Sstevel@tonic-gate 			mp->b_cont = mp1;
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 		MI_COPY_COUNT(mp) = 0;
3957c478bd9Sstevel@tonic-gate 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
3967c478bd9Sstevel@tonic-gate 		/* Make sure it looks clean to mi_copyout. */
3977c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCDATA;
3987c478bd9Sstevel@tonic-gate 		((struct copyresp *)iocp)->cp_rval = NULL;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 	mp1 = allocb(len, BPRI_MED);
4017c478bd9Sstevel@tonic-gate 	if (mp1 == NULL) {
4027c478bd9Sstevel@tonic-gate 		if (free_on_error)
4037c478bd9Sstevel@tonic-gate 			mi_copy_done(q, mp, ENOMEM);
4047c478bd9Sstevel@tonic-gate 		return (NULL);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	linkb(mp, mp1);
4077c478bd9Sstevel@tonic-gate 	mp1->b_next = (MBLKP)uaddr;
4087c478bd9Sstevel@tonic-gate 	return (mp1);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate void
4127c478bd9Sstevel@tonic-gate mi_copy_done(queue_t *q, MBLKP mp, int err)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
4157c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if (!mp)
4187c478bd9Sstevel@tonic-gate 		return;
4197c478bd9Sstevel@tonic-gate 	if (!q || (mp->b_wptr - mp->b_rptr) < sizeof (struct iocblk)) {
4207c478bd9Sstevel@tonic-gate 		freemsg(mp);
4217c478bd9Sstevel@tonic-gate 		return;
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
4247c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
4257c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
4287c478bd9Sstevel@tonic-gate 	if ((mp1 = mp->b_cont) != NULL) {
4297c478bd9Sstevel@tonic-gate 		for (; mp1; mp1 = mp1->b_cont) {
4307c478bd9Sstevel@tonic-gate 			mp1->b_prev = NULL;
4317c478bd9Sstevel@tonic-gate 			mp1->b_next = NULL;
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate 		freemsg(mp->b_cont);
4347c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 	qreply(q, mp);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate int
4407c478bd9Sstevel@tonic-gate mi_copy_state(queue_t *q, MBLKP mp, MBLKP *mpp)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
4437c478bd9Sstevel@tonic-gate 	struct copyresp *cp = (struct copyresp *)iocp;
4447c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	mp1 = mp->b_cont;
4477c478bd9Sstevel@tonic-gate 	mp->b_cont = cp->cp_private;
4487c478bd9Sstevel@tonic-gate 	if (mp1) {
4497c478bd9Sstevel@tonic-gate 		if (mp1->b_cont && !pullupmsg(mp1, -1)) {
4507c478bd9Sstevel@tonic-gate 			mi_copy_done(q, mp, ENOMEM);
4517c478bd9Sstevel@tonic-gate 			return (-1);
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 		linkb(mp->b_cont, mp1);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	if ((int)(uintptr_t)cp->cp_rval) {
4567c478bd9Sstevel@tonic-gate 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
4577c478bd9Sstevel@tonic-gate 		return (-1);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 	if (mpp && MI_COPY_DIRECTION(mp) == MI_COPY_IN)
4607c478bd9Sstevel@tonic-gate 		*mpp = mp1;
4617c478bd9Sstevel@tonic-gate 	return (MI_COPY_STATE(mp));
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate void
4657c478bd9Sstevel@tonic-gate mi_free(void *ptr)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	size_t	size;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (!ptr)
4707c478bd9Sstevel@tonic-gate 		return;
4717c478bd9Sstevel@tonic-gate 	if ((size = ((size_t *)ptr)[-1]) <= 0)
4727c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "mi_free");
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	kmem_free((void *) ((size_t *)ptr - 1), size);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate static int
4787c478bd9Sstevel@tonic-gate mi_iprintf(char *fmt, va_list ap, pfi_t putc_func, char *cookie)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	int	base;
4817c478bd9Sstevel@tonic-gate 	char	buf[(sizeof (long) * 3) + 1];
4827c478bd9Sstevel@tonic-gate 	static char	hex_val[] = "0123456789abcdef";
4837c478bd9Sstevel@tonic-gate 	int	ch;
4847c478bd9Sstevel@tonic-gate 	int	count;
4857c478bd9Sstevel@tonic-gate 	char	*cp1;
4867c478bd9Sstevel@tonic-gate 	int	digits;
4877c478bd9Sstevel@tonic-gate 	char	*fcp;
4887c478bd9Sstevel@tonic-gate 	boolean_t	is_long;
4897c478bd9Sstevel@tonic-gate 	ulong_t	uval;
4907c478bd9Sstevel@tonic-gate 	long	val;
4917c478bd9Sstevel@tonic-gate 	boolean_t	zero_filled;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (!fmt)
4947c478bd9Sstevel@tonic-gate 		return (-1);
4957c478bd9Sstevel@tonic-gate 	count = 0;
4967c478bd9Sstevel@tonic-gate 	while (*fmt) {
4977c478bd9Sstevel@tonic-gate 		if (*fmt != '%' || *++fmt == '%') {
4987c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, *fmt++);
4997c478bd9Sstevel@tonic-gate 			continue;
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 		if (*fmt == '0') {
5027c478bd9Sstevel@tonic-gate 			zero_filled = B_TRUE;
5037c478bd9Sstevel@tonic-gate 			fmt++;
5047c478bd9Sstevel@tonic-gate 			if (!*fmt)
5057c478bd9Sstevel@tonic-gate 				break;
5067c478bd9Sstevel@tonic-gate 		} else
5077c478bd9Sstevel@tonic-gate 			zero_filled = B_FALSE;
5087c478bd9Sstevel@tonic-gate 		base = 0;
5097c478bd9Sstevel@tonic-gate 		for (digits = 0; ISDIGIT(*fmt); fmt++) {
5107c478bd9Sstevel@tonic-gate 			digits *= 10;
5117c478bd9Sstevel@tonic-gate 			digits += (*fmt - '0');
5127c478bd9Sstevel@tonic-gate 		}
5137c478bd9Sstevel@tonic-gate 		if (!*fmt)
5147c478bd9Sstevel@tonic-gate 			break;
5157c478bd9Sstevel@tonic-gate 		is_long = B_FALSE;
5167c478bd9Sstevel@tonic-gate 		if (*fmt == 'l') {
5177c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
5187c478bd9Sstevel@tonic-gate 			fmt++;
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 		if (!*fmt)
5217c478bd9Sstevel@tonic-gate 			break;
5227c478bd9Sstevel@tonic-gate 		ch = *fmt++;
5237c478bd9Sstevel@tonic-gate 		if (ISUPPER(ch)) {
5247c478bd9Sstevel@tonic-gate 			ch = tolower(ch);
5257c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 		switch (ch) {
5287c478bd9Sstevel@tonic-gate 		case 'c':
5297c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, va_arg(ap, int *));
5307c478bd9Sstevel@tonic-gate 			continue;
5317c478bd9Sstevel@tonic-gate 		case 'd':
5327c478bd9Sstevel@tonic-gate 			base = 10;
5337c478bd9Sstevel@tonic-gate 			break;
5347c478bd9Sstevel@tonic-gate 		case 'm':	/* Print out memory, 2 hex chars per byte */
5357c478bd9Sstevel@tonic-gate 			if (is_long)
5367c478bd9Sstevel@tonic-gate 				fcp = va_arg(ap, char *);
5377c478bd9Sstevel@tonic-gate 			else {
5387c478bd9Sstevel@tonic-gate 				if ((cp1 = va_arg(ap, char *)) != NULL)
5397c478bd9Sstevel@tonic-gate 					fcp = (char *)cp1;
5407c478bd9Sstevel@tonic-gate 				else
5417c478bd9Sstevel@tonic-gate 					fcp = NULL;
5427c478bd9Sstevel@tonic-gate 			}
5437c478bd9Sstevel@tonic-gate 			if (!fcp) {
5447c478bd9Sstevel@tonic-gate 				for (fcp = (char *)"(NULL)"; *fcp; fcp++)
5457c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie, *fcp);
5467c478bd9Sstevel@tonic-gate 			} else {
5477c478bd9Sstevel@tonic-gate 				while (digits--) {
5487c478bd9Sstevel@tonic-gate 					int u1 = *fcp++ & 0xFF;
5497c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie,
5507c478bd9Sstevel@tonic-gate 					    hex_val[(u1>>4)& 0xF]);
5517c478bd9Sstevel@tonic-gate 					count += (*putc_func)(cookie,
5527c478bd9Sstevel@tonic-gate 					    hex_val[u1& 0xF]);
5537c478bd9Sstevel@tonic-gate 				}
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 			continue;
5567c478bd9Sstevel@tonic-gate 		case 'o':
5577c478bd9Sstevel@tonic-gate 			base = 8;
5587c478bd9Sstevel@tonic-gate 			break;
5597c478bd9Sstevel@tonic-gate 		case 'p':
5607c478bd9Sstevel@tonic-gate 			is_long = B_TRUE;
5617c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
5627c478bd9Sstevel@tonic-gate 		case 'x':
5637c478bd9Sstevel@tonic-gate 			base = 16;
5647c478bd9Sstevel@tonic-gate 			break;
5657c478bd9Sstevel@tonic-gate 		case 's':
5667c478bd9Sstevel@tonic-gate 			if (is_long)
5677c478bd9Sstevel@tonic-gate 				fcp = va_arg(ap, char *);
5687c478bd9Sstevel@tonic-gate 			else {
5697c478bd9Sstevel@tonic-gate 				if ((cp1 = va_arg(ap, char *)) != NULL)
5707c478bd9Sstevel@tonic-gate 					fcp = (char *)cp1;
5717c478bd9Sstevel@tonic-gate 				else
5727c478bd9Sstevel@tonic-gate 					fcp = NULL;
5737c478bd9Sstevel@tonic-gate 			}
5747c478bd9Sstevel@tonic-gate 			if (!fcp)
5757c478bd9Sstevel@tonic-gate 				fcp = (char *)"(NULL)";
5767c478bd9Sstevel@tonic-gate 			while (*fcp) {
5777c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, *fcp++);
5787c478bd9Sstevel@tonic-gate 				if (digits && --digits == 0)
5797c478bd9Sstevel@tonic-gate 					break;
5807c478bd9Sstevel@tonic-gate 			}
5817c478bd9Sstevel@tonic-gate 			while (digits > 0) {
5827c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, ' ');
5837c478bd9Sstevel@tonic-gate 				digits--;
5847c478bd9Sstevel@tonic-gate 			}
5857c478bd9Sstevel@tonic-gate 			continue;
5867c478bd9Sstevel@tonic-gate 		case 'u':
5877c478bd9Sstevel@tonic-gate 			base = 10;
5887c478bd9Sstevel@tonic-gate 			break;
5897c478bd9Sstevel@tonic-gate 		default:
5907c478bd9Sstevel@tonic-gate 			return (count);
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 		if (is_long)
5937c478bd9Sstevel@tonic-gate 			val = va_arg(ap, long);
5947c478bd9Sstevel@tonic-gate 		else
5957c478bd9Sstevel@tonic-gate 			val = va_arg(ap, int);
5967c478bd9Sstevel@tonic-gate 		if (base == 10 && ch != 'u') {
5977c478bd9Sstevel@tonic-gate 			if (val < 0) {
5987c478bd9Sstevel@tonic-gate 				count += (*putc_func)(cookie, '-');
5997c478bd9Sstevel@tonic-gate 				val = -val;
6007c478bd9Sstevel@tonic-gate 			}
6017c478bd9Sstevel@tonic-gate 			uval = val;
6027c478bd9Sstevel@tonic-gate 		} else {
6037c478bd9Sstevel@tonic-gate 			if (is_long)
6047c478bd9Sstevel@tonic-gate 				uval = val;
6057c478bd9Sstevel@tonic-gate 			else
6067c478bd9Sstevel@tonic-gate 				uval = (uint_t)val;
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 		/* Hand overload/restore the register variable 'fmt' */
6097c478bd9Sstevel@tonic-gate 		cp1 = fmt;
6107c478bd9Sstevel@tonic-gate 		fmt = A_END(buf);
6117c478bd9Sstevel@tonic-gate 		*--fmt = '\0';
6127c478bd9Sstevel@tonic-gate 		do {
6137c478bd9Sstevel@tonic-gate 			if (fmt > buf)
6147c478bd9Sstevel@tonic-gate 				*--fmt = hex_val[uval % base];
6157c478bd9Sstevel@tonic-gate 			if (digits && --digits == 0)
6167c478bd9Sstevel@tonic-gate 				break;
6177c478bd9Sstevel@tonic-gate 		} while (uval /= base);
6187c478bd9Sstevel@tonic-gate 		if (zero_filled) {
6197c478bd9Sstevel@tonic-gate 			while (digits > 0 && fmt > buf) {
6207c478bd9Sstevel@tonic-gate 				*--fmt = '0';
6217c478bd9Sstevel@tonic-gate 				digits--;
6227c478bd9Sstevel@tonic-gate 			}
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 		while (*fmt)
6257c478bd9Sstevel@tonic-gate 			count += (*putc_func)(cookie, *fmt++);
6267c478bd9Sstevel@tonic-gate 		fmt = cp1;
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	return (count);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
6327c478bd9Sstevel@tonic-gate int
6337c478bd9Sstevel@tonic-gate mi_mpprintf(MBLKP mp, char *fmt, ...)
6347c478bd9Sstevel@tonic-gate {
6357c478bd9Sstevel@tonic-gate 	va_list	ap;
6367c478bd9Sstevel@tonic-gate 	int	count = -1;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
6397c478bd9Sstevel@tonic-gate 	if (mp) {
6407c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
6417c478bd9Sstevel@tonic-gate 		    (char *)mp);
6427c478bd9Sstevel@tonic-gate 		if (count != -1)
6437c478bd9Sstevel@tonic-gate 			(void) mi_mpprintf_putc((char *)mp, '\0');
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 	va_end(ap);
6467c478bd9Sstevel@tonic-gate 	return (count);
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
6507c478bd9Sstevel@tonic-gate int
6517c478bd9Sstevel@tonic-gate mi_mpprintf_nr(MBLKP mp, char *fmt, ...)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	va_list	ap;
6547c478bd9Sstevel@tonic-gate 	int	count = -1;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
6577c478bd9Sstevel@tonic-gate 	if (mp) {
6587c478bd9Sstevel@tonic-gate 		(void) adjmsg(mp, -1);
6597c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
6607c478bd9Sstevel@tonic-gate 		    (char *)mp);
6617c478bd9Sstevel@tonic-gate 		if (count != -1)
6627c478bd9Sstevel@tonic-gate 			(void) mi_mpprintf_putc((char *)mp, '\0');
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 	va_end(ap);
6657c478bd9Sstevel@tonic-gate 	return (count);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate int
6697c478bd9Sstevel@tonic-gate mi_mpprintf_putc(char *cookie, int ch)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	MBLKP	mp = (MBLKP)cookie;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	while (mp->b_cont)
6747c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
6757c478bd9Sstevel@tonic-gate 	if (mp->b_wptr >= mp->b_datap->db_lim) {
6767c478bd9Sstevel@tonic-gate 		mp->b_cont = allocb(1024, BPRI_HI);
6777c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
6787c478bd9Sstevel@tonic-gate 		if (!mp)
6797c478bd9Sstevel@tonic-gate 			return (0);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 	*mp->b_wptr++ = (unsigned char)ch;
6827c478bd9Sstevel@tonic-gate 	return (1);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate IDP
6867c478bd9Sstevel@tonic-gate mi_first_ptr(void **mi_headp)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
6897c478bd9Sstevel@tonic-gate 	MI_OP	mi_op;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	mi_op = mi_head->mh_o.mi_o_next;
6927c478bd9Sstevel@tonic-gate 	if (mi_op && mi_op != &mi_head->mh_o)
6937c478bd9Sstevel@tonic-gate 		return ((IDP)&mi_op[1]);
6947c478bd9Sstevel@tonic-gate 	return (NULL);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * Clients can choose to have both module instances and device instances
6997c478bd9Sstevel@tonic-gate  * in the same list. Return the first device instance in the list.
7007c478bd9Sstevel@tonic-gate  */
7017c478bd9Sstevel@tonic-gate IDP
7027c478bd9Sstevel@tonic-gate mi_first_dev_ptr(void **mi_headp)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
7057c478bd9Sstevel@tonic-gate 	MI_OP	mi_op;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	mi_op = mi_head->mh_o.mi_o_next;
7087c478bd9Sstevel@tonic-gate 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
7097c478bd9Sstevel@tonic-gate 		if (mi_op->mi_o_isdev)
7107c478bd9Sstevel@tonic-gate 			return ((IDP)&mi_op[1]);
7117c478bd9Sstevel@tonic-gate 		mi_op = mi_op->mi_o_next;
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 	return (NULL);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate IDP
7177c478bd9Sstevel@tonic-gate mi_next_ptr(void **mi_headp, IDP ptr)
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
7207c478bd9Sstevel@tonic-gate 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if ((mi_op = mi_op->mi_o_next) != NULL && mi_op != &mi_head->mh_o)
7237c478bd9Sstevel@tonic-gate 		return ((IDP)&mi_op[1]);
7247c478bd9Sstevel@tonic-gate 	return (NULL);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate  * Clients can choose to have both module instances and device instances
7297c478bd9Sstevel@tonic-gate  * in the same list. Return the next device instance in the list.
7307c478bd9Sstevel@tonic-gate  */
7317c478bd9Sstevel@tonic-gate IDP
7327c478bd9Sstevel@tonic-gate mi_next_dev_ptr(void **mi_headp, IDP ptr)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
7357c478bd9Sstevel@tonic-gate 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	mi_op = mi_op->mi_o_next;
7387c478bd9Sstevel@tonic-gate 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
7397c478bd9Sstevel@tonic-gate 		if (mi_op->mi_o_isdev)
7407c478bd9Sstevel@tonic-gate 			return ((IDP)&mi_op[1]);
7417c478bd9Sstevel@tonic-gate 		mi_op = mi_op->mi_o_next;
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 	return (NULL);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate /*
7477c478bd9Sstevel@tonic-gate  * Self clone the device
7487c478bd9Sstevel@tonic-gate  * XXX - should we still support clone device
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate /* ARGSUSED4 */
7517c478bd9Sstevel@tonic-gate int
7527c478bd9Sstevel@tonic-gate mi_open_comm(void **mi_headp, size_t size, queue_t *q, dev_t *devp,
7537c478bd9Sstevel@tonic-gate     int flag, int sflag, cred_t *credp)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate 	int error;
7567c478bd9Sstevel@tonic-gate 	IDP ptr;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
7597c478bd9Sstevel@tonic-gate 		return (0);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	ptr = mi_open_alloc_sleep(size);
7627c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = ptr;
7637c478bd9Sstevel@tonic-gate 	error = mi_open_link(mi_headp, ptr, devp, flag, sflag, credp);
7647c478bd9Sstevel@tonic-gate 	if (error != 0) {
7657c478bd9Sstevel@tonic-gate 		q->q_ptr = WR(q)->q_ptr = NULL;
7667c478bd9Sstevel@tonic-gate 		mi_close_free(ptr);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	return (error);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate IDP
7727c478bd9Sstevel@tonic-gate mi_open_alloc_sleep(size_t size)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	if (size > (UINT_MAX - sizeof (MI_O)))
7777c478bd9Sstevel@tonic-gate 		return (NULL);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)mi_zalloc_sleep(size + sizeof (MI_O));
7807c478bd9Sstevel@tonic-gate 	mi_o++;
7817c478bd9Sstevel@tonic-gate 	return ((IDP)mi_o);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate IDP
7857c478bd9Sstevel@tonic-gate mi_open_alloc(size_t size)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	if (size > (UINT_MAX - sizeof (MI_O)))
7907c478bd9Sstevel@tonic-gate 		return (NULL);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if ((mi_o = (MI_OP)mi_zalloc(size + sizeof (MI_O))) == NULL)
7937c478bd9Sstevel@tonic-gate 		return (NULL);
7947c478bd9Sstevel@tonic-gate 	mi_o++;
7957c478bd9Sstevel@tonic-gate 	return ((IDP)mi_o);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate  * MODOPEN means just link in without respect of mi_o_dev.
8007c478bd9Sstevel@tonic-gate  * A NULL devp can be used to create a detached instance
8017c478bd9Sstevel@tonic-gate  * Otherwise self-clone the device.
8027c478bd9Sstevel@tonic-gate  */
8037c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
8047c478bd9Sstevel@tonic-gate int
8057c478bd9Sstevel@tonic-gate mi_open_link(void **mi_headp, IDP ptr, dev_t *devp, int flag, int sflag,
8067c478bd9Sstevel@tonic-gate     cred_t *credp)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
8097c478bd9Sstevel@tonic-gate 	MI_OP		insert;
8107c478bd9Sstevel@tonic-gate 	MI_OP		mi_o;
8117c478bd9Sstevel@tonic-gate 	dev_t		dev;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if (mi_head == NULL) {
8147c478bd9Sstevel@tonic-gate 		char arena_name[50];
8157c478bd9Sstevel@tonic-gate 		char *head_name;
8167c478bd9Sstevel@tonic-gate 		ulong_t offset;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		head_name = kobj_getsymname((uintptr_t)mi_headp, &offset);
819*f4b3ec61Sdh155122 		if (head_name != NULL && offset == 0) {
8207c478bd9Sstevel@tonic-gate 			(void) sprintf(arena_name, "%s_", head_name);
821*f4b3ec61Sdh155122 		} else {
822*f4b3ec61Sdh155122 			(void) sprintf(arena_name, "Hex0x%p_",
823*f4b3ec61Sdh155122 			    (void *)mi_headp);
824*f4b3ec61Sdh155122 		}
8257c478bd9Sstevel@tonic-gate 		(void) sprintf(strchr(arena_name, '_') + 1, "minor");
8267c478bd9Sstevel@tonic-gate 		mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t));
8277c478bd9Sstevel@tonic-gate 		*mi_headp = (void *)mi_head;
8287c478bd9Sstevel@tonic-gate 		/* Setup doubly linked list */
8297c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_next = &mi_head->mh_o;
8307c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_prev = &mi_head->mh_o;
8317c478bd9Sstevel@tonic-gate 		mi_head->mh_o.mi_o_dev = 0;	/* For asserts only */
8327c478bd9Sstevel@tonic-gate 		mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name,
8337c478bd9Sstevel@tonic-gate 		    INET_MIN_DEV, KM_SLEEP);
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 	ASSERT(ptr != NULL);
8367c478bd9Sstevel@tonic-gate 	mi_o = (MI_OP)ptr;
8377c478bd9Sstevel@tonic-gate 	mi_o--;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	if (sflag == MODOPEN) {
8407c478bd9Sstevel@tonic-gate 		devp = NULL;
8417c478bd9Sstevel@tonic-gate 		/*
8427c478bd9Sstevel@tonic-gate 		 * Set device number to MAXMIN + incrementing number.
8437c478bd9Sstevel@tonic-gate 		 */
8447c478bd9Sstevel@tonic-gate 		dev = MAXMIN + ++mi_head->mh_module_dev;
8457c478bd9Sstevel@tonic-gate 		/* check for wraparound */
8467c478bd9Sstevel@tonic-gate 		if (dev <= MAXMIN) {
8477c478bd9Sstevel@tonic-gate 			dev = MAXMIN + 1;
8487c478bd9Sstevel@tonic-gate 			mi_head->mh_module_dev = 1;
8497c478bd9Sstevel@tonic-gate 		}
8507c478bd9Sstevel@tonic-gate 	} else if (devp == NULL) {
8517c478bd9Sstevel@tonic-gate 		/* Detached open */
8527c478bd9Sstevel@tonic-gate 		dev = (dev_t)OPENFAIL;
8537c478bd9Sstevel@tonic-gate 	} else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) {
8547c478bd9Sstevel@tonic-gate 		return (EBUSY);
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	mi_o->mi_o_dev = dev;
8587c478bd9Sstevel@tonic-gate 	insert = (&mi_head->mh_o);
8597c478bd9Sstevel@tonic-gate 	mi_o->mi_o_next = insert;
8607c478bd9Sstevel@tonic-gate 	insert->mi_o_prev->mi_o_next = mi_o;
8617c478bd9Sstevel@tonic-gate 	mi_o->mi_o_prev = insert->mi_o_prev;
8627c478bd9Sstevel@tonic-gate 	insert->mi_o_prev = mi_o;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	if (sflag == MODOPEN)
8657c478bd9Sstevel@tonic-gate 		mi_o->mi_o_isdev = B_FALSE;
8667c478bd9Sstevel@tonic-gate 	else
8677c478bd9Sstevel@tonic-gate 		mi_o->mi_o_isdev = B_TRUE;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (devp)
8707c478bd9Sstevel@tonic-gate 		*devp = makedevice(getemajor(*devp), (minor_t)dev);
8717c478bd9Sstevel@tonic-gate 	return (0);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate uint8_t *
8757c478bd9Sstevel@tonic-gate mi_offset_param(mblk_t *mp, size_t offset, size_t len)
8767c478bd9Sstevel@tonic-gate {
8777c478bd9Sstevel@tonic-gate 	size_t	msg_len;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	if (!mp)
8807c478bd9Sstevel@tonic-gate 		return (NULL);
8817c478bd9Sstevel@tonic-gate 	msg_len = mp->b_wptr - mp->b_rptr;
8827c478bd9Sstevel@tonic-gate 	if (msg_len == 0 || offset > msg_len || len > msg_len ||
8837c478bd9Sstevel@tonic-gate 	    (offset + len) > msg_len || len == 0)
8847c478bd9Sstevel@tonic-gate 		return (NULL);
8857c478bd9Sstevel@tonic-gate 	return (&mp->b_rptr[offset]);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate uint8_t *
8897c478bd9Sstevel@tonic-gate mi_offset_paramc(mblk_t *mp, size_t offset, size_t len)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	uint8_t	*param;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	for (; mp; mp = mp->b_cont) {
8947c478bd9Sstevel@tonic-gate 		int type = mp->b_datap->db_type;
8957c478bd9Sstevel@tonic-gate 		if (datamsg(type)) {
8967c478bd9Sstevel@tonic-gate 			if (param = mi_offset_param(mp, offset, len))
8977c478bd9Sstevel@tonic-gate 				return (param);
8987c478bd9Sstevel@tonic-gate 			if (offset < mp->b_wptr - mp->b_rptr)
8997c478bd9Sstevel@tonic-gate 				break;
9007c478bd9Sstevel@tonic-gate 			offset -= mp->b_wptr - mp->b_rptr;
9017c478bd9Sstevel@tonic-gate 		}
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 	return (NULL);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate boolean_t
9087c478bd9Sstevel@tonic-gate mi_set_sth_hiwat(queue_t *q, size_t size)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate 	MBLKP	mp;
9117c478bd9Sstevel@tonic-gate 	STROPTP stropt;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
9147c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9157c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
9167c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
9177c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
9187c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_HIWAT;
9197c478bd9Sstevel@tonic-gate 	stropt->so_hiwat = size;
9207c478bd9Sstevel@tonic-gate 	putnext(q, mp);
9217c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate boolean_t
9257c478bd9Sstevel@tonic-gate mi_set_sth_lowat(queue_t *q, size_t size)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	MBLKP	mp;
9287c478bd9Sstevel@tonic-gate 	STROPTP stropt;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
9317c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9327c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
9337c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
9347c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
9357c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_LOWAT;
9367c478bd9Sstevel@tonic-gate 	stropt->so_lowat = size;
9377c478bd9Sstevel@tonic-gate 	putnext(q, mp);
9387c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate /* ARGSUSED */
9427c478bd9Sstevel@tonic-gate boolean_t
9437c478bd9Sstevel@tonic-gate mi_set_sth_maxblk(queue_t *q, ssize_t size)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	MBLKP	mp;
9467c478bd9Sstevel@tonic-gate 	STROPTP stropt;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
9497c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9507c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
9517c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
9527c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
9537c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_MAXBLK;
9547c478bd9Sstevel@tonic-gate 	stropt->so_maxblk = size;
9557c478bd9Sstevel@tonic-gate 	putnext(q, mp);
9567c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate boolean_t
9607c478bd9Sstevel@tonic-gate mi_set_sth_copyopt(queue_t *q, int copyopt)
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate 	MBLKP	mp;
9637c478bd9Sstevel@tonic-gate 	STROPTP stropt;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
9667c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9677c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
9687c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
9697c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
9707c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_COPYOPT;
9717c478bd9Sstevel@tonic-gate 	stropt->so_copyopt = (ushort_t)copyopt;
9727c478bd9Sstevel@tonic-gate 	putnext(q, mp);
9737c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate boolean_t
9777c478bd9Sstevel@tonic-gate mi_set_sth_wroff(queue_t *q, size_t size)
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	MBLKP	mp;
9807c478bd9Sstevel@tonic-gate 	STROPTP stropt;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
9837c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9847c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_SETOPTS;
9857c478bd9Sstevel@tonic-gate 	mp->b_wptr += sizeof (*stropt);
9867c478bd9Sstevel@tonic-gate 	stropt = (STROPTP)mp->b_rptr;
9877c478bd9Sstevel@tonic-gate 	stropt->so_flags = SO_WROFF;
9887c478bd9Sstevel@tonic-gate 	stropt->so_wroff = (ushort_t)size;
9897c478bd9Sstevel@tonic-gate 	putnext(q, mp);
9907c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9917c478bd9Sstevel@tonic-gate }
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate int
9947c478bd9Sstevel@tonic-gate mi_sprintf(char *buf, char *fmt, ...)
9957c478bd9Sstevel@tonic-gate {
9967c478bd9Sstevel@tonic-gate 	va_list	ap;
9977c478bd9Sstevel@tonic-gate 	int	count = -1;
9987c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
9997c478bd9Sstevel@tonic-gate 	if (buf) {
10007c478bd9Sstevel@tonic-gate 		count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc,
10017c478bd9Sstevel@tonic-gate 		    (char *)&buf);
10027c478bd9Sstevel@tonic-gate 		if (count != -1)
10037c478bd9Sstevel@tonic-gate 			(void) mi_sprintf_putc((char *)&buf, '\0');
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 	va_end(ap);
10067c478bd9Sstevel@tonic-gate 	return (count);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate /* Used to count without writing data */
10107c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
10117c478bd9Sstevel@tonic-gate static int
10127c478bd9Sstevel@tonic-gate mi_sprintf_noop(char *cookie, int ch)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate 	char	**cpp = (char **)cookie;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	(*cpp)++;
10177c478bd9Sstevel@tonic-gate 	return (1);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate int
10217c478bd9Sstevel@tonic-gate mi_sprintf_putc(char *cookie, int ch)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	char	**cpp = (char **)cookie;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	**cpp = (char)ch;
10267c478bd9Sstevel@tonic-gate 	(*cpp)++;
10277c478bd9Sstevel@tonic-gate 	return (1);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate int
10317c478bd9Sstevel@tonic-gate mi_strcmp(const char *cp1, const char *cp2)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	while (*cp1++ == *cp2++) {
10347c478bd9Sstevel@tonic-gate 		if (!cp2[-1])
10357c478bd9Sstevel@tonic-gate 			return (0);
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 	return ((uint_t)cp2[-1]  & 0xFF) - ((uint_t)cp1[-1] & 0xFF);
10387c478bd9Sstevel@tonic-gate }
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate size_t
10417c478bd9Sstevel@tonic-gate mi_strlen(const char *str)
10427c478bd9Sstevel@tonic-gate {
10437c478bd9Sstevel@tonic-gate 	const char *cp = str;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	while (*cp != '\0')
10467c478bd9Sstevel@tonic-gate 		cp++;
10477c478bd9Sstevel@tonic-gate 	return ((int)(cp - str));
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate int
10517c478bd9Sstevel@tonic-gate mi_strlog(queue_t *q, char level, ushort_t flags, char *fmt, ...)
10527c478bd9Sstevel@tonic-gate {
10537c478bd9Sstevel@tonic-gate 	va_list	ap;
10547c478bd9Sstevel@tonic-gate 	char	buf[200];
10557c478bd9Sstevel@tonic-gate 	char	*alloc_buf = buf;
10567c478bd9Sstevel@tonic-gate 	int	count = -1;
10577c478bd9Sstevel@tonic-gate 	char	*cp;
10587c478bd9Sstevel@tonic-gate 	short	mid;
10597c478bd9Sstevel@tonic-gate 	int	ret;
10607c478bd9Sstevel@tonic-gate 	short	sid;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	sid = 0;
10637c478bd9Sstevel@tonic-gate 	mid = 0;
10647c478bd9Sstevel@tonic-gate 	if (q != NULL) {
10657c478bd9Sstevel@tonic-gate 		mid = q->q_qinfo->qi_minfo->mi_idnum;
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	/* Find out how many bytes we need and allocate if necesary */
10697c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
10707c478bd9Sstevel@tonic-gate 	cp = buf;
10717c478bd9Sstevel@tonic-gate 	count = mi_iprintf(fmt, ap, mi_sprintf_noop, (char *)&cp);
10727c478bd9Sstevel@tonic-gate 	if (count > sizeof (buf) &&
10737c478bd9Sstevel@tonic-gate 	    !(alloc_buf = mi_alloc((uint_t)count + 2, BPRI_MED))) {
10747c478bd9Sstevel@tonic-gate 		va_end(ap);
10757c478bd9Sstevel@tonic-gate 		return (-1);
10767c478bd9Sstevel@tonic-gate 	}
10777c478bd9Sstevel@tonic-gate 	va_end(ap);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
10807c478bd9Sstevel@tonic-gate 	cp = alloc_buf;
10817c478bd9Sstevel@tonic-gate 	count = mi_iprintf(fmt, ap, mi_sprintf_putc, (char *)&cp);
10827c478bd9Sstevel@tonic-gate 	if (count != -1)
10837c478bd9Sstevel@tonic-gate 		(void) mi_sprintf_putc((char *)&cp, '\0');
10847c478bd9Sstevel@tonic-gate 	else
10857c478bd9Sstevel@tonic-gate 		alloc_buf[0] = '\0';
10867c478bd9Sstevel@tonic-gate 	va_end(ap);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	ret = strlog(mid, sid, level, flags, alloc_buf);
10897c478bd9Sstevel@tonic-gate 	if (alloc_buf != buf)
10907c478bd9Sstevel@tonic-gate 		mi_free(alloc_buf);
10917c478bd9Sstevel@tonic-gate 	return (ret);
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate long
10957c478bd9Sstevel@tonic-gate mi_strtol(const char *str, char **ptr, int base)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate 	const char *cp;
10987c478bd9Sstevel@tonic-gate 	int	digits;
10997c478bd9Sstevel@tonic-gate 	long	value;
11007c478bd9Sstevel@tonic-gate 	boolean_t	is_negative;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	cp = str;
11037c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t' || *cp == '\n')
11047c478bd9Sstevel@tonic-gate 		cp++;
11057c478bd9Sstevel@tonic-gate 	is_negative = (*cp == '-');
11067c478bd9Sstevel@tonic-gate 	if (is_negative)
11077c478bd9Sstevel@tonic-gate 		cp++;
11087c478bd9Sstevel@tonic-gate 	if (base == 0) {
11097c478bd9Sstevel@tonic-gate 		base = 10;
11107c478bd9Sstevel@tonic-gate 		if (*cp == '0') {
11117c478bd9Sstevel@tonic-gate 			base = 8;
11127c478bd9Sstevel@tonic-gate 			cp++;
11137c478bd9Sstevel@tonic-gate 			if (*cp == 'x' || *cp == 'X') {
11147c478bd9Sstevel@tonic-gate 				base = 16;
11157c478bd9Sstevel@tonic-gate 				cp++;
11167c478bd9Sstevel@tonic-gate 			}
11177c478bd9Sstevel@tonic-gate 		}
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 	value = 0;
11207c478bd9Sstevel@tonic-gate 	for (; *cp != '\0'; cp++) {
11217c478bd9Sstevel@tonic-gate 		if (*cp >= '0' && *cp <= '9')
11227c478bd9Sstevel@tonic-gate 			digits = *cp - '0';
11237c478bd9Sstevel@tonic-gate 		else if (*cp >= 'a' && *cp <= 'f')
11247c478bd9Sstevel@tonic-gate 			digits = *cp - 'a' + 10;
11257c478bd9Sstevel@tonic-gate 		else if (*cp >= 'A' && *cp <= 'F')
11267c478bd9Sstevel@tonic-gate 			digits = *cp - 'A' + 10;
11277c478bd9Sstevel@tonic-gate 		else
11287c478bd9Sstevel@tonic-gate 			break;
11297c478bd9Sstevel@tonic-gate 		if (digits >= base)
11307c478bd9Sstevel@tonic-gate 			break;
11317c478bd9Sstevel@tonic-gate 		value = (value * base) + digits;
11327c478bd9Sstevel@tonic-gate 	}
11337c478bd9Sstevel@tonic-gate 	/* Note: we cast away const here deliberately */
11347c478bd9Sstevel@tonic-gate 	if (ptr != NULL)
11357c478bd9Sstevel@tonic-gate 		*ptr = (char *)cp;
11367c478bd9Sstevel@tonic-gate 	if (is_negative)
11377c478bd9Sstevel@tonic-gate 		value = -value;
11387c478bd9Sstevel@tonic-gate 	return (value);
11397c478bd9Sstevel@tonic-gate }
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate /*
11427c478bd9Sstevel@tonic-gate  *		mi_timer mechanism.
11437c478bd9Sstevel@tonic-gate  *
11447c478bd9Sstevel@tonic-gate  * Each timer is represented by a timer mblk and a (streams) queue. When the
11457c478bd9Sstevel@tonic-gate  * timer fires the timer mblk will be put on the associated streams queue
11467c478bd9Sstevel@tonic-gate  * so that the streams module can process the timer even in its service
11477c478bd9Sstevel@tonic-gate  * procedure.
11487c478bd9Sstevel@tonic-gate  *
11497c478bd9Sstevel@tonic-gate  * The interface consists of 4 entry points:
11507c478bd9Sstevel@tonic-gate  *	mi_timer_alloc		- create a timer mblk
11517c478bd9Sstevel@tonic-gate  *	mi_timer_free		- free a timer mblk
11527c478bd9Sstevel@tonic-gate  *	mi_timer		- start, restart, stop, or move the
11537c478bd9Sstevel@tonic-gate  *				  timer to a different queue
11547c478bd9Sstevel@tonic-gate  *	mi_timer_valid		- called by streams module to verify that
11557c478bd9Sstevel@tonic-gate  *				  the timer did indeed fire.
11567c478bd9Sstevel@tonic-gate  */
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate /*
11627c478bd9Sstevel@tonic-gate  * Start, restart, stop, or move the timer to a new queue.
11637c478bd9Sstevel@tonic-gate  * If "tim" is -2 the timer is moved to a different queue.
11647c478bd9Sstevel@tonic-gate  * If "tim" is -1 the timer is stopped.
11657c478bd9Sstevel@tonic-gate  * Otherwise, the timer is stopped if it is already running, and
11667c478bd9Sstevel@tonic-gate  * set to fire tim milliseconds from now.
11677c478bd9Sstevel@tonic-gate  */
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate void
11707c478bd9Sstevel@tonic-gate mi_timer(queue_t *q, MBLKP mp, clock_t tim)
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate 	MTBP	mtb;
11737c478bd9Sstevel@tonic-gate 	int	state;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	ASSERT(tim >= -2);
11767c478bd9Sstevel@tonic-gate 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
11777c478bd9Sstevel@tonic-gate 		return;
11787c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
11797c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
11807c478bd9Sstevel@tonic-gate 	if (tim >= 0) {
11817c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
11827c478bd9Sstevel@tonic-gate 		state = mtb->mtb_state;
11837c478bd9Sstevel@tonic-gate 		tim = MSEC_TO_TICK(tim);
11847c478bd9Sstevel@tonic-gate 		if (state == TB_RUNNING) {
11857c478bd9Sstevel@tonic-gate 			if (untimeout(mtb->mtb_tid) < 0) {
11867c478bd9Sstevel@tonic-gate 				/* Message has already been putq */
11877c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
11887c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
11897c478bd9Sstevel@tonic-gate 				mtb->mtb_state = TB_RESCHED;
11907c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
11917c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
11927c478bd9Sstevel@tonic-gate 				return;
11937c478bd9Sstevel@tonic-gate 			}
11947c478bd9Sstevel@tonic-gate 		} else if (state != TB_IDLE) {
11957c478bd9Sstevel@tonic-gate 			ASSERT(state != TB_TO_BE_FREED);
11967c478bd9Sstevel@tonic-gate 			if (state == TB_CANCELLED) {
11977c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
11987c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
11997c478bd9Sstevel@tonic-gate 				mtb->mtb_state = TB_RESCHED;
12007c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
12017c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
12027c478bd9Sstevel@tonic-gate 				return;
12037c478bd9Sstevel@tonic-gate 			}
12047c478bd9Sstevel@tonic-gate 			if (state == TB_RESCHED) {
12057c478bd9Sstevel@tonic-gate 				ASSERT(mtb->mtb_q->q_first == mp ||
12067c478bd9Sstevel@tonic-gate 				    mp->b_prev || mp->b_next);
12077c478bd9Sstevel@tonic-gate 				mtb->mtb_time_left = tim;
12087c478bd9Sstevel@tonic-gate 				/* mi_timer_valid will start timer */
12097c478bd9Sstevel@tonic-gate 				return;
12107c478bd9Sstevel@tonic-gate 			}
12117c478bd9Sstevel@tonic-gate 		}
12127c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_RUNNING;
12137c478bd9Sstevel@tonic-gate 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
12147c478bd9Sstevel@tonic-gate 		return;
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 	switch (tim) {
12177c478bd9Sstevel@tonic-gate 	case -1:
12187c478bd9Sstevel@tonic-gate 		mi_timer_stop(mp);
12197c478bd9Sstevel@tonic-gate 		break;
12207c478bd9Sstevel@tonic-gate 	case -2:
12217c478bd9Sstevel@tonic-gate 		mi_timer_move(q, mp);
12227c478bd9Sstevel@tonic-gate 		break;
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate }
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate /*
12277c478bd9Sstevel@tonic-gate  * Allocate an M_PCSIG timer message. The space between db_base and
12287c478bd9Sstevel@tonic-gate  * b_rptr is used by the mi_timer mechanism, and after b_rptr there are
12297c478bd9Sstevel@tonic-gate  * "size" bytes that the caller can use for its own purposes.
12307c478bd9Sstevel@tonic-gate  *
12317c478bd9Sstevel@tonic-gate  * Note that db_type has to be a priority message since otherwise
12327c478bd9Sstevel@tonic-gate  * the putq will not cause the service procedure to run when
12337c478bd9Sstevel@tonic-gate  * there is flow control.
12347c478bd9Sstevel@tonic-gate  */
12357c478bd9Sstevel@tonic-gate MBLKP
12367c478bd9Sstevel@tonic-gate mi_timer_alloc(size_t size)
12377c478bd9Sstevel@tonic-gate {
12387c478bd9Sstevel@tonic-gate 	MBLKP	mp;
12397c478bd9Sstevel@tonic-gate 	MTBP	mtb;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size + sizeof (MTB), BPRI_HI)) != NULL) {
12427c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PCSIG;
12437c478bd9Sstevel@tonic-gate 		mtb = (MTBP)mp->b_datap->db_base;
12447c478bd9Sstevel@tonic-gate 		mp->b_rptr = (uchar_t *)&mtb[1];
12457c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + size;
12467c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_IDLE;
12477c478bd9Sstevel@tonic-gate 		mtb->mtb_mp = mp;
12487c478bd9Sstevel@tonic-gate 		mtb->mtb_q = NULL;
12497c478bd9Sstevel@tonic-gate 		return (mp);
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 	return (NULL);
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate /*
12557c478bd9Sstevel@tonic-gate  * timeout() callback function.
12567c478bd9Sstevel@tonic-gate  * Put the message on the current queue.
12577c478bd9Sstevel@tonic-gate  * If the timer is stopped or moved to a different queue after
12587c478bd9Sstevel@tonic-gate  * it has fired then mi_timer() and mi_timer_valid() will clean
12597c478bd9Sstevel@tonic-gate  * things up.
12607c478bd9Sstevel@tonic-gate  */
12617c478bd9Sstevel@tonic-gate static int
12627c478bd9Sstevel@tonic-gate mi_timer_fire(MTBP mtb)
12637c478bd9Sstevel@tonic-gate {
12647c478bd9Sstevel@tonic-gate 	ASSERT(mtb == (MTBP)mtb->mtb_mp->b_datap->db_base);
12657c478bd9Sstevel@tonic-gate 	ASSERT(mtb->mtb_mp->b_datap->db_type == M_PCSIG);
12667c478bd9Sstevel@tonic-gate 	return (putq(mtb->mtb_q, mtb->mtb_mp));
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate /*
12707c478bd9Sstevel@tonic-gate  * Logically free a timer mblk (that might have a pending timeout().)
12717c478bd9Sstevel@tonic-gate  * If the timer has fired and the mblk has been put on the queue then
12727c478bd9Sstevel@tonic-gate  * mi_timer_valid will free the mblk.
12737c478bd9Sstevel@tonic-gate  */
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate void
12767c478bd9Sstevel@tonic-gate mi_timer_free(MBLKP mp)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate 	MTBP	mtb;
12797c478bd9Sstevel@tonic-gate 	int	state;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
12827c478bd9Sstevel@tonic-gate 		return;
12837c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
12847c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
12857c478bd9Sstevel@tonic-gate 	if (state == TB_RUNNING) {
12867c478bd9Sstevel@tonic-gate 		if (untimeout(mtb->mtb_tid) < 0) {
12877c478bd9Sstevel@tonic-gate 			/* Message has already been putq */
12887c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
12897c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
12907c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_TO_BE_FREED;
12917c478bd9Sstevel@tonic-gate 			/* mi_timer_valid will free the mblk */
12927c478bd9Sstevel@tonic-gate 			return;
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 	} else if (state != TB_IDLE) {
12957c478bd9Sstevel@tonic-gate 		/* Message has already been putq */
12967c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
12977c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
12987c478bd9Sstevel@tonic-gate 		ASSERT(state != TB_TO_BE_FREED);
12997c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_TO_BE_FREED;
13007c478bd9Sstevel@tonic-gate 		/* mi_timer_valid will free the mblk */
13017c478bd9Sstevel@tonic-gate 		return;
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 	ASSERT(mtb->mtb_q ==  NULL || mtb->mtb_q->q_first != mp);
13047c478bd9Sstevel@tonic-gate 	freemsg(mp);
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate /*
13087c478bd9Sstevel@tonic-gate  * Called from mi_timer(,,-2)
13097c478bd9Sstevel@tonic-gate  */
13107c478bd9Sstevel@tonic-gate void
13117c478bd9Sstevel@tonic-gate mi_timer_move(queue_t *q, MBLKP mp)
13127c478bd9Sstevel@tonic-gate {
13137c478bd9Sstevel@tonic-gate 	MTBP	mtb;
13147c478bd9Sstevel@tonic-gate 	clock_t	tim;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
13177c478bd9Sstevel@tonic-gate 		return;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
13207c478bd9Sstevel@tonic-gate 	/*
13217c478bd9Sstevel@tonic-gate 	 * Need to untimeout and restart to make
13227c478bd9Sstevel@tonic-gate 	 * sure that the mblk is not about to be putq on the old queue
13237c478bd9Sstevel@tonic-gate 	 * by mi_timer_fire.
13247c478bd9Sstevel@tonic-gate 	 */
13257c478bd9Sstevel@tonic-gate 	if (mtb->mtb_state == TB_RUNNING) {
13267c478bd9Sstevel@tonic-gate 		if ((tim = untimeout(mtb->mtb_tid)) < 0) {
13277c478bd9Sstevel@tonic-gate 			/*
13287c478bd9Sstevel@tonic-gate 			 * Message has already been putq. Move from old queue
13297c478bd9Sstevel@tonic-gate 			 * to new queue.
13307c478bd9Sstevel@tonic-gate 			 */
13317c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
13327c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
13337c478bd9Sstevel@tonic-gate 			rmvq(mtb->mtb_q, mp);
13347c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first != mp &&
13357c478bd9Sstevel@tonic-gate 			    mp->b_prev == NULL && mp->b_next == NULL);
13367c478bd9Sstevel@tonic-gate 			mtb->mtb_q = q;
13377c478bd9Sstevel@tonic-gate 			(void) putq(mtb->mtb_q, mp);
13387c478bd9Sstevel@tonic-gate 			return;
13397c478bd9Sstevel@tonic-gate 		}
13407c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
13417c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_RUNNING;
13427c478bd9Sstevel@tonic-gate 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
13437c478bd9Sstevel@tonic-gate 	} else if (mtb->mtb_state != TB_IDLE) {
13447c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_state != TB_TO_BE_FREED);
13457c478bd9Sstevel@tonic-gate 		/*
13467c478bd9Sstevel@tonic-gate 		 * Message is already sitting on queue. Move to new queue.
13477c478bd9Sstevel@tonic-gate 		 */
13487c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
13497c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
13507c478bd9Sstevel@tonic-gate 		rmvq(mtb->mtb_q, mp);
13517c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first != mp &&
13527c478bd9Sstevel@tonic-gate 		    mp->b_prev == NULL && mp->b_next == NULL);
13537c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
13547c478bd9Sstevel@tonic-gate 		(void) putq(mtb->mtb_q, mp);
13557c478bd9Sstevel@tonic-gate 	} else
13567c478bd9Sstevel@tonic-gate 		mtb->mtb_q = q;
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate /*
13607c478bd9Sstevel@tonic-gate  * Called from mi_timer(,,-1)
13617c478bd9Sstevel@tonic-gate  */
13627c478bd9Sstevel@tonic-gate void
13637c478bd9Sstevel@tonic-gate mi_timer_stop(MBLKP mp)
13647c478bd9Sstevel@tonic-gate {
13657c478bd9Sstevel@tonic-gate 	MTBP	mtb;
13667c478bd9Sstevel@tonic-gate 	int	state;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
13697c478bd9Sstevel@tonic-gate 		return;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
13727c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
13737c478bd9Sstevel@tonic-gate 	if (state == TB_RUNNING) {
13747c478bd9Sstevel@tonic-gate 		if (untimeout(mtb->mtb_tid) < 0) {
13757c478bd9Sstevel@tonic-gate 			/* Message has already been putq */
13767c478bd9Sstevel@tonic-gate 			ASSERT(mtb->mtb_q->q_first == mp ||
13777c478bd9Sstevel@tonic-gate 			    mp->b_prev || mp->b_next);
13787c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_CANCELLED;
13797c478bd9Sstevel@tonic-gate 		} else {
13807c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_IDLE;
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 	} else if (state == TB_RESCHED) {
13837c478bd9Sstevel@tonic-gate 		ASSERT(mtb->mtb_q->q_first == mp ||
13847c478bd9Sstevel@tonic-gate 		    mp->b_prev || mp->b_next);
13857c478bd9Sstevel@tonic-gate 		mtb->mtb_state = TB_CANCELLED;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate /*
13907c478bd9Sstevel@tonic-gate  * The user of the mi_timer mechanism is required to call mi_timer_valid() for
13917c478bd9Sstevel@tonic-gate  * each M_PCSIG message processed in the service procedures.
13927c478bd9Sstevel@tonic-gate  * mi_timer_valid will return "true" if the timer actually did fire.
13937c478bd9Sstevel@tonic-gate  */
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate boolean_t
13967c478bd9Sstevel@tonic-gate mi_timer_valid(MBLKP mp)
13977c478bd9Sstevel@tonic-gate {
13987c478bd9Sstevel@tonic-gate 	MTBP	mtb;
13997c478bd9Sstevel@tonic-gate 	int	state;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB) ||
14027c478bd9Sstevel@tonic-gate 	    mp->b_datap->db_type != M_PCSIG)
14037c478bd9Sstevel@tonic-gate 		return (B_FALSE);
14047c478bd9Sstevel@tonic-gate 	mtb = (MTBP)mp->b_datap->db_base;
14057c478bd9Sstevel@tonic-gate 	state = mtb->mtb_state;
14067c478bd9Sstevel@tonic-gate 	if (state != TB_RUNNING) {
14077c478bd9Sstevel@tonic-gate 		ASSERT(state != TB_IDLE);
14087c478bd9Sstevel@tonic-gate 		if (state == TB_TO_BE_FREED) {
14097c478bd9Sstevel@tonic-gate 			/*
14107c478bd9Sstevel@tonic-gate 			 * mi_timer_free was called after the message
14117c478bd9Sstevel@tonic-gate 			 * was putq'ed.
14127c478bd9Sstevel@tonic-gate 			 */
14137c478bd9Sstevel@tonic-gate 			freemsg(mp);
14147c478bd9Sstevel@tonic-gate 			return (B_FALSE);
14157c478bd9Sstevel@tonic-gate 		}
14167c478bd9Sstevel@tonic-gate 		if (state == TB_CANCELLED) {
14177c478bd9Sstevel@tonic-gate 			/* The timer was stopped after the mblk was putq'ed */
14187c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_IDLE;
14197c478bd9Sstevel@tonic-gate 			return (B_FALSE);
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 		if (state == TB_RESCHED) {
14227c478bd9Sstevel@tonic-gate 			/*
14237c478bd9Sstevel@tonic-gate 			 * The timer was stopped and then restarted after
14247c478bd9Sstevel@tonic-gate 			 * the mblk was putq'ed.
14257c478bd9Sstevel@tonic-gate 			 * mtb_time_left contains the number of ticks that
14267c478bd9Sstevel@tonic-gate 			 * the timer was restarted with.
14277c478bd9Sstevel@tonic-gate 			 */
14287c478bd9Sstevel@tonic-gate 			mtb->mtb_state = TB_RUNNING;
14297c478bd9Sstevel@tonic-gate 			mtb->mtb_tid = timeout((pfv_t)mi_timer_fire,
14307c478bd9Sstevel@tonic-gate 			    mtb, mtb->mtb_time_left);
14317c478bd9Sstevel@tonic-gate 			return (B_FALSE);
14327c478bd9Sstevel@tonic-gate 		}
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 	mtb->mtb_state = TB_IDLE;
14357c478bd9Sstevel@tonic-gate 	return (B_TRUE);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate static void
14397c478bd9Sstevel@tonic-gate mi_tpi_addr_and_opt(MBLKP mp, char *addr, t_scalar_t addr_length,
14407c478bd9Sstevel@tonic-gate     char *opt, t_scalar_t opt_length)
14417c478bd9Sstevel@tonic-gate {
14427c478bd9Sstevel@tonic-gate 	struct T_unitdata_ind	*tudi;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	/*
14457c478bd9Sstevel@tonic-gate 	 * This code is used more than just for unitdata ind
14467c478bd9Sstevel@tonic-gate 	 * (also for T_CONN_IND and T_CONN_CON) and
14477c478bd9Sstevel@tonic-gate 	 * relies on correct functioning on the happy
14487c478bd9Sstevel@tonic-gate 	 * coincidence that the the address and option buffers
14497c478bd9Sstevel@tonic-gate 	 * represented by length/offset in all these primitives
14507c478bd9Sstevel@tonic-gate 	 * are isomorphic in terms of offset from start of data
14517c478bd9Sstevel@tonic-gate 	 * structure
14527c478bd9Sstevel@tonic-gate 	 */
14537c478bd9Sstevel@tonic-gate 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
14547c478bd9Sstevel@tonic-gate 	tudi->SRC_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
14557c478bd9Sstevel@tonic-gate 	tudi->SRC_length = addr_length;
14567c478bd9Sstevel@tonic-gate 	if (addr_length > 0) {
14577c478bd9Sstevel@tonic-gate 		bcopy(addr, (char *)mp->b_wptr, addr_length);
14587c478bd9Sstevel@tonic-gate 		mp->b_wptr += addr_length;
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 	tudi->OPT_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
14617c478bd9Sstevel@tonic-gate 	tudi->OPT_length = opt_length;
14627c478bd9Sstevel@tonic-gate 	if (opt_length > 0) {
14637c478bd9Sstevel@tonic-gate 		bcopy(opt, (char *)mp->b_wptr, opt_length);
14647c478bd9Sstevel@tonic-gate 		mp->b_wptr += opt_length;
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate }
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate MBLKP
14697c478bd9Sstevel@tonic-gate mi_tpi_conn_con(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
14707c478bd9Sstevel@tonic-gate     t_scalar_t opt_length)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate 	size_t	len;
14737c478bd9Sstevel@tonic-gate 	MBLKP	mp;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_conn_con) + src_length + opt_length;
14767c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_CON)) != NULL) {
14777c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_con)];
14787c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 	return (mp);
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate MBLKP
14847c478bd9Sstevel@tonic-gate mi_tpi_conn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
14857c478bd9Sstevel@tonic-gate     t_scalar_t opt_length, t_scalar_t seqnum)
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate 	size_t	len;
14887c478bd9Sstevel@tonic-gate 	MBLKP	mp;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_conn_ind) + src_length + opt_length;
14917c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_IND)) != NULL) {
14927c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_ind)];
14937c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
14947c478bd9Sstevel@tonic-gate 		((struct T_conn_ind *)mp->b_rptr)->SEQ_number = seqnum;
14957c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 	return (mp);
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate MBLKP
15017c478bd9Sstevel@tonic-gate mi_tpi_extconn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length,
15027c478bd9Sstevel@tonic-gate     char *opt, t_scalar_t opt_length, char *dst, t_scalar_t dst_length,
15037c478bd9Sstevel@tonic-gate     t_scalar_t seqnum)
15047c478bd9Sstevel@tonic-gate {
15057c478bd9Sstevel@tonic-gate 	size_t	len;
15067c478bd9Sstevel@tonic-gate 	MBLKP	mp;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_extconn_ind) + src_length + opt_length +
15097c478bd9Sstevel@tonic-gate 	    dst_length;
15107c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_EXTCONN_IND)) !=
15117c478bd9Sstevel@tonic-gate 	    NULL) {
15127c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_extconn_ind)];
15137c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
15147c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->DEST_length = dst_length;
15157c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->DEST_offset =
15167c478bd9Sstevel@tonic-gate 			(t_scalar_t)(mp->b_wptr - mp->b_rptr);
15177c478bd9Sstevel@tonic-gate 		if (dst_length > 0) {
15187c478bd9Sstevel@tonic-gate 			bcopy(dst, (char *)mp->b_wptr, dst_length);
15197c478bd9Sstevel@tonic-gate 			mp->b_wptr += dst_length;
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 		((struct T_extconn_ind *)mp->b_rptr)->SEQ_number = seqnum;
15227c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 	return (mp);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate MBLKP
15287c478bd9Sstevel@tonic-gate mi_tpi_discon_ind(MBLKP trailer_mp, t_scalar_t reason, t_scalar_t seqnum)
15297c478bd9Sstevel@tonic-gate {
15307c478bd9Sstevel@tonic-gate 	MBLKP	mp;
15317c478bd9Sstevel@tonic-gate 	struct T_discon_ind	*tdi;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_trailer_alloc(trailer_mp,
15347c478bd9Sstevel@tonic-gate 	    sizeof (struct T_discon_ind), T_DISCON_IND)) != NULL) {
15357c478bd9Sstevel@tonic-gate 		tdi = (struct T_discon_ind *)mp->b_rptr;
15367c478bd9Sstevel@tonic-gate 		tdi->DISCON_reason = reason;
15377c478bd9Sstevel@tonic-gate 		tdi->SEQ_number = seqnum;
15387c478bd9Sstevel@tonic-gate 	}
15397c478bd9Sstevel@tonic-gate 	return (mp);
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate /*
15437c478bd9Sstevel@tonic-gate  * Allocate and fill in a TPI err ack packet using the 'mp' passed in
15447c478bd9Sstevel@tonic-gate  * for the 'error_prim' context as well as sacrifice.
15457c478bd9Sstevel@tonic-gate  */
15467c478bd9Sstevel@tonic-gate MBLKP
15477c478bd9Sstevel@tonic-gate mi_tpi_err_ack_alloc(MBLKP mp, t_scalar_t tlierr, int unixerr)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate 	struct T_error_ack	*teackp;
15507c478bd9Sstevel@tonic-gate 	t_scalar_t error_prim;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	if (!mp)
15537c478bd9Sstevel@tonic-gate 		return (NULL);
15547c478bd9Sstevel@tonic-gate 	error_prim = ((TPRIMP)mp->b_rptr)->type;
15557c478bd9Sstevel@tonic-gate 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack),
15567c478bd9Sstevel@tonic-gate 	    M_PCPROTO, T_ERROR_ACK)) != NULL) {
15577c478bd9Sstevel@tonic-gate 		teackp = (struct T_error_ack *)mp->b_rptr;
15587c478bd9Sstevel@tonic-gate 		teackp->ERROR_prim = error_prim;
15597c478bd9Sstevel@tonic-gate 		teackp->TLI_error = tlierr;
15607c478bd9Sstevel@tonic-gate 		teackp->UNIX_error = unixerr;
15617c478bd9Sstevel@tonic-gate 	}
15627c478bd9Sstevel@tonic-gate 	return (mp);
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate MBLKP
15667c478bd9Sstevel@tonic-gate mi_tpi_ok_ack_alloc_extra(MBLKP mp, int extra)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	t_scalar_t correct_prim;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	if (!mp)
15717c478bd9Sstevel@tonic-gate 		return (NULL);
15727c478bd9Sstevel@tonic-gate 	correct_prim = ((TPRIMP)mp->b_rptr)->type;
15737c478bd9Sstevel@tonic-gate 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack) + extra,
15747c478bd9Sstevel@tonic-gate 	    M_PCPROTO, T_OK_ACK)) != NULL) {
15757c478bd9Sstevel@tonic-gate 		((struct T_ok_ack *)mp->b_rptr)->CORRECT_prim = correct_prim;
15767c478bd9Sstevel@tonic-gate 		mp->b_wptr -= extra;
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate 	return (mp);
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate MBLKP
15827c478bd9Sstevel@tonic-gate mi_tpi_ok_ack_alloc(MBLKP mp)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate 	return (mi_tpi_ok_ack_alloc_extra(mp, 0));
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate MBLKP
15887c478bd9Sstevel@tonic-gate mi_tpi_ordrel_ind(void)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	MBLKP	mp;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if ((mp = allocb(sizeof (struct T_ordrel_ind), BPRI_HI)) != NULL) {
15937c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
15947c478bd9Sstevel@tonic-gate 		((struct T_ordrel_ind *)mp->b_rptr)->PRIM_type = T_ORDREL_IND;
15957c478bd9Sstevel@tonic-gate 		mp->b_wptr += sizeof (struct T_ordrel_ind);
15967c478bd9Sstevel@tonic-gate 	}
15977c478bd9Sstevel@tonic-gate 	return (mp);
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate static MBLKP
16017c478bd9Sstevel@tonic-gate mi_tpi_trailer_alloc(MBLKP trailer_mp, size_t size, t_scalar_t type)
16027c478bd9Sstevel@tonic-gate {
16037c478bd9Sstevel@tonic-gate 	MBLKP	mp;
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size, BPRI_MED)) != NULL) {
16067c478bd9Sstevel@tonic-gate 		mp->b_cont = trailer_mp;
16077c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
16087c478bd9Sstevel@tonic-gate 		((union T_primitives *)mp->b_rptr)->type = type;
16097c478bd9Sstevel@tonic-gate 		mp->b_wptr += size;
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 	return (mp);
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate MBLKP
16157c478bd9Sstevel@tonic-gate mi_tpi_uderror_ind(char *dest, t_scalar_t dest_length, char *opt,
16167c478bd9Sstevel@tonic-gate     t_scalar_t opt_length, t_scalar_t error)
16177c478bd9Sstevel@tonic-gate {
16187c478bd9Sstevel@tonic-gate 	size_t	len;
16197c478bd9Sstevel@tonic-gate 	MBLKP	mp;
16207c478bd9Sstevel@tonic-gate 	struct T_uderror_ind	*tudei;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	len = sizeof (struct T_uderror_ind) + dest_length + opt_length;
16237c478bd9Sstevel@tonic-gate 	if ((mp = allocb(len, BPRI_HI)) != NULL) {
16247c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
16257c478bd9Sstevel@tonic-gate 		tudei = (struct T_uderror_ind *)mp->b_rptr;
16267c478bd9Sstevel@tonic-gate 		tudei->PRIM_type = T_UDERROR_IND;
16277c478bd9Sstevel@tonic-gate 		tudei->ERROR_type = error;
16287c478bd9Sstevel@tonic-gate 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_uderror_ind)];
16297c478bd9Sstevel@tonic-gate 		mi_tpi_addr_and_opt(mp, dest, dest_length, opt, opt_length);
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 	return (mp);
16327c478bd9Sstevel@tonic-gate }
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate IDP
16357c478bd9Sstevel@tonic-gate mi_zalloc(size_t size)
16367c478bd9Sstevel@tonic-gate {
16377c478bd9Sstevel@tonic-gate 	IDP	ptr;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	if (ptr = mi_alloc(size, BPRI_LO))
16407c478bd9Sstevel@tonic-gate 		bzero(ptr, size);
16417c478bd9Sstevel@tonic-gate 	return (ptr);
16427c478bd9Sstevel@tonic-gate }
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate IDP
16457c478bd9Sstevel@tonic-gate mi_zalloc_sleep(size_t size)
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate 	IDP	ptr;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	if (ptr = mi_alloc_sleep(size, BPRI_LO))
16507c478bd9Sstevel@tonic-gate 		bzero(ptr, size);
16517c478bd9Sstevel@tonic-gate 	return (ptr);
16527c478bd9Sstevel@tonic-gate }
1653