xref: /onnv-gate/usr/src/uts/common/os/ddi.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
220Sstevel@tonic-gate /*	  All Rights Reserved  	*/
230Sstevel@tonic-gate 
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
26*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
270Sstevel@tonic-gate  * Use is subject to license terms.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * UNIX Device Driver Interface functions
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * This file contains functions that are to be added to the kernel
340Sstevel@tonic-gate  * to put the interface presented to drivers in conformance with
350Sstevel@tonic-gate  * the DDI standard. Of the functions added to the kernel, 17 are
360Sstevel@tonic-gate  * function equivalents of existing macros in sysmacros.h,
370Sstevel@tonic-gate  * stream.h, and param.h
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * 17 additional functions -- drv_getparm(), drv_setparm(),
400Sstevel@tonic-gate  * getrbuf(), freerbuf(),
410Sstevel@tonic-gate  * getemajor(), geteminor(), etoimajor(), itoemajor(), drv_usectohz(),
420Sstevel@tonic-gate  * drv_hztousec(), drv_usecwait(), drv_priv(), and kvtoppid() --
430Sstevel@tonic-gate  * are specified by DDI to exist in the kernel and are implemented here.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * Note that putnext() and put() are not in this file. The C version of
460Sstevel@tonic-gate  * these routines are in uts/common/os/putnext.c and assembly versions
470Sstevel@tonic-gate  * might exist for some architectures.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <sys/types.h>
510Sstevel@tonic-gate #include <sys/param.h>
520Sstevel@tonic-gate #include <sys/t_lock.h>
530Sstevel@tonic-gate #include <sys/time.h>
540Sstevel@tonic-gate #include <sys/systm.h>
550Sstevel@tonic-gate #include <sys/cpuvar.h>
560Sstevel@tonic-gate #include <sys/signal.h>
570Sstevel@tonic-gate #include <sys/pcb.h>
580Sstevel@tonic-gate #include <sys/user.h>
590Sstevel@tonic-gate #include <sys/errno.h>
600Sstevel@tonic-gate #include <sys/buf.h>
610Sstevel@tonic-gate #include <sys/proc.h>
620Sstevel@tonic-gate #include <sys/cmn_err.h>
630Sstevel@tonic-gate #include <sys/stream.h>
640Sstevel@tonic-gate #include <sys/strsubr.h>
650Sstevel@tonic-gate #include <sys/uio.h>
660Sstevel@tonic-gate #include <sys/kmem.h>
670Sstevel@tonic-gate #include <sys/conf.h>
680Sstevel@tonic-gate #include <sys/cred.h>
690Sstevel@tonic-gate #include <sys/vnode.h>
700Sstevel@tonic-gate #include <sys/file.h>
710Sstevel@tonic-gate #include <sys/poll.h>
720Sstevel@tonic-gate #include <sys/session.h>
730Sstevel@tonic-gate #include <sys/ddi.h>
740Sstevel@tonic-gate #include <sys/sunddi.h>
750Sstevel@tonic-gate #include <sys/esunddi.h>
760Sstevel@tonic-gate #include <sys/mkdev.h>
770Sstevel@tonic-gate #include <sys/debug.h>
780Sstevel@tonic-gate #include <sys/vtrace.h>
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * return internal major number corresponding to device
820Sstevel@tonic-gate  * number (new format) argument
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate major_t
getmajor(dev_t dev)850Sstevel@tonic-gate getmajor(dev_t dev)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate #ifdef _LP64
880Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
890Sstevel@tonic-gate #else
900Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
910Sstevel@tonic-gate #endif
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * return external major number corresponding to device
960Sstevel@tonic-gate  * number (new format) argument
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate major_t
getemajor(dev_t dev)990Sstevel@tonic-gate getemajor(dev_t dev)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate #ifdef _LP64
1020Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
1030Sstevel@tonic-gate #else
1040Sstevel@tonic-gate 	return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
1050Sstevel@tonic-gate #endif
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * return internal minor number corresponding to device
1100Sstevel@tonic-gate  * number (new format) argument
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate minor_t
getminor(dev_t dev)1130Sstevel@tonic-gate getminor(dev_t dev)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate #ifdef _LP64
1160Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN64));
1170Sstevel@tonic-gate #else
1180Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN));
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * return external minor number corresponding to device
1240Sstevel@tonic-gate  * number (new format) argument
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate minor_t
geteminor(dev_t dev)1270Sstevel@tonic-gate geteminor(dev_t dev)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate #ifdef _LP64
1300Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN64));
1310Sstevel@tonic-gate #else
1320Sstevel@tonic-gate 	return ((minor_t)(dev & MAXMIN));
1330Sstevel@tonic-gate #endif
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * return internal major number corresponding to external
1380Sstevel@tonic-gate  * major number.
1390Sstevel@tonic-gate  */
1400Sstevel@tonic-gate int
etoimajor(major_t emajnum)1410Sstevel@tonic-gate etoimajor(major_t emajnum)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate #ifdef _LP64
1440Sstevel@tonic-gate 	if (emajnum >= devcnt)
1450Sstevel@tonic-gate 		return (-1); /* invalid external major */
1460Sstevel@tonic-gate #else
1470Sstevel@tonic-gate 	if (emajnum > MAXMAJ || emajnum >= devcnt)
1480Sstevel@tonic-gate 		return (-1); /* invalid external major */
1490Sstevel@tonic-gate #endif
1500Sstevel@tonic-gate 	return ((int)emajnum);
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * return external major number corresponding to internal
1550Sstevel@tonic-gate  * major number argument or -1 if no external major number
1560Sstevel@tonic-gate  * can be found after lastemaj that maps to the internal
1570Sstevel@tonic-gate  * major number. Pass a lastemaj val of -1 to start
1580Sstevel@tonic-gate  * the search initially. (Typical use of this function is
1590Sstevel@tonic-gate  * of the form:
1600Sstevel@tonic-gate  *
1610Sstevel@tonic-gate  *	lastemaj = -1;
1620Sstevel@tonic-gate  *	while ((lastemaj = itoemajor(imag, lastemaj)) != -1)
1630Sstevel@tonic-gate  *		{ process major number }
1640Sstevel@tonic-gate  */
1650Sstevel@tonic-gate int
itoemajor(major_t imajnum,int lastemaj)1660Sstevel@tonic-gate itoemajor(major_t imajnum, int lastemaj)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	if (imajnum >= devcnt)
1690Sstevel@tonic-gate 		return (-1);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/*
1720Sstevel@tonic-gate 	 * if lastemaj == -1 then start from beginning of
1730Sstevel@tonic-gate 	 * the (imaginary) MAJOR table
1740Sstevel@tonic-gate 	 */
1750Sstevel@tonic-gate 	if (lastemaj < -1)
1760Sstevel@tonic-gate 		return (-1);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * given that there's a 1-1 mapping of internal to external
1800Sstevel@tonic-gate 	 * major numbers, searching is somewhat pointless ... let's
1810Sstevel@tonic-gate 	 * just go there directly.
1820Sstevel@tonic-gate 	 */
1830Sstevel@tonic-gate 	if (++lastemaj < devcnt && imajnum < devcnt)
1840Sstevel@tonic-gate 		return (imajnum);
1850Sstevel@tonic-gate 	return (-1);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * encode external major and minor number arguments into a
1900Sstevel@tonic-gate  * new format device number
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate dev_t
makedevice(major_t maj,minor_t minor)1930Sstevel@tonic-gate makedevice(major_t maj, minor_t minor)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate #ifdef _LP64
1960Sstevel@tonic-gate 	return (((dev_t)maj << NBITSMINOR64) | (minor & MAXMIN64));
1970Sstevel@tonic-gate #else
1980Sstevel@tonic-gate 	return (((dev_t)maj << NBITSMINOR) | (minor & MAXMIN));
1990Sstevel@tonic-gate #endif
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * cmpdev - compress new device format to old device format
2040Sstevel@tonic-gate  */
2050Sstevel@tonic-gate o_dev_t
cmpdev(dev_t dev)2060Sstevel@tonic-gate cmpdev(dev_t dev)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	major_t major_d;
2090Sstevel@tonic-gate 	minor_t minor_d;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate #ifdef _LP64
2120Sstevel@tonic-gate 	major_d = dev >> NBITSMINOR64;
2130Sstevel@tonic-gate 	minor_d = dev & MAXMIN64;
2140Sstevel@tonic-gate #else
2150Sstevel@tonic-gate 	major_d = dev >> NBITSMINOR;
2160Sstevel@tonic-gate 	minor_d = dev & MAXMIN;
2170Sstevel@tonic-gate #endif
2180Sstevel@tonic-gate 	if (major_d > OMAXMAJ || minor_d > OMAXMIN)
2190Sstevel@tonic-gate 		return ((o_dev_t)NODEV);
2200Sstevel@tonic-gate 	return ((o_dev_t)((major_d << ONBITSMINOR) | minor_d));
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate dev_t
expdev(dev_t dev)2240Sstevel@tonic-gate expdev(dev_t dev)
2250Sstevel@tonic-gate {
2260Sstevel@tonic-gate 	major_t major_d;
2270Sstevel@tonic-gate 	minor_t minor_d;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	major_d = ((dev >> ONBITSMINOR) & OMAXMAJ);
2300Sstevel@tonic-gate 	minor_d = (dev & OMAXMIN);
2310Sstevel@tonic-gate #ifdef _LP64
2320Sstevel@tonic-gate 	return ((((dev_t)major_d << NBITSMINOR64) | minor_d));
2330Sstevel@tonic-gate #else
2340Sstevel@tonic-gate 	return ((((dev_t)major_d << NBITSMINOR) | minor_d));
2350Sstevel@tonic-gate #endif
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * return true (1) if the message type input is a data
2400Sstevel@tonic-gate  * message type, 0 otherwise
2410Sstevel@tonic-gate  */
2420Sstevel@tonic-gate #undef datamsg
2430Sstevel@tonic-gate int
datamsg(unsigned char db_type)2440Sstevel@tonic-gate datamsg(unsigned char db_type)
2450Sstevel@tonic-gate {
2460Sstevel@tonic-gate 	return (db_type == M_DATA || db_type == M_PROTO ||
2474630Sksn 	    db_type == M_PCPROTO || db_type == M_DELAY);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  * return a pointer to the other queue in the queue pair of qp
2520Sstevel@tonic-gate  */
2530Sstevel@tonic-gate queue_t *
OTHERQ(queue_t * q)2540Sstevel@tonic-gate OTHERQ(queue_t *q)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	return (_OTHERQ(q));
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate /*
2600Sstevel@tonic-gate  * return a pointer to the read queue in the queue pair of qp.
2610Sstevel@tonic-gate  */
2620Sstevel@tonic-gate queue_t *
RD(queue_t * q)2630Sstevel@tonic-gate RD(queue_t *q)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 		return (_RD(q));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * return a pointer to the write queue in the queue pair of qp.
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate int
SAMESTR(queue_t * q)2730Sstevel@tonic-gate SAMESTR(queue_t *q)
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate 	return (_SAMESTR(q));
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * return a pointer to the write queue in the queue pair of qp.
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate queue_t *
WR(queue_t * q)2820Sstevel@tonic-gate WR(queue_t *q)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	return (_WR(q));
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * store value of kernel parameter associated with parm
2890Sstevel@tonic-gate  */
2900Sstevel@tonic-gate int
drv_getparm(unsigned int parm,void * valuep)2910Sstevel@tonic-gate drv_getparm(unsigned int parm, void *valuep)
2920Sstevel@tonic-gate {
2932712Snn35248 	proc_t	*p = curproc;
2942712Snn35248 	time_t	now;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	switch (parm) {
2970Sstevel@tonic-gate 	case UPROCP:
2982712Snn35248 		*(proc_t **)valuep = p;
2990Sstevel@tonic-gate 		break;
3000Sstevel@tonic-gate 	case PPGRP:
3014630Sksn 		mutex_enter(&p->p_lock);
3022712Snn35248 		*(pid_t *)valuep = p->p_pgrp;
3034630Sksn 		mutex_exit(&p->p_lock);
3040Sstevel@tonic-gate 		break;
3050Sstevel@tonic-gate 	case LBOLT:
306*11066Srafael.vanoni@sun.com 		*(clock_t *)valuep = ddi_get_lbolt();
3070Sstevel@tonic-gate 		break;
3080Sstevel@tonic-gate 	case TIME:
3090Sstevel@tonic-gate 		if ((now = gethrestime_sec()) == 0) {
3100Sstevel@tonic-gate 			timestruc_t ts;
3110Sstevel@tonic-gate 			mutex_enter(&tod_lock);
3120Sstevel@tonic-gate 			ts = tod_get();
3130Sstevel@tonic-gate 			mutex_exit(&tod_lock);
3140Sstevel@tonic-gate 			*(time_t *)valuep = ts.tv_sec;
3150Sstevel@tonic-gate 		} else {
3160Sstevel@tonic-gate 			*(time_t *)valuep = now;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 		break;
3190Sstevel@tonic-gate 	case PPID:
3202712Snn35248 		*(pid_t *)valuep = p->p_pid;
3210Sstevel@tonic-gate 		break;
3220Sstevel@tonic-gate 	case PSID:
3232712Snn35248 		mutex_enter(&p->p_splock);
3242712Snn35248 		*(pid_t *)valuep = p->p_sessp->s_sid;
3252712Snn35248 		mutex_exit(&p->p_splock);
3260Sstevel@tonic-gate 		break;
3270Sstevel@tonic-gate 	case UCRED:
3280Sstevel@tonic-gate 		*(cred_t **)valuep = CRED();
3290Sstevel@tonic-gate 		break;
3300Sstevel@tonic-gate 	default:
3310Sstevel@tonic-gate 		return (-1);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	return (0);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate  * set value of kernel parameter associated with parm
3390Sstevel@tonic-gate  */
3400Sstevel@tonic-gate int
drv_setparm(unsigned int parm,unsigned long value)3410Sstevel@tonic-gate drv_setparm(unsigned int parm, unsigned long value)
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	switch (parm) {
3440Sstevel@tonic-gate 	case SYSRINT:
3450Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, rcvint, value);
3460Sstevel@tonic-gate 		break;
3470Sstevel@tonic-gate 	case SYSXINT:
3480Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, xmtint, value);
3490Sstevel@tonic-gate 		break;
3500Sstevel@tonic-gate 	case SYSMINT:
3510Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, mdmint, value);
3520Sstevel@tonic-gate 		break;
3530Sstevel@tonic-gate 	case SYSRAWC:
3540Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, rawch, value);
3550Sstevel@tonic-gate 		break;
3560Sstevel@tonic-gate 	case SYSCANC:
3570Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, canch, value);
3580Sstevel@tonic-gate 		break;
3590Sstevel@tonic-gate 	case SYSOUTC:
3600Sstevel@tonic-gate 		CPU_STATS_ADDQ(CPU, sys, outch, value);
3610Sstevel@tonic-gate 		break;
3620Sstevel@tonic-gate 	default:
3630Sstevel@tonic-gate 		return (-1);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	return (0);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate /*
3700Sstevel@tonic-gate  * allocate space for buffer header and return pointer to it.
3710Sstevel@tonic-gate  * preferred means of obtaining space for a local buf header.
3720Sstevel@tonic-gate  * returns pointer to buf upon success, NULL for failure
3730Sstevel@tonic-gate  */
3740Sstevel@tonic-gate struct buf *
getrbuf(int sleep)3750Sstevel@tonic-gate getrbuf(int sleep)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	struct buf *bp;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	bp = kmem_alloc(sizeof (struct buf), sleep);
3800Sstevel@tonic-gate 	if (bp == NULL)
3810Sstevel@tonic-gate 		return (NULL);
3820Sstevel@tonic-gate 	bioinit(bp);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	return (bp);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate  * free up space allocated by getrbuf()
3890Sstevel@tonic-gate  */
3900Sstevel@tonic-gate void
freerbuf(struct buf * bp)3910Sstevel@tonic-gate freerbuf(struct buf *bp)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	biofini(bp);
3940Sstevel@tonic-gate 	kmem_free(bp, sizeof (struct buf));
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  * convert byte count input to logical page units
3990Sstevel@tonic-gate  * (byte counts that are not a page-size multiple
4000Sstevel@tonic-gate  * are rounded down)
4010Sstevel@tonic-gate  */
4020Sstevel@tonic-gate pgcnt_t
btop(size_t numbytes)4030Sstevel@tonic-gate btop(size_t numbytes)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	return (numbytes >> PAGESHIFT);
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate /*
4090Sstevel@tonic-gate  * convert byte count input to logical page units
4100Sstevel@tonic-gate  * (byte counts that are not a page-size multiple
4110Sstevel@tonic-gate  * are rounded up)
4120Sstevel@tonic-gate  */
4130Sstevel@tonic-gate pgcnt_t
btopr(size_t numbytes)4140Sstevel@tonic-gate btopr(size_t numbytes)
4150Sstevel@tonic-gate {
4160Sstevel@tonic-gate 	return ((numbytes + PAGEOFFSET) >> PAGESHIFT);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * convert size in pages to bytes.
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate size_t
ptob(pgcnt_t numpages)4230Sstevel@tonic-gate ptob(pgcnt_t numpages)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate 	return (numpages << PAGESHIFT);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate #define	MAXCLOCK_T LONG_MAX
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * Convert from system time units (hz) to microseconds.
4320Sstevel@tonic-gate  *
4330Sstevel@tonic-gate  * If ticks <= 0, return 0.
4340Sstevel@tonic-gate  * If converting ticks to usecs would overflow, return MAXCLOCK_T.
4350Sstevel@tonic-gate  * Otherwise, convert ticks to microseconds.
4360Sstevel@tonic-gate  */
4370Sstevel@tonic-gate clock_t
drv_hztousec(clock_t ticks)4380Sstevel@tonic-gate drv_hztousec(clock_t ticks)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate 	if (ticks <= 0)
4410Sstevel@tonic-gate 		return (0);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if (ticks > MAXCLOCK_T / usec_per_tick)
4440Sstevel@tonic-gate 		return (MAXCLOCK_T);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (TICK_TO_USEC(ticks));
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * Convert from microseconds to system time units (hz), rounded up.
4520Sstevel@tonic-gate  *
4530Sstevel@tonic-gate  * If ticks <= 0, return 0.
4540Sstevel@tonic-gate  * Otherwise, convert microseconds to ticks, rounding up.
4550Sstevel@tonic-gate  */
4560Sstevel@tonic-gate clock_t
drv_usectohz(clock_t microsecs)4570Sstevel@tonic-gate drv_usectohz(clock_t microsecs)
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate 	if (microsecs <= 0)
4600Sstevel@tonic-gate 		return (0);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	return (USEC_TO_TICK_ROUNDUP(microsecs));
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate #ifdef	sun
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate  * drv_usecwait implemented in each architecture's machine
4680Sstevel@tonic-gate  * specific code somewhere. For sparc, it is the alternate entry
4690Sstevel@tonic-gate  * to usec_delay (eventually usec_delay goes away). See
4700Sstevel@tonic-gate  * sparc/os/ml/sparc_subr.s
4710Sstevel@tonic-gate  */
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate  * bcanputnext, canputnext assume called from timeout, bufcall,
4760Sstevel@tonic-gate  * or esballoc free routines.  since these are driven by
4770Sstevel@tonic-gate  * clock interrupts, instead of system calls the appropriate plumbing
4780Sstevel@tonic-gate  * locks have not been acquired.
4790Sstevel@tonic-gate  */
4800Sstevel@tonic-gate int
bcanputnext(queue_t * q,unsigned char band)4810Sstevel@tonic-gate bcanputnext(queue_t *q, unsigned char band)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	int	ret;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	claimstr(q);
4860Sstevel@tonic-gate 	ret = bcanput(q->q_next, band);
4870Sstevel@tonic-gate 	releasestr(q);
4880Sstevel@tonic-gate 	return (ret);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate int
canputnext(queue_t * q)4920Sstevel@tonic-gate canputnext(queue_t *q)
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate 	queue_t	*qofsq = q;
4950Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
4960Sstevel@tonic-gate 	kmutex_t *sdlock;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	TRACE_1(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_IN,
4990Sstevel@tonic-gate 	    "canputnext?:%p\n", q);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	if (stp->sd_ciputctrl != NULL) {
5020Sstevel@tonic-gate 		int ix = CPU->cpu_seqid & stp->sd_nciputctrl;
5030Sstevel@tonic-gate 		sdlock = &stp->sd_ciputctrl[ix].ciputctrl_lock;
5040Sstevel@tonic-gate 		mutex_enter(sdlock);
5050Sstevel@tonic-gate 	} else
5060Sstevel@tonic-gate 		mutex_enter(sdlock = &stp->sd_reflock);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	/* get next module forward with a service queue */
5090Sstevel@tonic-gate 	q = q->q_next->q_nfsrv;
5100Sstevel@tonic-gate 	ASSERT(q != NULL);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/* this is for loopback transports, they should not do a canputnext */
5130Sstevel@tonic-gate 	ASSERT(STRMATED(q->q_stream) || STREAM(q) == STREAM(qofsq));
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	if (!(q->q_flag & QFULL)) {
5160Sstevel@tonic-gate 		mutex_exit(sdlock);
5170Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT,
5180Sstevel@tonic-gate 		    "canputnext:%p %d", q, 1);
5190Sstevel@tonic-gate 		return (1);
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	if (sdlock != &stp->sd_reflock) {
5230Sstevel@tonic-gate 		mutex_exit(sdlock);
5240Sstevel@tonic-gate 		mutex_enter(&stp->sd_reflock);
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	/* the above is the most frequently used path */
5280Sstevel@tonic-gate 	stp->sd_refcnt++;
5290Sstevel@tonic-gate 	ASSERT(stp->sd_refcnt != 0);	/* Wraparound */
5300Sstevel@tonic-gate 	mutex_exit(&stp->sd_reflock);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	mutex_enter(QLOCK(q));
5330Sstevel@tonic-gate 	if (q->q_flag & QFULL) {
5340Sstevel@tonic-gate 		q->q_flag |= QWANTW;
5350Sstevel@tonic-gate 		mutex_exit(QLOCK(q));
5360Sstevel@tonic-gate 		TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT,
5370Sstevel@tonic-gate 		    "canputnext:%p %d", q, 0);
5380Sstevel@tonic-gate 		releasestr(qofsq);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		return (0);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 	mutex_exit(QLOCK(q));
5430Sstevel@tonic-gate 	TRACE_2(TR_FAC_STREAMS_FR, TR_CANPUTNEXT_OUT, "canputnext:%p %d", q, 1);
5440Sstevel@tonic-gate 	releasestr(qofsq);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	return (1);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * Open has progressed to the point where it is safe to send/receive messages.
5520Sstevel@tonic-gate  *
5530Sstevel@tonic-gate  * "qprocson enables the put and service routines of the driver
5540Sstevel@tonic-gate  * or module... Prior to the call to qprocson, the put and service
5550Sstevel@tonic-gate  * routines of a newly pushed module or newly opened driver are
5560Sstevel@tonic-gate  * disabled.  For the module, messages flow around it as if it
5570Sstevel@tonic-gate  * were not present in the stream... qprocson must be called by
5580Sstevel@tonic-gate  * the first open of a module or driver after allocation and
5590Sstevel@tonic-gate  * initialization of any resource on which the put and service
5600Sstevel@tonic-gate  * routines depend."
5610Sstevel@tonic-gate  *
5620Sstevel@tonic-gate  * Note that before calling qprocson a module/driver could itself cause its
5630Sstevel@tonic-gate  * put or service procedures to be run by using put() or qenable().
5640Sstevel@tonic-gate  */
5650Sstevel@tonic-gate void
qprocson(queue_t * q)5660Sstevel@tonic-gate qprocson(queue_t *q)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
5690Sstevel@tonic-gate 	/*
5700Sstevel@tonic-gate 	 * Do not call insertq() if it is a re-open.  But if _QINSERTING
5710Sstevel@tonic-gate 	 * is set, q_next will not be NULL and we need to call insertq().
5720Sstevel@tonic-gate 	 */
5730Sstevel@tonic-gate 	if ((q->q_next == NULL && WR(q)->q_next == NULL) ||
5740Sstevel@tonic-gate 	    (q->q_flag & _QINSERTING))
5750Sstevel@tonic-gate 		insertq(STREAM(q), q);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate /*
5790Sstevel@tonic-gate  * Close has reached a point where it can no longer allow put/service
5800Sstevel@tonic-gate  * into the queue.
5810Sstevel@tonic-gate  *
5820Sstevel@tonic-gate  * "qprocsoff disables the put and service routines of the driver
5830Sstevel@tonic-gate  * or module... When the routines are disabled in a module, messages
5840Sstevel@tonic-gate  * flow around the module as if it were not present in the stream.
5850Sstevel@tonic-gate  * qprocsoff must be called by the close routine of a driver or module
5860Sstevel@tonic-gate  * before deallocating any resources on which the driver/module's
5870Sstevel@tonic-gate  * put and service routines depend.  qprocsoff will remove the
5880Sstevel@tonic-gate  * queue's service routines from the list of service routines to be
5890Sstevel@tonic-gate  * run and waits until any concurrent put or service routines are
5900Sstevel@tonic-gate  * finished."
5910Sstevel@tonic-gate  *
5920Sstevel@tonic-gate  * Note that after calling qprocsoff a module/driver could itself cause its
5930Sstevel@tonic-gate  * put procedures to be run by using put().
5940Sstevel@tonic-gate  */
5950Sstevel@tonic-gate void
qprocsoff(queue_t * q)5960Sstevel@tonic-gate qprocsoff(queue_t *q)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	ASSERT(q->q_flag & QREADR);
5990Sstevel@tonic-gate 	if (q->q_flag & QWCLOSE) {
6000Sstevel@tonic-gate 		/* Called more than once */
6010Sstevel@tonic-gate 		return;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 	disable_svc(q);
6040Sstevel@tonic-gate 	removeq(q);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate  * "freezestr() freezes the state of the entire STREAM  containing
6090Sstevel@tonic-gate  *  the  queue  pair  q.  A frozen STREAM blocks any thread
6100Sstevel@tonic-gate  *  attempting to enter any open, close, put or service  routine
6110Sstevel@tonic-gate  *  belonging  to  any  queue instance in the STREAM, and blocks
6120Sstevel@tonic-gate  *  any thread currently within the STREAM if it attempts to put
6130Sstevel@tonic-gate  *  messages  onto  or take messages off of any queue within the
6140Sstevel@tonic-gate  *  STREAM (with the sole exception  of  the  caller).   Threads
6150Sstevel@tonic-gate  *  blocked  by  this  mechanism  remain  so until the STREAM is
6160Sstevel@tonic-gate  *  thawed by a call to unfreezestr().
6170Sstevel@tonic-gate  *
6180Sstevel@tonic-gate  * Use strblock to set SQ_FROZEN in all syncqs in the stream (prevents
6190Sstevel@tonic-gate  * further entry into put, service, open, and close procedures) and
6200Sstevel@tonic-gate  * grab (and hold) all the QLOCKs in the stream (to block putq, getq etc.)
6210Sstevel@tonic-gate  *
6220Sstevel@tonic-gate  * Note: this has to be the only code that acquires one QLOCK while holding
6230Sstevel@tonic-gate  * another QLOCK (otherwise we would have locking hirarchy/ordering violations.)
6240Sstevel@tonic-gate  */
6250Sstevel@tonic-gate void
freezestr(queue_t * q)6260Sstevel@tonic-gate freezestr(queue_t *q)
6270Sstevel@tonic-gate {
6280Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	/*
6310Sstevel@tonic-gate 	 * Increment refcnt to prevent q_next from changing during the strblock
6320Sstevel@tonic-gate 	 * as well as while the stream is frozen.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	claimstr(RD(q));
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	strblock(q);
6370Sstevel@tonic-gate 	ASSERT(stp->sd_freezer == NULL);
6380Sstevel@tonic-gate 	stp->sd_freezer = curthread;
6390Sstevel@tonic-gate 	for (q = stp->sd_wrq; q != NULL; q = SAMESTR(q) ? q->q_next : NULL) {
6400Sstevel@tonic-gate 		mutex_enter(QLOCK(q));
6410Sstevel@tonic-gate 		mutex_enter(QLOCK(RD(q)));
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate  * Undo what freezestr did.
6470Sstevel@tonic-gate  * Have to drop the QLOCKs before the strunblock since strunblock will
6480Sstevel@tonic-gate  * potentially call other put procedures.
6490Sstevel@tonic-gate  */
6500Sstevel@tonic-gate void
unfreezestr(queue_t * q)6510Sstevel@tonic-gate unfreezestr(queue_t *q)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate 	struct stdata *stp = STREAM(q);
6540Sstevel@tonic-gate 	queue_t	*q1;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	for (q1 = stp->sd_wrq; q1 != NULL;
6570Sstevel@tonic-gate 	    q1 = SAMESTR(q1) ? q1->q_next : NULL) {
6580Sstevel@tonic-gate 		mutex_exit(QLOCK(q1));
6590Sstevel@tonic-gate 		mutex_exit(QLOCK(RD(q1)));
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 	ASSERT(stp->sd_freezer == curthread);
6620Sstevel@tonic-gate 	stp->sd_freezer = NULL;
6630Sstevel@tonic-gate 	strunblock(q);
6640Sstevel@tonic-gate 	releasestr(RD(q));
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate  * Used by open and close procedures to "sleep" waiting for messages to
6690Sstevel@tonic-gate  * arrive. Note: can only be used in open and close procedures.
6700Sstevel@tonic-gate  *
6710Sstevel@tonic-gate  * Lower the gate and let in either messages on the syncq (if there are
6720Sstevel@tonic-gate  * any) or put/service procedures.
6730Sstevel@tonic-gate  *
6740Sstevel@tonic-gate  * If the queue has an outer perimeter this will not prevent entry into this
6750Sstevel@tonic-gate  * syncq (since outer_enter does not set SQ_WRITER on the syncq that gets the
6760Sstevel@tonic-gate  * exclusive access to the outer perimeter.)
6770Sstevel@tonic-gate  *
6780Sstevel@tonic-gate  * Return 0 is the cv_wait_sig was interrupted; otherwise 1.
6790Sstevel@tonic-gate  *
6800Sstevel@tonic-gate  * It only makes sense to grab sq_putlocks for !SQ_CIOC sync queues because
6810Sstevel@tonic-gate  * otherwise put entry points were not blocked in the first place. if this is
6820Sstevel@tonic-gate  * SQ_CIOC then qwait is used to wait for service procedure to run since syncq
6830Sstevel@tonic-gate  * is always SQ_CIPUT if it is SQ_CIOC.
6840Sstevel@tonic-gate  *
6850Sstevel@tonic-gate  * Note that SQ_EXCL is dropped and SQ_WANTEXITWAKEUP set in sq_flags
6860Sstevel@tonic-gate  * atomically under sq_putlocks to make sure putnext will not miss a pending
6870Sstevel@tonic-gate  * wakeup.
6880Sstevel@tonic-gate  */
6890Sstevel@tonic-gate int
qwait_sig(queue_t * q)6900Sstevel@tonic-gate qwait_sig(queue_t *q)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	syncq_t		*sq, *outer;
6930Sstevel@tonic-gate 	uint_t		flags;
6940Sstevel@tonic-gate 	int		ret = 1;
6950Sstevel@tonic-gate 	int		is_sq_cioc;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	/*
6980Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_OPENCLOSE)
6990Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
7000Sstevel@tonic-gate 	 * so that qwait_sig can return to the caller.
7010Sstevel@tonic-gate 	 *
7020Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
7030Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
7040Sstevel@tonic-gate 	 */
7050Sstevel@tonic-gate 	sq = q->q_syncq;
7060Sstevel@tonic-gate 	ASSERT(sq);
7070Sstevel@tonic-gate 	is_sq_cioc = (sq->sq_type & SQ_CIOC) ? 1 : 0;
7080Sstevel@tonic-gate 	ASSERT(sq->sq_outer == NULL || sq->sq_outer->sq_flags & SQ_WRITER);
7090Sstevel@tonic-gate 	outer = sq->sq_outer;
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * XXX this does not work if there is only an outer perimeter.
7120Sstevel@tonic-gate 	 * The semantics of qwait/qwait_sig are undefined in this case.
7130Sstevel@tonic-gate 	 */
7140Sstevel@tonic-gate 	if (outer)
7150Sstevel@tonic-gate 		outer_exit(outer);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
7180Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7190Sstevel@tonic-gate 		SQ_PUTLOCKS_ENTER(sq);
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 	flags = sq->sq_flags;
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK
7240Sstevel@tonic-gate 	 * to prevent any undetected entry and exit into the perimeter.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
7270Sstevel@tonic-gate 	sq->sq_count--;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7300Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
7310Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 	/*
7340Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
7350Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
7360Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
7370Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
7380Sstevel@tonic-gate 	 */
7390Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
7400Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
7410Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 	sq->sq_flags = flags;
7440Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
7450Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7460Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
7490Sstevel@tonic-gate 		drain_syncq(sq);
7500Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
7510Sstevel@tonic-gate 		entersq(sq, SQ_OPENCLOSE);
7520Sstevel@tonic-gate 		return (1);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 	/*
7550Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
7560Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
7570Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
7580Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
7590Sstevel@tonic-gate 	 */
7600Sstevel@tonic-gate 	do {
7610Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
7620Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7630Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
7640Sstevel@tonic-gate 		}
7650Sstevel@tonic-gate 		ret = cv_wait_sig(&sq->sq_exitwait, SQLOCK(sq));
7660Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
7670Sstevel@tonic-gate 			SQ_PUTLOCKS_ENTER(sq);
7680Sstevel@tonic-gate 		}
7690Sstevel@tonic-gate 	} while (ret && (sq->sq_flags & SQ_WANTEXWAKEUP));
7700Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
7710Sstevel@tonic-gate 		SQ_PUTLOCKS_EXIT(sq);
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/*
7760Sstevel@tonic-gate 	 * Re-enter the perimeters again
7770Sstevel@tonic-gate 	 */
7780Sstevel@tonic-gate 	entersq(sq, SQ_OPENCLOSE);
7790Sstevel@tonic-gate 	return (ret);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate  * Used by open and close procedures to "sleep" waiting for messages to
7840Sstevel@tonic-gate  * arrive. Note: can only be used in open and close procedures.
7850Sstevel@tonic-gate  *
7860Sstevel@tonic-gate  * Lower the gate and let in either messages on the syncq (if there are
7870Sstevel@tonic-gate  * any) or put/service procedures.
7880Sstevel@tonic-gate  *
7890Sstevel@tonic-gate  * If the queue has an outer perimeter this will not prevent entry into this
7900Sstevel@tonic-gate  * syncq (since outer_enter does not set SQ_WRITER on the syncq that gets the
7910Sstevel@tonic-gate  * exclusive access to the outer perimeter.)
7920Sstevel@tonic-gate  *
7930Sstevel@tonic-gate  * It only makes sense to grab sq_putlocks for !SQ_CIOC sync queues because
7940Sstevel@tonic-gate  * otherwise put entry points were not blocked in the first place. if this is
7950Sstevel@tonic-gate  * SQ_CIOC then qwait is used to wait for service procedure to run since syncq
7960Sstevel@tonic-gate  * is always SQ_CIPUT if it is SQ_CIOC.
7970Sstevel@tonic-gate  *
7980Sstevel@tonic-gate  * Note that SQ_EXCL is dropped and SQ_WANTEXITWAKEUP set in sq_flags
7990Sstevel@tonic-gate  * atomically under sq_putlocks to make sure putnext will not miss a pending
8000Sstevel@tonic-gate  * wakeup.
8010Sstevel@tonic-gate  */
8020Sstevel@tonic-gate void
qwait(queue_t * q)8030Sstevel@tonic-gate qwait(queue_t *q)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	syncq_t		*sq, *outer;
8060Sstevel@tonic-gate 	uint_t		flags;
8070Sstevel@tonic-gate 	int		is_sq_cioc;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/*
8100Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_OPENCLOSE)
8110Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
8120Sstevel@tonic-gate 	 * so that qwait can return to the caller.
8130Sstevel@tonic-gate 	 *
8140Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
8150Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
8160Sstevel@tonic-gate 	 */
8170Sstevel@tonic-gate 	sq = q->q_syncq;
8180Sstevel@tonic-gate 	ASSERT(sq);
8190Sstevel@tonic-gate 	is_sq_cioc = (sq->sq_type & SQ_CIOC) ? 1 : 0;
8200Sstevel@tonic-gate 	ASSERT(sq->sq_outer == NULL || sq->sq_outer->sq_flags & SQ_WRITER);
8210Sstevel@tonic-gate 	outer = sq->sq_outer;
8220Sstevel@tonic-gate 	/*
8230Sstevel@tonic-gate 	 * XXX this does not work if there is only an outer perimeter.
8240Sstevel@tonic-gate 	 * The semantics of qwait/qwait_sig are undefined in this case.
8250Sstevel@tonic-gate 	 */
8260Sstevel@tonic-gate 	if (outer)
8270Sstevel@tonic-gate 		outer_exit(outer);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
8300Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8310Sstevel@tonic-gate 		SQ_PUTLOCKS_ENTER(sq);
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 	flags = sq->sq_flags;
8340Sstevel@tonic-gate 	/*
8350Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK
8360Sstevel@tonic-gate 	 * to prevent any undetected entry and exit into the perimeter.
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
8390Sstevel@tonic-gate 	sq->sq_count--;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8420Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
8430Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 	/*
8460Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
8470Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
8480Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
8490Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
8500Sstevel@tonic-gate 	 */
8510Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
8520Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
8530Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 	sq->sq_flags = flags;
8560Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
8570Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8580Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
8590Sstevel@tonic-gate 		}
8600Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
8610Sstevel@tonic-gate 		drain_syncq(sq);
8620Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
8630Sstevel@tonic-gate 		entersq(sq, SQ_OPENCLOSE);
8640Sstevel@tonic-gate 		return;
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 	/*
8670Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
8680Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
8690Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
8700Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
8710Sstevel@tonic-gate 	 */
8720Sstevel@tonic-gate 	do {
8730Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
8740Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8750Sstevel@tonic-gate 			SQ_PUTLOCKS_EXIT(sq);
8760Sstevel@tonic-gate 		}
8770Sstevel@tonic-gate 		cv_wait(&sq->sq_exitwait, SQLOCK(sq));
8780Sstevel@tonic-gate 		if (is_sq_cioc == 0) {
8790Sstevel@tonic-gate 			SQ_PUTLOCKS_ENTER(sq);
8800Sstevel@tonic-gate 		}
8810Sstevel@tonic-gate 	} while (sq->sq_flags & SQ_WANTEXWAKEUP);
8820Sstevel@tonic-gate 	if (is_sq_cioc == 0) {
8830Sstevel@tonic-gate 		SQ_PUTLOCKS_EXIT(sq);
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/*
8880Sstevel@tonic-gate 	 * Re-enter the perimeters again
8890Sstevel@tonic-gate 	 */
8900Sstevel@tonic-gate 	entersq(sq, SQ_OPENCLOSE);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate  * Used for the synchronous streams entrypoints when sleeping outside
8950Sstevel@tonic-gate  * the perimeters. Must never be called from regular put entrypoint.
8960Sstevel@tonic-gate  *
8970Sstevel@tonic-gate  * There's no need to grab sq_putlocks here (which only exist for CIPUT sync
8980Sstevel@tonic-gate  * queues). If it is CIPUT sync queue put entry points were not blocked in the
8990Sstevel@tonic-gate  * first place by rwnext/infonext which are treated as put entrypoints for
9000Sstevel@tonic-gate  * permiter syncronization purposes.
9010Sstevel@tonic-gate  *
9020Sstevel@tonic-gate  * Consolidation private.
9030Sstevel@tonic-gate  */
9040Sstevel@tonic-gate boolean_t
qwait_rw(queue_t * q)9050Sstevel@tonic-gate qwait_rw(queue_t *q)
9060Sstevel@tonic-gate {
9070Sstevel@tonic-gate 	syncq_t		*sq;
9080Sstevel@tonic-gate 	ulong_t		flags;
9090Sstevel@tonic-gate 	boolean_t	gotsignal = B_FALSE;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	/*
9120Sstevel@tonic-gate 	 * Perform the same operations as a leavesq(sq, SQ_PUT)
9130Sstevel@tonic-gate 	 * while detecting all cases where the perimeter is entered
9140Sstevel@tonic-gate 	 * so that qwait_rw can return to the caller.
9150Sstevel@tonic-gate 	 *
9160Sstevel@tonic-gate 	 * Drain the syncq if possible. Otherwise reset SQ_EXCL and
9170Sstevel@tonic-gate 	 * wait for a thread to leave the syncq.
9180Sstevel@tonic-gate 	 */
9190Sstevel@tonic-gate 	sq = q->q_syncq;
9200Sstevel@tonic-gate 	ASSERT(sq);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
9230Sstevel@tonic-gate 	flags = sq->sq_flags;
9240Sstevel@tonic-gate 	/*
9250Sstevel@tonic-gate 	 * Drop SQ_EXCL and sq_count but hold the SQLOCK until to prevent any
9260Sstevel@tonic-gate 	 * undetected entry and exit into the perimeter.
9270Sstevel@tonic-gate 	 */
9280Sstevel@tonic-gate 	ASSERT(sq->sq_count > 0);
9290Sstevel@tonic-gate 	sq->sq_count--;
9300Sstevel@tonic-gate 	if (!(sq->sq_type & SQ_CIPUT)) {
9310Sstevel@tonic-gate 		ASSERT(flags & SQ_EXCL);
9320Sstevel@tonic-gate 		flags &= ~SQ_EXCL;
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate 	/*
9350Sstevel@tonic-gate 	 * Unblock any thread blocked in an entersq or outer_enter.
9360Sstevel@tonic-gate 	 * Note: we do not unblock a thread waiting in qwait/qwait_sig,
9370Sstevel@tonic-gate 	 * since that could lead to livelock with two threads in
9380Sstevel@tonic-gate 	 * qwait for the same (per module) inner perimeter.
9390Sstevel@tonic-gate 	 */
9400Sstevel@tonic-gate 	if (flags & SQ_WANTWAKEUP) {
9410Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
9420Sstevel@tonic-gate 		flags &= ~SQ_WANTWAKEUP;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	sq->sq_flags = flags;
9450Sstevel@tonic-gate 	if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) {
9460Sstevel@tonic-gate 		/* drain_syncq() drops SQLOCK */
9470Sstevel@tonic-gate 		drain_syncq(sq);
9480Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
9490Sstevel@tonic-gate 		entersq(sq, SQ_PUT);
9500Sstevel@tonic-gate 		return (B_FALSE);
9510Sstevel@tonic-gate 	}
9520Sstevel@tonic-gate 	/*
9530Sstevel@tonic-gate 	 * Sleep on sq_exitwait to only be woken up when threads leave the
9540Sstevel@tonic-gate 	 * put or service procedures. We can not sleep on sq_wait since an
9550Sstevel@tonic-gate 	 * outer_exit in a qwait running in the same outer perimeter would
9560Sstevel@tonic-gate 	 * cause a livelock "ping-pong" between two or more qwait'ers.
9570Sstevel@tonic-gate 	 */
9580Sstevel@tonic-gate 	do {
9590Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTEXWAKEUP;
9600Sstevel@tonic-gate 		if (cv_wait_sig(&sq->sq_exitwait, SQLOCK(sq)) <= 0) {
9610Sstevel@tonic-gate 			sq->sq_flags &= ~SQ_WANTEXWAKEUP;
9620Sstevel@tonic-gate 			gotsignal = B_TRUE;
9630Sstevel@tonic-gate 			break;
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 	} while (sq->sq_flags & SQ_WANTEXWAKEUP);
9660Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/*
9690Sstevel@tonic-gate 	 * Re-enter the perimeters again
9700Sstevel@tonic-gate 	 */
9710Sstevel@tonic-gate 	entersq(sq, SQ_PUT);
9720Sstevel@tonic-gate 	return (gotsignal);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate /*
9760Sstevel@tonic-gate  * Asynchronously upgrade to exclusive access at either the inner or
9770Sstevel@tonic-gate  * outer perimeter.
9780Sstevel@tonic-gate  */
9790Sstevel@tonic-gate void
qwriter(queue_t * q,mblk_t * mp,void (* func)(),int perim)9800Sstevel@tonic-gate qwriter(queue_t *q, mblk_t *mp, void (*func)(), int perim)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate 	if (perim == PERIM_INNER)
9830Sstevel@tonic-gate 		qwriter_inner(q, mp, func);
9840Sstevel@tonic-gate 	else if (perim == PERIM_OUTER)
9850Sstevel@tonic-gate 		qwriter_outer(q, mp, func);
9860Sstevel@tonic-gate 	else
9870Sstevel@tonic-gate 		panic("qwriter: wrong \"perimeter\" parameter");
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate  * Schedule a synchronous streams timeout
9920Sstevel@tonic-gate  */
9930Sstevel@tonic-gate timeout_id_t
qtimeout(queue_t * q,void (* func)(void *),void * arg,clock_t tim)9940Sstevel@tonic-gate qtimeout(queue_t *q, void (*func)(void *), void *arg, clock_t tim)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	syncq_t		*sq;
9970Sstevel@tonic-gate 	callbparams_t	*cbp;
9980Sstevel@tonic-gate 	timeout_id_t	tid;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	sq = q->q_syncq;
10010Sstevel@tonic-gate 	/*
10020Sstevel@tonic-gate 	 * you don't want the timeout firing before its params are set up
10030Sstevel@tonic-gate 	 * callbparams_alloc() acquires SQLOCK(sq)
10040Sstevel@tonic-gate 	 * qtimeout() can't fail and can't sleep, so panic if memory is not
10050Sstevel@tonic-gate 	 * available.
10060Sstevel@tonic-gate 	 */
10070Sstevel@tonic-gate 	cbp = callbparams_alloc(sq, func, arg, KM_NOSLEEP | KM_PANIC);
10080Sstevel@tonic-gate 	/*
10090Sstevel@tonic-gate 	 * the callbflags in the sq use the same flags. They get anded
10100Sstevel@tonic-gate 	 * in the callbwrapper to determine if a qun* of this callback type
10110Sstevel@tonic-gate 	 * is required. This is not a request to cancel.
10120Sstevel@tonic-gate 	 */
10130Sstevel@tonic-gate 	cbp->cbp_flags = SQ_CANCEL_TOUT;
10140Sstevel@tonic-gate 	/* check new timeout version return codes */
10150Sstevel@tonic-gate 	tid = timeout(qcallbwrapper, cbp, tim);
10160Sstevel@tonic-gate 	cbp->cbp_id = (callbparams_id_t)tid;
10170Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10180Sstevel@tonic-gate 	/* use local id because the cbp memory could be free by now */
10190Sstevel@tonic-gate 	return (tid);
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate bufcall_id_t
qbufcall(queue_t * q,size_t size,uint_t pri,void (* func)(void *),void * arg)10230Sstevel@tonic-gate qbufcall(queue_t *q, size_t size, uint_t pri, void (*func)(void *), void *arg)
10240Sstevel@tonic-gate {
10250Sstevel@tonic-gate 	syncq_t		*sq;
10260Sstevel@tonic-gate 	callbparams_t	*cbp;
10270Sstevel@tonic-gate 	bufcall_id_t	bid;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	sq = q->q_syncq;
10300Sstevel@tonic-gate 	/*
10310Sstevel@tonic-gate 	 * you don't want the timeout firing before its params are set up
10320Sstevel@tonic-gate 	 * callbparams_alloc() acquires SQLOCK(sq) if successful.
10330Sstevel@tonic-gate 	 */
10340Sstevel@tonic-gate 	cbp = callbparams_alloc(sq, func, arg, KM_NOSLEEP);
10350Sstevel@tonic-gate 	if (cbp == NULL)
10360Sstevel@tonic-gate 		return ((bufcall_id_t)0);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	/*
10390Sstevel@tonic-gate 	 * the callbflags in the sq use the same flags. They get anded
10400Sstevel@tonic-gate 	 * in the callbwrapper to determine if a qun* of this callback type
10410Sstevel@tonic-gate 	 * is required. This is not a request to cancel.
10420Sstevel@tonic-gate 	 */
10430Sstevel@tonic-gate 	cbp->cbp_flags = SQ_CANCEL_BUFCALL;
10440Sstevel@tonic-gate 	/* check new timeout version return codes */
10450Sstevel@tonic-gate 	bid = bufcall(size, pri, qcallbwrapper, cbp);
10460Sstevel@tonic-gate 	cbp->cbp_id = (callbparams_id_t)bid;
10470Sstevel@tonic-gate 	if (bid == 0) {
10480Sstevel@tonic-gate 		callbparams_free(sq, cbp);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10510Sstevel@tonic-gate 	/* use local id because the params memory could be free by now */
10520Sstevel@tonic-gate 	return (bid);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate /*
10560Sstevel@tonic-gate  * cancel a timeout callback which enters the inner perimeter.
10570Sstevel@tonic-gate  * cancelling of all callback types on a given syncq is serialized.
10580Sstevel@tonic-gate  * the SQ_CALLB_BYPASSED flag indicates that the callback fn did
10590Sstevel@tonic-gate  * not execute. The quntimeout return value needs to reflect this.
10600Sstevel@tonic-gate  * As with out existing callback programming model - callbacks must
10610Sstevel@tonic-gate  * be cancelled before a close completes - so ensuring that the sq
10620Sstevel@tonic-gate  * is valid when the callback wrapper is executed.
10630Sstevel@tonic-gate  */
10640Sstevel@tonic-gate clock_t
quntimeout(queue_t * q,timeout_id_t id)10650Sstevel@tonic-gate quntimeout(queue_t *q, timeout_id_t id)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	syncq_t *sq = q->q_syncq;
10680Sstevel@tonic-gate 	clock_t ret;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
10710Sstevel@tonic-gate 	/* callbacks are processed serially on each syncq */
10720Sstevel@tonic-gate 	while (sq->sq_callbflags & SQ_CALLB_CANCEL_MASK) {
10730Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTWAKEUP;
10740Sstevel@tonic-gate 		cv_wait(&sq->sq_wait, SQLOCK(sq));
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 	sq->sq_cancelid = (callbparams_id_t)id;
10770Sstevel@tonic-gate 	sq->sq_callbflags = SQ_CANCEL_TOUT;
10780Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
10790Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
10800Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10830Sstevel@tonic-gate 	ret = untimeout(id);
10840Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
10850Sstevel@tonic-gate 	if (ret != -1) {
10860Sstevel@tonic-gate 		/* The wrapper was never called - need to free based on id */
10870Sstevel@tonic-gate 		callbparams_free_id(sq, (callbparams_id_t)id, SQ_CANCEL_TOUT);
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 	if (sq->sq_callbflags & SQ_CALLB_BYPASSED) {
10900Sstevel@tonic-gate 		ret = 0;	/* this was how much time left */
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 	sq->sq_callbflags = 0;
10930Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
10940Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
10950Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
10980Sstevel@tonic-gate 	return (ret);
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate void
qunbufcall(queue_t * q,bufcall_id_t id)11030Sstevel@tonic-gate qunbufcall(queue_t *q, bufcall_id_t id)
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate 	syncq_t *sq = q->q_syncq;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
11080Sstevel@tonic-gate 	/* callbacks are processed serially on each syncq */
11090Sstevel@tonic-gate 	while (sq->sq_callbflags & SQ_CALLB_CANCEL_MASK) {
11100Sstevel@tonic-gate 		sq->sq_flags |= SQ_WANTWAKEUP;
11110Sstevel@tonic-gate 		cv_wait(&sq->sq_wait, SQLOCK(sq));
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 	sq->sq_cancelid = (callbparams_id_t)id;
11140Sstevel@tonic-gate 	sq->sq_callbflags = SQ_CANCEL_BUFCALL;
11150Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
11160Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
11170Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
11200Sstevel@tonic-gate 	unbufcall(id);
11210Sstevel@tonic-gate 	mutex_enter(SQLOCK(sq));
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * No indication from unbufcall if the callback has already run.
11240Sstevel@tonic-gate 	 * Always attempt to free it.
11250Sstevel@tonic-gate 	 */
11260Sstevel@tonic-gate 	callbparams_free_id(sq, (callbparams_id_t)id, SQ_CANCEL_BUFCALL);
11270Sstevel@tonic-gate 	sq->sq_callbflags = 0;
11280Sstevel@tonic-gate 	if (sq->sq_flags & SQ_WANTWAKEUP) {
11290Sstevel@tonic-gate 		cv_broadcast(&sq->sq_wait);
11300Sstevel@tonic-gate 		sq->sq_flags &= ~SQ_WANTWAKEUP;
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 	mutex_exit(SQLOCK(sq));
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate /*
113653Scth  * Associate the stream with an instance of the bottom driver.  This
113753Scth  * function is called by APIs that establish or modify the hardware
113853Scth  * association (ppa) of an open stream.  Two examples of such
113953Scth  * post-open(9E) APIs are the dlpi(7p) DL_ATTACH_REQ message, and the
114053Scth  * ndd(1M) "instance=" ioctl(2).  This interface may be called from a
114153Scth  * stream driver's wput procedure and from within syncq perimeters,
114253Scth  * so it can't block.
114353Scth  *
114453Scth  * The qassociate() "model" is that it should drive attach(9E), yet it
114553Scth  * can't really do that because driving attach(9E) is a blocking
114653Scth  * operation.  Instead, the qassociate() implementation has complex
114753Scth  * dependencies on the implementation behavior of other parts of the
114853Scth  * kernel to ensure all appropriate instances (ones that have not been
114953Scth  * made inaccessible by DR) are attached at stream open() time, and
115053Scth  * that they will not autodetach.  The code relies on the fact that an
115153Scth  * open() of a stream that ends up using qassociate() always occurs on
115253Scth  * a minor node created with CLONE_DEV.  The open() comes through
115353Scth  * clnopen() and since clnopen() calls ddi_hold_installed_driver() we
115453Scth  * attach all instances and mark them DN_NO_AUTODETACH (given
115553Scth  * DN_DRIVER_HELD is maintained correctly).
115653Scth  *
115753Scth  * Since qassociate() can't really drive attach(9E), there are corner
115853Scth  * cases where the compromise described above leads to qassociate()
115953Scth  * returning failure.  This can happen when administrative functions
116053Scth  * that cause detach(9E), such as "update_drv" or "modunload -i", are
116153Scth  * performed on the driver between the time the stream was opened and
116253Scth  * the time its hardware association was established.  Although this can
116353Scth  * theoretically be an arbitrary amount of time, in practice the window
116453Scth  * is usually quite small, since applications almost always issue their
116553Scth  * hardware association request immediately after opening the stream,
116653Scth  * and do not typically switch association while open.  When these
116753Scth  * corner cases occur, and qassociate() finds the requested instance
116853Scth  * detached, it will return failure.  This failure should be propagated
116953Scth  * to the requesting administrative application using the appropriate
117053Scth  * post-open(9E) API error mechanism.
117153Scth  *
117253Scth  * All qassociate() callers are expected to check for and gracefully handle
117353Scth  * failure return, propagating errors back to the requesting administrative
117453Scth  * application.
11750Sstevel@tonic-gate  */
11760Sstevel@tonic-gate int
qassociate(queue_t * q,int instance)11770Sstevel@tonic-gate qassociate(queue_t *q, int instance)
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate 	vnode_t *vp;
11800Sstevel@tonic-gate 	major_t major;
11810Sstevel@tonic-gate 	dev_info_t *dip;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	if (instance == -1) {
11840Sstevel@tonic-gate 		ddi_assoc_queue_with_devi(q, NULL);
11850Sstevel@tonic-gate 		return (0);
11860Sstevel@tonic-gate 	}
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	vp = STREAM(q)->sd_vnode;
11890Sstevel@tonic-gate 	major = getmajor(vp->v_rdev);
11900Sstevel@tonic-gate 	dip = ddi_hold_devi_by_instance(major, instance,
11910Sstevel@tonic-gate 	    E_DDI_HOLD_DEVI_NOATTACH);
11920Sstevel@tonic-gate 	if (dip == NULL)
11930Sstevel@tonic-gate 		return (-1);
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	ddi_assoc_queue_with_devi(q, dip);
11960Sstevel@tonic-gate 	ddi_release_devi(dip);
11970Sstevel@tonic-gate 	return (0);
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate /*
12010Sstevel@tonic-gate  * This routine is the SVR4MP 'replacement' for
12020Sstevel@tonic-gate  * hat_getkpfnum.  The only major difference is
12030Sstevel@tonic-gate  * the return value for illegal addresses - since
12040Sstevel@tonic-gate  * sunm_getkpfnum() and srmmu_getkpfnum() both
12050Sstevel@tonic-gate  * return '-1' for bogus mappings, we can (more or
12060Sstevel@tonic-gate  * less) return the value directly.
12070Sstevel@tonic-gate  */
12080Sstevel@tonic-gate ppid_t
kvtoppid(caddr_t addr)12090Sstevel@tonic-gate kvtoppid(caddr_t addr)
12100Sstevel@tonic-gate {
12110Sstevel@tonic-gate 	return ((ppid_t)hat_getpfnum(kas.a_hat, addr));
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate /*
12150Sstevel@tonic-gate  * This is used to set the timeout value for cv_timed_wait() or
12160Sstevel@tonic-gate  * cv_timedwait_sig().
12170Sstevel@tonic-gate  */
12180Sstevel@tonic-gate void
time_to_wait(clock_t * now,clock_t time)12190Sstevel@tonic-gate time_to_wait(clock_t *now, clock_t time)
12200Sstevel@tonic-gate {
1221*11066Srafael.vanoni@sun.com 	*now = ddi_get_lbolt() + time;
12220Sstevel@tonic-gate }
1223