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