xref: /titanic_51/usr/src/uts/common/os/ddi.c (revision eb53af1d99d46ca40a06ed10b229d933b2301b49)
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
59acbbeafSnn35248  * Common Development and Distribution License (the "License").
69acbbeafSnn35248  * 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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
227c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
26*eb53af1dSksn  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * UNIX Device Driver Interface functions
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * This file contains functions that are to be added to the kernel
367c478bd9Sstevel@tonic-gate  * to put the interface presented to drivers in conformance with
377c478bd9Sstevel@tonic-gate  * the DDI standard. Of the functions added to the kernel, 17 are
387c478bd9Sstevel@tonic-gate  * function equivalents of existing macros in sysmacros.h,
397c478bd9Sstevel@tonic-gate  * stream.h, and param.h
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * 17 additional functions -- drv_getparm(), drv_setparm(),
427c478bd9Sstevel@tonic-gate  * getrbuf(), freerbuf(),
437c478bd9Sstevel@tonic-gate  * getemajor(), geteminor(), etoimajor(), itoemajor(), drv_usectohz(),
447c478bd9Sstevel@tonic-gate  * drv_hztousec(), drv_usecwait(), drv_priv(), and kvtoppid() --
457c478bd9Sstevel@tonic-gate  * are specified by DDI to exist in the kernel and are implemented here.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * Note that putnext() and put() are not in this file. The C version of
487c478bd9Sstevel@tonic-gate  * these routines are in uts/common/os/putnext.c and assembly versions
497c478bd9Sstevel@tonic-gate  * might exist for some architectures.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <sys/types.h>
537c478bd9Sstevel@tonic-gate #include <sys/param.h>
547c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
557c478bd9Sstevel@tonic-gate #include <sys/time.h>
567c478bd9Sstevel@tonic-gate #include <sys/systm.h>
577c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
587c478bd9Sstevel@tonic-gate #include <sys/signal.h>
597c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
607c478bd9Sstevel@tonic-gate #include <sys/user.h>
617c478bd9Sstevel@tonic-gate #include <sys/errno.h>
627c478bd9Sstevel@tonic-gate #include <sys/buf.h>
637c478bd9Sstevel@tonic-gate #include <sys/proc.h>
647c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
657c478bd9Sstevel@tonic-gate #include <sys/stream.h>
667c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
677c478bd9Sstevel@tonic-gate #include <sys/uio.h>
687c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
697c478bd9Sstevel@tonic-gate #include <sys/conf.h>
707c478bd9Sstevel@tonic-gate #include <sys/cred.h>
717c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
727c478bd9Sstevel@tonic-gate #include <sys/file.h>
737c478bd9Sstevel@tonic-gate #include <sys/poll.h>
747c478bd9Sstevel@tonic-gate #include <sys/session.h>
757c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
767c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
777c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
787c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
797c478bd9Sstevel@tonic-gate #include <sys/debug.h>
807c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate  * return internal major number corresponding to device
847c478bd9Sstevel@tonic-gate  * number (new format) argument
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate major_t
877c478bd9Sstevel@tonic-gate getmajor(dev_t dev)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate #ifdef _LP64
907c478bd9Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
917c478bd9Sstevel@tonic-gate #else
927c478bd9Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
937c478bd9Sstevel@tonic-gate #endif
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * return external major number corresponding to device
987c478bd9Sstevel@tonic-gate  * number (new format) argument
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate major_t
1017c478bd9Sstevel@tonic-gate getemajor(dev_t dev)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate #ifdef _LP64
1047c478bd9Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
1057c478bd9Sstevel@tonic-gate #else
1067c478bd9Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
1077c478bd9Sstevel@tonic-gate #endif
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * return internal minor number corresponding to device
1127c478bd9Sstevel@tonic-gate  * number (new format) argument
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate minor_t
1157c478bd9Sstevel@tonic-gate getminor(dev_t dev)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate #ifdef _LP64
1187c478bd9Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN64));
1197c478bd9Sstevel@tonic-gate #else
1207c478bd9Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN));
1217c478bd9Sstevel@tonic-gate #endif
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * return external minor number corresponding to device
1267c478bd9Sstevel@tonic-gate  * number (new format) argument
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate minor_t
1297c478bd9Sstevel@tonic-gate geteminor(dev_t dev)
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate #ifdef _LP64
1327c478bd9Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN64));
1337c478bd9Sstevel@tonic-gate #else
1347c478bd9Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN));
1357c478bd9Sstevel@tonic-gate #endif
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * return internal major number corresponding to external
1407c478bd9Sstevel@tonic-gate  * major number.
1417c478bd9Sstevel@tonic-gate  */
1427c478bd9Sstevel@tonic-gate int
1437c478bd9Sstevel@tonic-gate etoimajor(major_t emajnum)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate #ifdef _LP64
1467c478bd9Sstevel@tonic-gate 	if (emajnum >= devcnt)
1477c478bd9Sstevel@tonic-gate 		return (-1); /* invalid external major */
1487c478bd9Sstevel@tonic-gate #else
1497c478bd9Sstevel@tonic-gate 	if (emajnum > MAXMAJ || emajnum >= devcnt)
1507c478bd9Sstevel@tonic-gate 		return (-1); /* invalid external major */
1517c478bd9Sstevel@tonic-gate #endif
1527c478bd9Sstevel@tonic-gate 	return ((int)emajnum);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * return external major number corresponding to internal
1577c478bd9Sstevel@tonic-gate  * major number argument or -1 if no external major number
1587c478bd9Sstevel@tonic-gate  * can be found after lastemaj that maps to the internal
1597c478bd9Sstevel@tonic-gate  * major number. Pass a lastemaj val of -1 to start
1607c478bd9Sstevel@tonic-gate  * the search initially. (Typical use of this function is
1617c478bd9Sstevel@tonic-gate  * of the form:
1627c478bd9Sstevel@tonic-gate  *
1637c478bd9Sstevel@tonic-gate  *	lastemaj = -1;
1647c478bd9Sstevel@tonic-gate  *	while ((lastemaj = itoemajor(imag, lastemaj)) != -1)
1657c478bd9Sstevel@tonic-gate  *		{ process major number }
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate int
1687c478bd9Sstevel@tonic-gate itoemajor(major_t imajnum, int lastemaj)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	if (imajnum >= devcnt)
1717c478bd9Sstevel@tonic-gate 		return (-1);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	/*
1747c478bd9Sstevel@tonic-gate 	 * if lastemaj == -1 then start from beginning of
1757c478bd9Sstevel@tonic-gate 	 * the (imaginary) MAJOR table
1767c478bd9Sstevel@tonic-gate 	 */
1777c478bd9Sstevel@tonic-gate 	if (lastemaj < -1)
1787c478bd9Sstevel@tonic-gate 		return (-1);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * given that there's a 1-1 mapping of internal to external
1827c478bd9Sstevel@tonic-gate 	 * major numbers, searching is somewhat pointless ... let's
1837c478bd9Sstevel@tonic-gate 	 * just go there directly.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if (++lastemaj < devcnt && imajnum < devcnt)
1867c478bd9Sstevel@tonic-gate 		return (imajnum);
1877c478bd9Sstevel@tonic-gate 	return (-1);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * encode external major and minor number arguments into a
1927c478bd9Sstevel@tonic-gate  * new format device number
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate dev_t
1957c478bd9Sstevel@tonic-gate makedevice(major_t maj, minor_t minor)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate #ifdef _LP64
1987c478bd9Sstevel@tonic-gate 	return (((dev_t)maj << NBITSMINOR64) | (minor & MAXMIN64));
1997c478bd9Sstevel@tonic-gate #else
2007c478bd9Sstevel@tonic-gate 	return (((dev_t)maj << NBITSMINOR) | (minor & MAXMIN));
2017c478bd9Sstevel@tonic-gate #endif
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * cmpdev - compress new device format to old device format
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate o_dev_t
2087c478bd9Sstevel@tonic-gate cmpdev(dev_t dev)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	major_t major_d;
2117c478bd9Sstevel@tonic-gate 	minor_t minor_d;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate #ifdef _LP64
2147c478bd9Sstevel@tonic-gate 	major_d = dev >> NBITSMINOR64;
2157c478bd9Sstevel@tonic-gate 	minor_d = dev & MAXMIN64;
2167c478bd9Sstevel@tonic-gate #else
2177c478bd9Sstevel@tonic-gate 	major_d = dev >> NBITSMINOR;
2187c478bd9Sstevel@tonic-gate 	minor_d = dev & MAXMIN;
2197c478bd9Sstevel@tonic-gate #endif
2207c478bd9Sstevel@tonic-gate 	if (major_d > OMAXMAJ || minor_d > OMAXMIN)
2217c478bd9Sstevel@tonic-gate 		return ((o_dev_t)NODEV);
2227c478bd9Sstevel@tonic-gate 	return ((o_dev_t)((major_d << ONBITSMINOR) | minor_d));
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate dev_t
2267c478bd9Sstevel@tonic-gate expdev(dev_t dev)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	major_t major_d;
2297c478bd9Sstevel@tonic-gate 	minor_t minor_d;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	major_d = ((dev >> ONBITSMINOR) & OMAXMAJ);
2327c478bd9Sstevel@tonic-gate 	minor_d = (dev & OMAXMIN);
2337c478bd9Sstevel@tonic-gate #ifdef _LP64
2347c478bd9Sstevel@tonic-gate 	return ((((dev_t)major_d << NBITSMINOR64) | minor_d));
2357c478bd9Sstevel@tonic-gate #else
2367c478bd9Sstevel@tonic-gate 	return ((((dev_t)major_d << NBITSMINOR) | minor_d));
2377c478bd9Sstevel@tonic-gate #endif
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * return true (1) if the message type input is a data
2427c478bd9Sstevel@tonic-gate  * message type, 0 otherwise
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate #undef datamsg
2457c478bd9Sstevel@tonic-gate int
2467c478bd9Sstevel@tonic-gate datamsg(unsigned char db_type)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	return (db_type == M_DATA || db_type == M_PROTO ||
2497c478bd9Sstevel@tonic-gate 	    db_type == M_PCPROTO || db_type == M_DELAY);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * return a pointer to the other queue in the queue pair of qp
2547c478bd9Sstevel@tonic-gate  */
2557c478bd9Sstevel@tonic-gate queue_t *
2567c478bd9Sstevel@tonic-gate OTHERQ(queue_t *q)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate 	return (_OTHERQ(q));
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * return a pointer to the read queue in the queue pair of qp.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate queue_t *
2657c478bd9Sstevel@tonic-gate RD(queue_t *q)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 		return (_RD(q));
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * return a pointer to the write queue in the queue pair of qp.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate int
2757c478bd9Sstevel@tonic-gate SAMESTR(queue_t *q)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	return (_SAMESTR(q));
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * return a pointer to the write queue in the queue pair of qp.
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate queue_t *
2847c478bd9Sstevel@tonic-gate WR(queue_t *q)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	return (_WR(q));
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate  * store value of kernel parameter associated with parm
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate int
2937c478bd9Sstevel@tonic-gate drv_getparm(unsigned int parm, void *valuep)
2947c478bd9Sstevel@tonic-gate {
2959acbbeafSnn35248 	proc_t	*p = curproc;
2967c478bd9Sstevel@tonic-gate 	time_t	now;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	switch (parm) {
2997c478bd9Sstevel@tonic-gate 	case UPROCP:
3009acbbeafSnn35248 		*(proc_t **)valuep = p;
3017c478bd9Sstevel@tonic-gate 		break;
3027c478bd9Sstevel@tonic-gate 	case PPGRP:
303*eb53af1dSksn 		mutex_enter(&p->p_lock);
3049acbbeafSnn35248 		*(pid_t *)valuep = p->p_pgrp;
305*eb53af1dSksn 		mutex_exit(&p->p_lock);
3067c478bd9Sstevel@tonic-gate 		break;
3077c478bd9Sstevel@tonic-gate 	case LBOLT:
3087c478bd9Sstevel@tonic-gate 		*(clock_t *)valuep = lbolt;
3097c478bd9Sstevel@tonic-gate 		break;
3107c478bd9Sstevel@tonic-gate 	case TIME:
3117c478bd9Sstevel@tonic-gate 		if ((now = gethrestime_sec()) == 0) {
3127c478bd9Sstevel@tonic-gate 			timestruc_t ts;
3137c478bd9Sstevel@tonic-gate 			mutex_enter(&tod_lock);
3147c478bd9Sstevel@tonic-gate 			ts = tod_get();
3157c478bd9Sstevel@tonic-gate 			mutex_exit(&tod_lock);
3167c478bd9Sstevel@tonic-gate 			*(time_t *)valuep = ts.tv_sec;
3177c478bd9Sstevel@tonic-gate 		} else {
3187c478bd9Sstevel@tonic-gate 			*(time_t *)valuep = now;
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 		break;
3217c478bd9Sstevel@tonic-gate 	case PPID:
3229acbbeafSnn35248 		*(pid_t *)valuep = p->p_pid;
3237c478bd9Sstevel@tonic-gate 		break;
3247c478bd9Sstevel@tonic-gate 	case PSID:
3259acbbeafSnn35248 		mutex_enter(&p->p_splock);
3269acbbeafSnn35248 		*(pid_t *)valuep = p->p_sessp->s_sid;
3279acbbeafSnn35248 		mutex_exit(&p->p_splock);
3287c478bd9Sstevel@tonic-gate 		break;
3297c478bd9Sstevel@tonic-gate 	case UCRED:
3307c478bd9Sstevel@tonic-gate 		*(cred_t **)valuep = CRED();
3317c478bd9Sstevel@tonic-gate 		break;
3327c478bd9Sstevel@tonic-gate 	default:
3337c478bd9Sstevel@tonic-gate 		return (-1);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	return (0);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * set value of kernel parameter associated with parm
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate int
3437c478bd9Sstevel@tonic-gate drv_setparm(unsigned int parm, unsigned long value)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	switch (parm) {
3467c478bd9Sstevel@tonic-gate 	case SYSRINT:
3477c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, rcvint, value);
3487c478bd9Sstevel@tonic-gate 		break;
3497c478bd9Sstevel@tonic-gate 	case SYSXINT:
3507c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, xmtint, value);
3517c478bd9Sstevel@tonic-gate 		break;
3527c478bd9Sstevel@tonic-gate 	case SYSMINT:
3537c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, mdmint, value);
3547c478bd9Sstevel@tonic-gate 		break;
3557c478bd9Sstevel@tonic-gate 	case SYSRAWC:
3567c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, rawch, value);
3577c478bd9Sstevel@tonic-gate 		break;
3587c478bd9Sstevel@tonic-gate 	case SYSCANC:
3597c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, canch, value);
3607c478bd9Sstevel@tonic-gate 		break;
3617c478bd9Sstevel@tonic-gate 	case SYSOUTC:
3627c478bd9Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, outch, value);
3637c478bd9Sstevel@tonic-gate 		break;
3647c478bd9Sstevel@tonic-gate 	default:
3657c478bd9Sstevel@tonic-gate 		return (-1);
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	return (0);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * allocate space for buffer header and return pointer to it.
3737c478bd9Sstevel@tonic-gate  * preferred means of obtaining space for a local buf header.
3747c478bd9Sstevel@tonic-gate  * returns pointer to buf upon success, NULL for failure
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate struct buf *
3777c478bd9Sstevel@tonic-gate getrbuf(int sleep)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	struct buf *bp;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	bp = kmem_alloc(sizeof (struct buf), sleep);
3827c478bd9Sstevel@tonic-gate 	if (bp == NULL)
3837c478bd9Sstevel@tonic-gate 		return (NULL);
3847c478bd9Sstevel@tonic-gate 	bioinit(bp);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return (bp);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * free up space allocated by getrbuf()
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate void
3937c478bd9Sstevel@tonic-gate freerbuf(struct buf *bp)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	biofini(bp);
3967c478bd9Sstevel@tonic-gate 	kmem_free(bp, sizeof (struct buf));
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate  * convert byte count input to logical page units
4017c478bd9Sstevel@tonic-gate  * (byte counts that are not a page-size multiple
4027c478bd9Sstevel@tonic-gate  * are rounded down)
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate pgcnt_t
4057c478bd9Sstevel@tonic-gate btop(size_t numbytes)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	return (numbytes >> PAGESHIFT);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * convert byte count input to logical page units
4127c478bd9Sstevel@tonic-gate  * (byte counts that are not a page-size multiple
4137c478bd9Sstevel@tonic-gate  * are rounded up)
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate pgcnt_t
4167c478bd9Sstevel@tonic-gate btopr(size_t numbytes)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	return ((numbytes + PAGEOFFSET) >> PAGESHIFT);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate  * convert size in pages to bytes.
4237c478bd9Sstevel@tonic-gate  */
4247c478bd9Sstevel@tonic-gate size_t
4257c478bd9Sstevel@tonic-gate ptob(pgcnt_t numpages)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	return (numpages << PAGESHIFT);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate #define	MAXCLOCK_T LONG_MAX
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate  * Convert from system time units (hz) to microseconds.
4347c478bd9Sstevel@tonic-gate  *
4357c478bd9Sstevel@tonic-gate  * If ticks <= 0, return 0.
4367c478bd9Sstevel@tonic-gate  * If converting ticks to usecs would overflow, return MAXCLOCK_T.
4377c478bd9Sstevel@tonic-gate  * Otherwise, convert ticks to microseconds.
4387c478bd9Sstevel@tonic-gate  */
4397c478bd9Sstevel@tonic-gate clock_t
4407c478bd9Sstevel@tonic-gate drv_hztousec(clock_t ticks)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	if (ticks <= 0)
4437c478bd9Sstevel@tonic-gate 		return (0);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if (ticks > MAXCLOCK_T / usec_per_tick)
4467c478bd9Sstevel@tonic-gate 		return (MAXCLOCK_T);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	return (TICK_TO_USEC(ticks));
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate  * Convert from microseconds to system time units (hz), rounded up.
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  * If ticks <= 0, return 0.
4567c478bd9Sstevel@tonic-gate  * Otherwise, convert microseconds to ticks, rounding up.
4577c478bd9Sstevel@tonic-gate  */
4587c478bd9Sstevel@tonic-gate clock_t
4597c478bd9Sstevel@tonic-gate drv_usectohz(clock_t microsecs)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	if (microsecs <= 0)
4627c478bd9Sstevel@tonic-gate 		return (0);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (USEC_TO_TICK_ROUNDUP(microsecs));
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate #ifdef	sun
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * drv_usecwait implemented in each architecture's machine
4707c478bd9Sstevel@tonic-gate  * specific code somewhere. For sparc, it is the alternate entry
4717c478bd9Sstevel@tonic-gate  * to usec_delay (eventually usec_delay goes away). See
4727c478bd9Sstevel@tonic-gate  * sparc/os/ml/sparc_subr.s
4737c478bd9Sstevel@tonic-gate  */
4747c478bd9Sstevel@tonic-gate #endif
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * bcanputnext, canputnext assume called from timeout, bufcall,
4787c478bd9Sstevel@tonic-gate  * or esballoc free routines.  since these are driven by
4797c478bd9Sstevel@tonic-gate  * clock interrupts, instead of system calls the appropriate plumbing
4807c478bd9Sstevel@tonic-gate  * locks have not been acquired.
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate int
4837c478bd9Sstevel@tonic-gate bcanputnext(queue_t *q, unsigned char band)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	int	ret;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	claimstr(q);
4887c478bd9Sstevel@tonic-gate 	ret = bcanput(q->q_next, band);
4897c478bd9Sstevel@tonic-gate 	releasestr(q);
4907c478bd9Sstevel@tonic-gate 	return (ret);
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate int
4947c478bd9Sstevel@tonic-gate canputnext(queue_t *q)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	queue_t	*qofsq = q;
4977c478bd9Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
4987c478bd9Sstevel@tonic-gate 	kmutex_t *sdlock;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_IN,
5017c478bd9Sstevel@tonic-gate 	    "canputnext?:%p\n", q);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (stp->sd_ciputctrl != NULL) {
5047c478bd9Sstevel@tonic-gate 		int ix = CPU->cpu_seqid & stp->sd_nciputctrl;
5057c478bd9Sstevel@tonic-gate 		sdlock = &stp->sd_ciputctrl[ix].ciputctrl_lock;
5067c478bd9Sstevel@tonic-gate 		mutex_enter(sdlock);
5077c478bd9Sstevel@tonic-gate 	} else
5087c478bd9Sstevel@tonic-gate 		mutex_enter(sdlock = &stp->sd_reflock);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	/* get next module forward with a service queue */
5117c478bd9Sstevel@tonic-gate 	q = q->q_next->q_nfsrv;
5127c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	/* this is for loopback transports, they should not do a canputnext */
5157c478bd9Sstevel@tonic-gate 	ASSERT(STRMATED(q->q_stream) || STREAM(q) == STREAM(qofsq));
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if (!(q->q_flag & QFULL)) {
5187c478bd9Sstevel@tonic-gate 		mutex_exit(sdlock);
5197c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT,
5207c478bd9Sstevel@tonic-gate 		    "canputnext:%p %d", q, 1);
5217c478bd9Sstevel@tonic-gate 		return (1);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (sdlock != &stp->sd_reflock) {
5257c478bd9Sstevel@tonic-gate 		mutex_exit(sdlock);
5267c478bd9Sstevel@tonic-gate 		mutex_enter(&stp->sd_reflock);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/* the above is the most frequently used path */
5307c478bd9Sstevel@tonic-gate 	stp->sd_refcnt++;
5317c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_refcnt != 0);	/* Wraparound */
5327c478bd9Sstevel@tonic-gate 	mutex_exit(&stp->sd_reflock);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	mutex_enter(QLOCK(q));
5357c478bd9Sstevel@tonic-gate 	if (q->q_flag & QFULL) {
5367c478bd9Sstevel@tonic-gate 		q->q_flag |= QWANTW;
5377c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
5387c478bd9Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT,
5397c478bd9Sstevel@tonic-gate 		    "canputnext:%p %d", q, 0);
5407c478bd9Sstevel@tonic-gate 		releasestr(qofsq);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 		return (0);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	mutex_exit(QLOCK(q));
5457c478bd9Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT, "canputnext:%p %d", q, 1);
5467c478bd9Sstevel@tonic-gate 	releasestr(qofsq);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	return (1);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  * Open has progressed to the point where it is safe to send/receive messages.
5547c478bd9Sstevel@tonic-gate  *
5557c478bd9Sstevel@tonic-gate  * "qprocson enables the put and service routines of the driver
5567c478bd9Sstevel@tonic-gate  * or module... Prior to the call to qprocson, the put and service
5577c478bd9Sstevel@tonic-gate  * routines of a newly pushed module or newly opened driver are
5587c478bd9Sstevel@tonic-gate  * disabled.  For the module, messages flow around it as if it
5597c478bd9Sstevel@tonic-gate  * were not present in the stream... qprocson must be called by
5607c478bd9Sstevel@tonic-gate  * the first open of a module or driver after allocation and
5617c478bd9Sstevel@tonic-gate  * initialization of any resource on which the put and service
5627c478bd9Sstevel@tonic-gate  * routines depend."
5637c478bd9Sstevel@tonic-gate  *
5647c478bd9Sstevel@tonic-gate  * Note that before calling qprocson a module/driver could itself cause its
5657c478bd9Sstevel@tonic-gate  * put or service procedures to be run by using put() or qenable().
5667c478bd9Sstevel@tonic-gate  */
5677c478bd9Sstevel@tonic-gate void
5687c478bd9Sstevel@tonic-gate qprocson(queue_t *q)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
5717c478bd9Sstevel@tonic-gate 	/*
5727c478bd9Sstevel@tonic-gate 	 * Do not call insertq() if it is a re-open.  But if _QINSERTING
5737c478bd9Sstevel@tonic-gate 	 * is set, q_next will not be NULL and we need to call insertq().
5747c478bd9Sstevel@tonic-gate 	 */
5757c478bd9Sstevel@tonic-gate 	if ((q->q_next == NULL && WR(q)->q_next == NULL) ||
5767c478bd9Sstevel@tonic-gate 	    (q->q_flag & _QINSERTING))
5777c478bd9Sstevel@tonic-gate 		insertq(STREAM(q), q);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate  * Close has reached a point where it can no longer allow put/service
5827c478bd9Sstevel@tonic-gate  * into the queue.
5837c478bd9Sstevel@tonic-gate  *
5847c478bd9Sstevel@tonic-gate  * "qprocsoff disables the put and service routines of the driver
5857c478bd9Sstevel@tonic-gate  * or module... When the routines are disabled in a module, messages
5867c478bd9Sstevel@tonic-gate  * flow around the module as if it were not present in the stream.
5877c478bd9Sstevel@tonic-gate  * qprocsoff must be called by the close routine of a driver or module
5887c478bd9Sstevel@tonic-gate  * before deallocating any resources on which the driver/module's
5897c478bd9Sstevel@tonic-gate  * put and service routines depend.  qprocsoff will remove the
5907c478bd9Sstevel@tonic-gate  * queue's service routines from the list of service routines to be
5917c478bd9Sstevel@tonic-gate  * run and waits until any concurrent put or service routines are
5927c478bd9Sstevel@tonic-gate  * finished."
5937c478bd9Sstevel@tonic-gate  *
5947c478bd9Sstevel@tonic-gate  * Note that after calling qprocsoff a module/driver could itself cause its
5957c478bd9Sstevel@tonic-gate  * put procedures to be run by using put().
5967c478bd9Sstevel@tonic-gate  */
5977c478bd9Sstevel@tonic-gate void
5987c478bd9Sstevel@tonic-gate qprocsoff(queue_t *q)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
6017c478bd9Sstevel@tonic-gate 	if (q->q_flag & QWCLOSE) {
6027c478bd9Sstevel@tonic-gate 		/* Called more than once */
6037c478bd9Sstevel@tonic-gate 		return;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 	disable_svc(q);
6067c478bd9Sstevel@tonic-gate 	removeq(q);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate  * "freezestr() freezes the state of the entire STREAM  containing
6117c478bd9Sstevel@tonic-gate  *  the  queue  pair  q.  A frozen STREAM blocks any thread
6127c478bd9Sstevel@tonic-gate  *  attempting to enter any open, close, put or service  routine
6137c478bd9Sstevel@tonic-gate  *  belonging  to  any  queue instance in the STREAM, and blocks
6147c478bd9Sstevel@tonic-gate  *  any thread currently within the STREAM if it attempts to put
6157c478bd9Sstevel@tonic-gate  *  messages  onto  or take messages off of any queue within the
6167c478bd9Sstevel@tonic-gate  *  STREAM (with the sole exception  of  the  caller).   Threads
6177c478bd9Sstevel@tonic-gate  *  blocked  by  this  mechanism  remain  so until the STREAM is
6187c478bd9Sstevel@tonic-gate  *  thawed by a call to unfreezestr().
6197c478bd9Sstevel@tonic-gate  *
6207c478bd9Sstevel@tonic-gate  * Use strblock to set SQ_FROZEN in all syncqs in the stream (prevents
6217c478bd9Sstevel@tonic-gate  * further entry into put, service, open, and close procedures) and
6227c478bd9Sstevel@tonic-gate  * grab (and hold) all the QLOCKs in the stream (to block putq, getq etc.)
6237c478bd9Sstevel@tonic-gate  *
6247c478bd9Sstevel@tonic-gate  * Note: this has to be the only code that acquires one QLOCK while holding
6257c478bd9Sstevel@tonic-gate  * another QLOCK (otherwise we would have locking hirarchy/ordering violations.)
6267c478bd9Sstevel@tonic-gate  */
6277c478bd9Sstevel@tonic-gate void
6287c478bd9Sstevel@tonic-gate freezestr(queue_t *q)
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	/*
6337c478bd9Sstevel@tonic-gate 	 * Increment refcnt to prevent q_next from changing during the strblock
6347c478bd9Sstevel@tonic-gate 	 * as well as while the stream is frozen.
6357c478bd9Sstevel@tonic-gate 	 */
6367c478bd9Sstevel@tonic-gate 	claimstr(RD(q));
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	strblock(q);
6397c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_freezer == NULL);
6407c478bd9Sstevel@tonic-gate 	stp->sd_freezer = curthread;
6417c478bd9Sstevel@tonic-gate 	for (q = stp->sd_wrq; q != NULL; q = SAMESTR(q) ? q->q_next : NULL) {
6427c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
6437c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(RD(q)));
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate /*
6487c478bd9Sstevel@tonic-gate  * Undo what freezestr did.
6497c478bd9Sstevel@tonic-gate  * Have to drop the QLOCKs before the strunblock since strunblock will
6507c478bd9Sstevel@tonic-gate  * potentially call other put procedures.
6517c478bd9Sstevel@tonic-gate  */
6527c478bd9Sstevel@tonic-gate void
6537c478bd9Sstevel@tonic-gate unfreezestr(queue_t *q)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
6567c478bd9Sstevel@tonic-gate 	queue_t	*q1;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	for (q1 = stp->sd_wrq; q1 != NULL;
6597c478bd9Sstevel@tonic-gate 	    q1 = SAMESTR(q1) ? q1->q_next : NULL) {
6607c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(q1));
6617c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(RD(q1)));
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 	ASSERT(stp->sd_freezer == curthread);
6647c478bd9Sstevel@tonic-gate 	stp->sd_freezer = NULL;
6657c478bd9Sstevel@tonic-gate 	strunblock(q);
6667c478bd9Sstevel@tonic-gate 	releasestr(RD(q));
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * Used by open and close procedures to "sleep" waiting for messages to
6717c478bd9Sstevel@tonic-gate  * arrive. Note: can only be used in open and close procedures.
6727c478bd9Sstevel@tonic-gate  *
6737c478bd9Sstevel@tonic-gate  * Lower the gate and let in either messages on the syncq (if there are
6747c478bd9Sstevel@tonic-gate  * any) or put/service procedures.
6757c478bd9Sstevel@tonic-gate  *
6767c478bd9Sstevel@tonic-gate  * If the queue has an outer perimeter this will not prevent entry into this
6777c478bd9Sstevel@tonic-gate  * syncq (since outer_enter does not set SQ_WRITER on the syncq that gets the
6787c478bd9Sstevel@tonic-gate  * exclusive access to the outer perimeter.)
6797c478bd9Sstevel@tonic-gate  *
6807c478bd9Sstevel@tonic-gate  * Return 0 is the cv_wait_sig was interrupted; otherwise 1.
6817c478bd9Sstevel@tonic-gate  *
6827c478bd9Sstevel@tonic-gate  * It only makes sense to grab sq_putlocks for !SQ_CIOC sync queues because
6837c478bd9Sstevel@tonic-gate  * otherwise put entry points were not blocked in the first place. if this is
6847c478bd9Sstevel@tonic-gate  * SQ_CIOC then qwait is used to wait for service procedure to run since syncq
6857c478bd9Sstevel@tonic-gate  * is always SQ_CIPUT if it is SQ_CIOC.
6867c478bd9Sstevel@tonic-gate  *
6877c478bd9Sstevel@tonic-gate  * Note that SQ_EXCL is dropped and SQ_WANTEXITWAKEUP set in sq_flags
6887c478bd9Sstevel@tonic-gate  * atomically under sq_putlocks to make sure putnext will not miss a pending
6897c478bd9Sstevel@tonic-gate  * wakeup.
6907c478bd9Sstevel@tonic-gate  */
6917c478bd9Sstevel@tonic-gate int
6927c478bd9Sstevel@tonic-gate qwait_sig(queue_t *q)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate 	syncq_t		*sq, *outer;
6957c478bd9Sstevel@tonic-gate 	uint_t		flags;
6967c478bd9Sstevel@tonic-gate 	int		ret = 1;
6977c478bd9Sstevel@tonic-gate 	int		is_sq_cioc;
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	/*
7007c478bd9Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_OPENCLOSE)
7017c478bd9Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
7027c478bd9Sstevel@tonic-gate 	 * so that qwait_sig can return to the caller.
7037c478bd9Sstevel@tonic-gate 	 *
7047c478bd9Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
7057c478bd9Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
7067c478bd9Sstevel@tonic-gate 	 */
7077c478bd9Sstevel@tonic-gate 	sq = q->q_syncq;
7087c478bd9Sstevel@tonic-gate 	ASSERT(sq);
7097c478bd9Sstevel@tonic-gate 	is_sq_cioc = (sq->sq_type & SQ_CIOC) ? 1 : 0;
7107c478bd9Sstevel@tonic-gate 	ASSERT(sq->sq_outer == NULL || sq->sq_outer->sq_flags & SQ_WRITER);
7117c478bd9Sstevel@tonic-gate 	outer = sq->sq_outer;
7127c478bd9Sstevel@tonic-gate 	/*
7137c478bd9Sstevel@tonic-gate 	 * XXX this does not work if there is only an outer perimeter.
7147c478bd9Sstevel@tonic-gate 	 * The semantics of qwait/qwait_sig are undefined in this case.
7157c478bd9Sstevel@tonic-gate 	 */
7167c478bd9Sstevel@tonic-gate 	if (outer)
7177c478bd9Sstevel@tonic-gate 		outer_exit(outer);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
7207c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7217c478bd9Sstevel@tonic-gate 		SQ_PUTLOCKS_ENTER(sq);
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 	flags = sq->sq_flags;
7247c478bd9Sstevel@tonic-gate 	/*
7257c478bd9Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK
7267c478bd9Sstevel@tonic-gate 	 * to prevent any undetected entry and exit into the perimeter.
7277c478bd9Sstevel@tonic-gate 	 */
7287c478bd9Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
7297c478bd9Sstevel@tonic-gate 	sq->sq_count--;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7327c478bd9Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
7337c478bd9Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
7347c478bd9Sstevel@tonic-gate 	}
7357c478bd9Sstevel@tonic-gate 	/*
7367c478bd9Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
7377c478bd9Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
7387c478bd9Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
7397c478bd9Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
7407c478bd9Sstevel@tonic-gate 	 */
7417c478bd9Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
7427c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
7437c478bd9Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 	sq->sq_flags = flags;
7467c478bd9Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
7477c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7487c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
7517c478bd9Sstevel@tonic-gate 		drain_syncq(sq);
7527c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
7537c478bd9Sstevel@tonic-gate 		entersq(sq, SQ_OPENCLOSE);
7547c478bd9Sstevel@tonic-gate 		return (1);
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 	/*
7577c478bd9Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
7587c478bd9Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
7597c478bd9Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
7607c478bd9Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
7617c478bd9Sstevel@tonic-gate 	 */
7627c478bd9Sstevel@tonic-gate 	do {
7637c478bd9Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
7647c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7657c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		ret = cv_wait_sig(&sq->sq_exitwait, SQLOCK(sq));
7687c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7697c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_ENTER(sq);
7707c478bd9Sstevel@tonic-gate 		}
7717c478bd9Sstevel@tonic-gate 	} while (ret && (sq->sq_flags & SQ_WANTEXWAKEUP));
7727c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7737c478bd9Sstevel@tonic-gate 		SQ_PUTLOCKS_EXIT(sq);
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	/*
7787c478bd9Sstevel@tonic-gate 	 * Re-enter the perimeters again
7797c478bd9Sstevel@tonic-gate 	 */
7807c478bd9Sstevel@tonic-gate 	entersq(sq, SQ_OPENCLOSE);
7817c478bd9Sstevel@tonic-gate 	return (ret);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * Used by open and close procedures to "sleep" waiting for messages to
7867c478bd9Sstevel@tonic-gate  * arrive. Note: can only be used in open and close procedures.
7877c478bd9Sstevel@tonic-gate  *
7887c478bd9Sstevel@tonic-gate  * Lower the gate and let in either messages on the syncq (if there are
7897c478bd9Sstevel@tonic-gate  * any) or put/service procedures.
7907c478bd9Sstevel@tonic-gate  *
7917c478bd9Sstevel@tonic-gate  * If the queue has an outer perimeter this will not prevent entry into this
7927c478bd9Sstevel@tonic-gate  * syncq (since outer_enter does not set SQ_WRITER on the syncq that gets the
7937c478bd9Sstevel@tonic-gate  * exclusive access to the outer perimeter.)
7947c478bd9Sstevel@tonic-gate  *
7957c478bd9Sstevel@tonic-gate  * It only makes sense to grab sq_putlocks for !SQ_CIOC sync queues because
7967c478bd9Sstevel@tonic-gate  * otherwise put entry points were not blocked in the first place. if this is
7977c478bd9Sstevel@tonic-gate  * SQ_CIOC then qwait is used to wait for service procedure to run since syncq
7987c478bd9Sstevel@tonic-gate  * is always SQ_CIPUT if it is SQ_CIOC.
7997c478bd9Sstevel@tonic-gate  *
8007c478bd9Sstevel@tonic-gate  * Note that SQ_EXCL is dropped and SQ_WANTEXITWAKEUP set in sq_flags
8017c478bd9Sstevel@tonic-gate  * atomically under sq_putlocks to make sure putnext will not miss a pending
8027c478bd9Sstevel@tonic-gate  * wakeup.
8037c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate void
8057c478bd9Sstevel@tonic-gate qwait(queue_t *q)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	syncq_t		*sq, *outer;
8087c478bd9Sstevel@tonic-gate 	uint_t		flags;
8097c478bd9Sstevel@tonic-gate 	int		is_sq_cioc;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/*
8127c478bd9Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_OPENCLOSE)
8137c478bd9Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
8147c478bd9Sstevel@tonic-gate 	 * so that qwait can return to the caller.
8157c478bd9Sstevel@tonic-gate 	 *
8167c478bd9Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
8177c478bd9Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
8187c478bd9Sstevel@tonic-gate 	 */
8197c478bd9Sstevel@tonic-gate 	sq = q->q_syncq;
8207c478bd9Sstevel@tonic-gate 	ASSERT(sq);
8217c478bd9Sstevel@tonic-gate 	is_sq_cioc = (sq->sq_type & SQ_CIOC) ? 1 : 0;
8227c478bd9Sstevel@tonic-gate 	ASSERT(sq->sq_outer == NULL || sq->sq_outer->sq_flags & SQ_WRITER);
8237c478bd9Sstevel@tonic-gate 	outer = sq->sq_outer;
8247c478bd9Sstevel@tonic-gate 	/*
8257c478bd9Sstevel@tonic-gate 	 * XXX this does not work if there is only an outer perimeter.
8267c478bd9Sstevel@tonic-gate 	 * The semantics of qwait/qwait_sig are undefined in this case.
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	if (outer)
8297c478bd9Sstevel@tonic-gate 		outer_exit(outer);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
8327c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8337c478bd9Sstevel@tonic-gate 		SQ_PUTLOCKS_ENTER(sq);
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 	flags = sq->sq_flags;
8367c478bd9Sstevel@tonic-gate 	/*
8377c478bd9Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK
8387c478bd9Sstevel@tonic-gate 	 * to prevent any undetected entry and exit into the perimeter.
8397c478bd9Sstevel@tonic-gate 	 */
8407c478bd9Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
8417c478bd9Sstevel@tonic-gate 	sq->sq_count--;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8447c478bd9Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
8457c478bd9Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 	/*
8487c478bd9Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
8497c478bd9Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
8507c478bd9Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
8517c478bd9Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
8527c478bd9Sstevel@tonic-gate 	 */
8537c478bd9Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
8547c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
8557c478bd9Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
8567c478bd9Sstevel@tonic-gate 	}
8577c478bd9Sstevel@tonic-gate 	sq->sq_flags = flags;
8587c478bd9Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
8597c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8607c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
8617c478bd9Sstevel@tonic-gate 		}
8627c478bd9Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
8637c478bd9Sstevel@tonic-gate 		drain_syncq(sq);
8647c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
8657c478bd9Sstevel@tonic-gate 		entersq(sq, SQ_OPENCLOSE);
8667c478bd9Sstevel@tonic-gate 		return;
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 	/*
8697c478bd9Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
8707c478bd9Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
8717c478bd9Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
8727c478bd9Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 	do {
8757c478bd9Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
8767c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8777c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 		cv_wait(&sq->sq_exitwait, SQLOCK(sq));
8807c478bd9Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8817c478bd9Sstevel@tonic-gate 			SQ_PUTLOCKS_ENTER(sq);
8827c478bd9Sstevel@tonic-gate 		}
8837c478bd9Sstevel@tonic-gate 	} while (sq->sq_flags & SQ_WANTEXWAKEUP);
8847c478bd9Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8857c478bd9Sstevel@tonic-gate 		SQ_PUTLOCKS_EXIT(sq);
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/*
8907c478bd9Sstevel@tonic-gate 	 * Re-enter the perimeters again
8917c478bd9Sstevel@tonic-gate 	 */
8927c478bd9Sstevel@tonic-gate 	entersq(sq, SQ_OPENCLOSE);
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate  * Used for the synchronous streams entrypoints when sleeping outside
8977c478bd9Sstevel@tonic-gate  * the perimeters. Must never be called from regular put entrypoint.
8987c478bd9Sstevel@tonic-gate  *
8997c478bd9Sstevel@tonic-gate  * There's no need to grab sq_putlocks here (which only exist for CIPUT sync
9007c478bd9Sstevel@tonic-gate  * queues). If it is CIPUT sync queue put entry points were not blocked in the
9017c478bd9Sstevel@tonic-gate  * first place by rwnext/infonext which are treated as put entrypoints for
9027c478bd9Sstevel@tonic-gate  * permiter syncronization purposes.
9037c478bd9Sstevel@tonic-gate  *
9047c478bd9Sstevel@tonic-gate  * Consolidation private.
9057c478bd9Sstevel@tonic-gate  */
9067c478bd9Sstevel@tonic-gate boolean_t
9077c478bd9Sstevel@tonic-gate qwait_rw(queue_t *q)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	syncq_t		*sq;
9107c478bd9Sstevel@tonic-gate 	ulong_t		flags;
9117c478bd9Sstevel@tonic-gate 	boolean_t	gotsignal = B_FALSE;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	/*
9147c478bd9Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_PUT)
9157c478bd9Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
9167c478bd9Sstevel@tonic-gate 	 * so that qwait_rw can return to the caller.
9177c478bd9Sstevel@tonic-gate 	 *
9187c478bd9Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
9197c478bd9Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
9207c478bd9Sstevel@tonic-gate 	 */
9217c478bd9Sstevel@tonic-gate 	sq = q->q_syncq;
9227c478bd9Sstevel@tonic-gate 	ASSERT(sq);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
9257c478bd9Sstevel@tonic-gate 	flags = sq->sq_flags;
9267c478bd9Sstevel@tonic-gate 	/*
9277c478bd9Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK until to prevent any
9287c478bd9Sstevel@tonic-gate 	 * undetected entry and exit into the perimeter.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
9317c478bd9Sstevel@tonic-gate 	sq->sq_count--;
9327c478bd9Sstevel@tonic-gate 	if (!(sq->sq_type & SQ_CIPUT)) {
9337c478bd9Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
9347c478bd9Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 	/*
9377c478bd9Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
9387c478bd9Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
9397c478bd9Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
9407c478bd9Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
9417c478bd9Sstevel@tonic-gate 	 */
9427c478bd9Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
9437c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
9447c478bd9Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 	sq->sq_flags = flags;
9477c478bd9Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
9487c478bd9Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
9497c478bd9Sstevel@tonic-gate 		drain_syncq(sq);
9507c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
9517c478bd9Sstevel@tonic-gate 		entersq(sq, SQ_PUT);
9527c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 	/*
9557c478bd9Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
9567c478bd9Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
9577c478bd9Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
9587c478bd9Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
9597c478bd9Sstevel@tonic-gate 	 */
9607c478bd9Sstevel@tonic-gate 	do {
9617c478bd9Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
9627c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&sq->sq_exitwait, SQLOCK(sq)) <= 0) {
9637c478bd9Sstevel@tonic-gate 			sq->sq_flags &= ~SQ_WANTEXWAKEUP;
9647c478bd9Sstevel@tonic-gate 			gotsignal = B_TRUE;
9657c478bd9Sstevel@tonic-gate 			break;
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 	} while (sq->sq_flags & SQ_WANTEXWAKEUP);
9687c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/*
9717c478bd9Sstevel@tonic-gate 	 * Re-enter the perimeters again
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	entersq(sq, SQ_PUT);
9747c478bd9Sstevel@tonic-gate 	return (gotsignal);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate /*
9787c478bd9Sstevel@tonic-gate  * Asynchronously upgrade to exclusive access at either the inner or
9797c478bd9Sstevel@tonic-gate  * outer perimeter.
9807c478bd9Sstevel@tonic-gate  */
9817c478bd9Sstevel@tonic-gate void
9827c478bd9Sstevel@tonic-gate qwriter(queue_t *q, mblk_t *mp, void (*func)(), int perim)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate 	if (perim == PERIM_INNER)
9857c478bd9Sstevel@tonic-gate 		qwriter_inner(q, mp, func);
9867c478bd9Sstevel@tonic-gate 	else if (perim == PERIM_OUTER)
9877c478bd9Sstevel@tonic-gate 		qwriter_outer(q, mp, func);
9887c478bd9Sstevel@tonic-gate 	else
9897c478bd9Sstevel@tonic-gate 		panic("qwriter: wrong \"perimeter\" parameter");
9907c478bd9Sstevel@tonic-gate }
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate  * Schedule a synchronous streams timeout
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate timeout_id_t
9967c478bd9Sstevel@tonic-gate qtimeout(queue_t *q, void (*func)(void *), void *arg, clock_t tim)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	syncq_t		*sq;
9997c478bd9Sstevel@tonic-gate 	callbparams_t	*cbp;
10007c478bd9Sstevel@tonic-gate 	timeout_id_t	tid;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	sq = q->q_syncq;
10037c478bd9Sstevel@tonic-gate 	/*
10047c478bd9Sstevel@tonic-gate 	 * you don't want the timeout firing before its params are set up
10057c478bd9Sstevel@tonic-gate 	 * callbparams_alloc() acquires SQLOCK(sq)
10067c478bd9Sstevel@tonic-gate 	 * qtimeout() can't fail and can't sleep, so panic if memory is not
10077c478bd9Sstevel@tonic-gate 	 * available.
10087c478bd9Sstevel@tonic-gate 	 */
10097c478bd9Sstevel@tonic-gate 	cbp = callbparams_alloc(sq, func, arg, KM_NOSLEEP | KM_PANIC);
10107c478bd9Sstevel@tonic-gate 	/*
10117c478bd9Sstevel@tonic-gate 	 * the callbflags in the sq use the same flags. They get anded
10127c478bd9Sstevel@tonic-gate 	 * in the callbwrapper to determine if a qun* of this callback type
10137c478bd9Sstevel@tonic-gate 	 * is required. This is not a request to cancel.
10147c478bd9Sstevel@tonic-gate 	 */
10157c478bd9Sstevel@tonic-gate 	cbp->cbp_flags = SQ_CANCEL_TOUT;
10167c478bd9Sstevel@tonic-gate 	/* check new timeout version return codes */
10177c478bd9Sstevel@tonic-gate 	tid = timeout(qcallbwrapper, cbp, tim);
10187c478bd9Sstevel@tonic-gate 	cbp->cbp_id = (callbparams_id_t)tid;
10197c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10207c478bd9Sstevel@tonic-gate 	/* use local id because the cbp memory could be free by now */
10217c478bd9Sstevel@tonic-gate 	return (tid);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate bufcall_id_t
10257c478bd9Sstevel@tonic-gate qbufcall(queue_t *q, size_t size, uint_t pri, void (*func)(void *), void *arg)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	syncq_t		*sq;
10287c478bd9Sstevel@tonic-gate 	callbparams_t	*cbp;
10297c478bd9Sstevel@tonic-gate 	bufcall_id_t	bid;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	sq = q->q_syncq;
10327c478bd9Sstevel@tonic-gate 	/*
10337c478bd9Sstevel@tonic-gate 	 * you don't want the timeout firing before its params are set up
10347c478bd9Sstevel@tonic-gate 	 * callbparams_alloc() acquires SQLOCK(sq) if successful.
10357c478bd9Sstevel@tonic-gate 	 */
10367c478bd9Sstevel@tonic-gate 	cbp = callbparams_alloc(sq, func, arg, KM_NOSLEEP);
10377c478bd9Sstevel@tonic-gate 	if (cbp == NULL)
10387c478bd9Sstevel@tonic-gate 		return ((bufcall_id_t)0);
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/*
10417c478bd9Sstevel@tonic-gate 	 * the callbflags in the sq use the same flags. They get anded
10427c478bd9Sstevel@tonic-gate 	 * in the callbwrapper to determine if a qun* of this callback type
10437c478bd9Sstevel@tonic-gate 	 * is required. This is not a request to cancel.
10447c478bd9Sstevel@tonic-gate 	 */
10457c478bd9Sstevel@tonic-gate 	cbp->cbp_flags = SQ_CANCEL_BUFCALL;
10467c478bd9Sstevel@tonic-gate 	/* check new timeout version return codes */
10477c478bd9Sstevel@tonic-gate 	bid = bufcall(size, pri, qcallbwrapper, cbp);
10487c478bd9Sstevel@tonic-gate 	cbp->cbp_id = (callbparams_id_t)bid;
10497c478bd9Sstevel@tonic-gate 	if (bid == 0) {
10507c478bd9Sstevel@tonic-gate 		callbparams_free(sq, cbp);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10537c478bd9Sstevel@tonic-gate 	/* use local id because the params memory could be free by now */
10547c478bd9Sstevel@tonic-gate 	return (bid);
10557c478bd9Sstevel@tonic-gate }
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate  * cancel a timeout callback which enters the inner perimeter.
10597c478bd9Sstevel@tonic-gate  * cancelling of all callback types on a given syncq is serialized.
10607c478bd9Sstevel@tonic-gate  * the SQ_CALLB_BYPASSED flag indicates that the callback fn did
10617c478bd9Sstevel@tonic-gate  * not execute. The quntimeout return value needs to reflect this.
10627c478bd9Sstevel@tonic-gate  * As with out existing callback programming model - callbacks must
10637c478bd9Sstevel@tonic-gate  * be cancelled before a close completes - so ensuring that the sq
10647c478bd9Sstevel@tonic-gate  * is valid when the callback wrapper is executed.
10657c478bd9Sstevel@tonic-gate  */
10667c478bd9Sstevel@tonic-gate clock_t
10677c478bd9Sstevel@tonic-gate quntimeout(queue_t *q, timeout_id_t id)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	syncq_t *sq = q->q_syncq;
10707c478bd9Sstevel@tonic-gate 	clock_t ret;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
10737c478bd9Sstevel@tonic-gate 	/* callbacks are processed serially on each syncq */
10747c478bd9Sstevel@tonic-gate 	while (sq->sq_callbflags & SQ_CALLB_CANCEL_MASK) {
10757c478bd9Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTWAKEUP;
10767c478bd9Sstevel@tonic-gate 		cv_wait(&sq->sq_wait, SQLOCK(sq));
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 	sq->sq_cancelid = (callbparams_id_t)id;
10797c478bd9Sstevel@tonic-gate 	sq->sq_callbflags = SQ_CANCEL_TOUT;
10807c478bd9Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
10817c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
10827c478bd9Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10857c478bd9Sstevel@tonic-gate 	ret = untimeout(id);
10867c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
10877c478bd9Sstevel@tonic-gate 	if (ret != -1) {
10887c478bd9Sstevel@tonic-gate 		/* The wrapper was never called - need to free based on id */
10897c478bd9Sstevel@tonic-gate 		callbparams_free_id(sq, (callbparams_id_t)id, SQ_CANCEL_TOUT);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 	if (sq->sq_callbflags & SQ_CALLB_BYPASSED) {
10927c478bd9Sstevel@tonic-gate 		ret = 0;	/* this was how much time left */
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 	sq->sq_callbflags = 0;
10957c478bd9Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
10967c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
10977c478bd9Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
11007c478bd9Sstevel@tonic-gate 	return (ret);
11017c478bd9Sstevel@tonic-gate }
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate void
11057c478bd9Sstevel@tonic-gate qunbufcall(queue_t *q, bufcall_id_t id)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate 	syncq_t *sq = q->q_syncq;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
11107c478bd9Sstevel@tonic-gate 	/* callbacks are processed serially on each syncq */
11117c478bd9Sstevel@tonic-gate 	while (sq->sq_callbflags & SQ_CALLB_CANCEL_MASK) {
11127c478bd9Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTWAKEUP;
11137c478bd9Sstevel@tonic-gate 		cv_wait(&sq->sq_wait, SQLOCK(sq));
11147c478bd9Sstevel@tonic-gate 	}
11157c478bd9Sstevel@tonic-gate 	sq->sq_cancelid = (callbparams_id_t)id;
11167c478bd9Sstevel@tonic-gate 	sq->sq_callbflags = SQ_CANCEL_BUFCALL;
11177c478bd9Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
11187c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
11197c478bd9Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
11207c478bd9Sstevel@tonic-gate 	}
11217c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
11227c478bd9Sstevel@tonic-gate 	unbufcall(id);
11237c478bd9Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
11247c478bd9Sstevel@tonic-gate 	/*
11257c478bd9Sstevel@tonic-gate 	 * No indication from unbufcall if the callback has already run.
11267c478bd9Sstevel@tonic-gate 	 * Always attempt to free it.
11277c478bd9Sstevel@tonic-gate 	 */
11287c478bd9Sstevel@tonic-gate 	callbparams_free_id(sq, (callbparams_id_t)id, SQ_CANCEL_BUFCALL);
11297c478bd9Sstevel@tonic-gate 	sq->sq_callbflags = 0;
11307c478bd9Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
11317c478bd9Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
11327c478bd9Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate /*
1138cfbaf6c3Scth  * Associate the stream with an instance of the bottom driver.  This
1139cfbaf6c3Scth  * function is called by APIs that establish or modify the hardware
1140cfbaf6c3Scth  * association (ppa) of an open stream.  Two examples of such
1141cfbaf6c3Scth  * post-open(9E) APIs are the dlpi(7p) DL_ATTACH_REQ message, and the
1142cfbaf6c3Scth  * ndd(1M) "instance=" ioctl(2).  This interface may be called from a
1143cfbaf6c3Scth  * stream driver's wput procedure and from within syncq perimeters,
1144cfbaf6c3Scth  * so it can't block.
1145cfbaf6c3Scth  *
1146cfbaf6c3Scth  * The qassociate() "model" is that it should drive attach(9E), yet it
1147cfbaf6c3Scth  * can't really do that because driving attach(9E) is a blocking
1148cfbaf6c3Scth  * operation.  Instead, the qassociate() implementation has complex
1149cfbaf6c3Scth  * dependencies on the implementation behavior of other parts of the
1150cfbaf6c3Scth  * kernel to ensure all appropriate instances (ones that have not been
1151cfbaf6c3Scth  * made inaccessible by DR) are attached at stream open() time, and
1152cfbaf6c3Scth  * that they will not autodetach.  The code relies on the fact that an
1153cfbaf6c3Scth  * open() of a stream that ends up using qassociate() always occurs on
1154cfbaf6c3Scth  * a minor node created with CLONE_DEV.  The open() comes through
1155cfbaf6c3Scth  * clnopen() and since clnopen() calls ddi_hold_installed_driver() we
1156cfbaf6c3Scth  * attach all instances and mark them DN_NO_AUTODETACH (given
1157cfbaf6c3Scth  * DN_DRIVER_HELD is maintained correctly).
1158cfbaf6c3Scth  *
1159cfbaf6c3Scth  * Since qassociate() can't really drive attach(9E), there are corner
1160cfbaf6c3Scth  * cases where the compromise described above leads to qassociate()
1161cfbaf6c3Scth  * returning failure.  This can happen when administrative functions
1162cfbaf6c3Scth  * that cause detach(9E), such as "update_drv" or "modunload -i", are
1163cfbaf6c3Scth  * performed on the driver between the time the stream was opened and
1164cfbaf6c3Scth  * the time its hardware association was established.  Although this can
1165cfbaf6c3Scth  * theoretically be an arbitrary amount of time, in practice the window
1166cfbaf6c3Scth  * is usually quite small, since applications almost always issue their
1167cfbaf6c3Scth  * hardware association request immediately after opening the stream,
1168cfbaf6c3Scth  * and do not typically switch association while open.  When these
1169cfbaf6c3Scth  * corner cases occur, and qassociate() finds the requested instance
1170cfbaf6c3Scth  * detached, it will return failure.  This failure should be propagated
1171cfbaf6c3Scth  * to the requesting administrative application using the appropriate
1172cfbaf6c3Scth  * post-open(9E) API error mechanism.
1173cfbaf6c3Scth  *
1174cfbaf6c3Scth  * All qassociate() callers are expected to check for and gracefully handle
1175cfbaf6c3Scth  * failure return, propagating errors back to the requesting administrative
1176cfbaf6c3Scth  * application.
11777c478bd9Sstevel@tonic-gate  */
11787c478bd9Sstevel@tonic-gate int
11797c478bd9Sstevel@tonic-gate qassociate(queue_t *q, int instance)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate 	vnode_t *vp;
11827c478bd9Sstevel@tonic-gate 	major_t major;
11837c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (instance == -1) {
11867c478bd9Sstevel@tonic-gate 		ddi_assoc_queue_with_devi(q, NULL);
11877c478bd9Sstevel@tonic-gate 		return (0);
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	vp = STREAM(q)->sd_vnode;
11917c478bd9Sstevel@tonic-gate 	major = getmajor(vp->v_rdev);
11927c478bd9Sstevel@tonic-gate 	dip = ddi_hold_devi_by_instance(major, instance,
11937c478bd9Sstevel@tonic-gate 	    E_DDI_HOLD_DEVI_NOATTACH);
11947c478bd9Sstevel@tonic-gate 	if (dip == NULL)
11957c478bd9Sstevel@tonic-gate 		return (-1);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	ddi_assoc_queue_with_devi(q, dip);
11987c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
11997c478bd9Sstevel@tonic-gate 	return (0);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate  * This routine is the SVR4MP 'replacement' for
12047c478bd9Sstevel@tonic-gate  * hat_getkpfnum.  The only major difference is
12057c478bd9Sstevel@tonic-gate  * the return value for illegal addresses - since
12067c478bd9Sstevel@tonic-gate  * sunm_getkpfnum() and srmmu_getkpfnum() both
12077c478bd9Sstevel@tonic-gate  * return '-1' for bogus mappings, we can (more or
12087c478bd9Sstevel@tonic-gate  * less) return the value directly.
12097c478bd9Sstevel@tonic-gate  */
12107c478bd9Sstevel@tonic-gate ppid_t
12117c478bd9Sstevel@tonic-gate kvtoppid(caddr_t addr)
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	return ((ppid_t)hat_getpfnum(kas.a_hat, addr));
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate /*
12177c478bd9Sstevel@tonic-gate  * This is used to set the timeout value for cv_timed_wait() or
12187c478bd9Sstevel@tonic-gate  * cv_timedwait_sig().
12197c478bd9Sstevel@tonic-gate  */
12207c478bd9Sstevel@tonic-gate void
12217c478bd9Sstevel@tonic-gate time_to_wait(clock_t *now, clock_t time)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	*now = lbolt + time;
12247c478bd9Sstevel@tonic-gate }
1225