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