17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5cdb79230Sja97890 * Common Development and Distribution License (the "License"). 6cdb79230Sja97890 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * DESCRIPTION 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * ttymux - Multiplexer driver for multiplexing termio compliant streams onto 317c478bd9Sstevel@tonic-gate * a single upper stream. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * ADD2FRONT macro can be used to specify the order in which a console 347c478bd9Sstevel@tonic-gate * device is put in the queue of multiplexed physical serial devices, 357c478bd9Sstevel@tonic-gate * during the association and disassociation of a console interface. 367c478bd9Sstevel@tonic-gate * When this macro is defined, the device is placed in front of the queue, 377c478bd9Sstevel@tonic-gate * otherwise by default it is placed at the end. 387c478bd9Sstevel@tonic-gate * Console I/O happens to each of the physical devices in the order of 397c478bd9Sstevel@tonic-gate * their position in this queue. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/file.h> 447c478bd9Sstevel@tonic-gate #include <sys/stream.h> 457c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 467c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 477c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 487c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 497c478bd9Sstevel@tonic-gate #include <sys/debug.h> 507c478bd9Sstevel@tonic-gate #include <sys/kbio.h> 517c478bd9Sstevel@tonic-gate #include <sys/devops.h> 527c478bd9Sstevel@tonic-gate #include <sys/errno.h> 537c478bd9Sstevel@tonic-gate #include <sys/stat.h> 547c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 557c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 567c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 577c478bd9Sstevel@tonic-gate #include <sys/tty.h> 587c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h> 597c478bd9Sstevel@tonic-gate #include <sys/termio.h> 607c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 617c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 627c478bd9Sstevel@tonic-gate #include <sys/ser_sync.h> 637c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 647c478bd9Sstevel@tonic-gate #include <sys/policy.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #include <sys/ttymux.h> 677c478bd9Sstevel@tonic-gate #include "ttymux_impl.h" 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Extern declarations 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate extern mblk_t *mkiocb(uint_t); 737c478bd9Sstevel@tonic-gate extern int nulldev(); 747c478bd9Sstevel@tonic-gate extern uintptr_t space_fetch(char *key); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate extern int sm_ioctl_cmd(sm_uqi_t *, mblk_t *); 777c478bd9Sstevel@tonic-gate extern int ttymux_abort_ioctl(mblk_t *); 787c478bd9Sstevel@tonic-gate extern int ttymux_device_fini(sm_lqi_t *); 797c478bd9Sstevel@tonic-gate extern int ttymux_device_init(sm_lqi_t *); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Exported interfaces 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate int sm_disassociate(int, sm_lqi_t *, ulong_t); 857c478bd9Sstevel@tonic-gate int sm_associate(int, sm_lqi_t *, ulong_t, uint_t, char *); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Variables defined here and visible only internally 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate sm_ss_t *sm_ssp = 0; 917c478bd9Sstevel@tonic-gate static int sm_instance = 0; 927c478bd9Sstevel@tonic-gate static int smctlunit; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static uint_t sm_default_trflag = 0; 957c478bd9Sstevel@tonic-gate uint_t sm_max_units = 6; 967c478bd9Sstevel@tonic-gate uint_t sm_minor_cnt = 0; 977c478bd9Sstevel@tonic-gate static uint_t sm_refuse_opens = 0; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * Local definitions. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* force these flags to be unset on console devices */ 1047c478bd9Sstevel@tonic-gate static ulong_t sm_cmask = (ulong_t)(CRTSXOFF|CRTSCTS); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * SECTION 1087c478bd9Sstevel@tonic-gate * Implementation Section: 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate void 1117c478bd9Sstevel@tonic-gate sm_debug(char *msg, ...) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate va_list args; 1147c478bd9Sstevel@tonic-gate char buf[256]; 1157c478bd9Sstevel@tonic-gate int sz; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate va_start(args, msg); 1187c478bd9Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), msg, args); 1197c478bd9Sstevel@tonic-gate va_end(args); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate if (sz < 0) 1227c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1, 1237c478bd9Sstevel@tonic-gate SL_TRACE, "vsnprintf parse error\n"); 1247c478bd9Sstevel@tonic-gate else if (sz > sizeof (buf)) { 1257c478bd9Sstevel@tonic-gate char *b; 1267c478bd9Sstevel@tonic-gate size_t len = sz + 1; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate b = kmem_alloc(len, KM_SLEEP); 1297c478bd9Sstevel@tonic-gate va_start(args, msg); 1307c478bd9Sstevel@tonic-gate sz = vsnprintf(b, len, msg, args); 1317c478bd9Sstevel@tonic-gate va_end(args); 1327c478bd9Sstevel@tonic-gate if (sz > 0) 1337c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), 1347c478bd9Sstevel@tonic-gate sm_instance, 1, SL_TRACE, b); 1357c478bd9Sstevel@tonic-gate kmem_free(b, len); 1367c478bd9Sstevel@tonic-gate } else { 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1397c478bd9Sstevel@tonic-gate 1, SL_TRACE, buf); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate void 1447c478bd9Sstevel@tonic-gate sm_log(char *msg, ...) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate va_list args; 1477c478bd9Sstevel@tonic-gate char buf[128]; 1487c478bd9Sstevel@tonic-gate int sz; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate va_start(args, msg); 1517c478bd9Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), msg, args); 1527c478bd9Sstevel@tonic-gate va_end(args); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (sz < 0) 1557c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1, 1567c478bd9Sstevel@tonic-gate SL_TRACE, "vsnprintf parse error\n"); 1577c478bd9Sstevel@tonic-gate else if (sz > sizeof (buf)) { 1587c478bd9Sstevel@tonic-gate char *b; 1597c478bd9Sstevel@tonic-gate size_t len = sz + 1; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate b = kmem_alloc(len, KM_SLEEP); 1627c478bd9Sstevel@tonic-gate va_start(args, msg); 1637c478bd9Sstevel@tonic-gate sz = vsnprintf(b, len, msg, args); 1647c478bd9Sstevel@tonic-gate va_end(args); 1657c478bd9Sstevel@tonic-gate if (sz > 0) 1667c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), 1677c478bd9Sstevel@tonic-gate sm_instance, 1, SL_NOTE, b); 1687c478bd9Sstevel@tonic-gate kmem_free(b, len); 1697c478bd9Sstevel@tonic-gate } else { 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1727c478bd9Sstevel@tonic-gate 1, SL_NOTE, buf); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * Should only be called if the caller can guarantee that the vnode 1787c478bd9Sstevel@tonic-gate * and/or the stream won't disappear while finding the dip. 1797c478bd9Sstevel@tonic-gate * This routine is only called during an I_PLINK request so it's safe. 1807c478bd9Sstevel@tonic-gate * The routine obtains the dev_t for a linked se stream. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate static void 1837c478bd9Sstevel@tonic-gate sm_setdip(queue_t *q, sm_lqi_t *lqi) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate lqi->sm_dev = q && STREAM(q) ? STREAM(q)->sd_vnode->v_rdev : NODEV; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * Called from driver close, state change reports and I_PUNLINK ioctl. 1907c478bd9Sstevel@tonic-gate * A lower stream has been unlinked - clean up the state associated with it. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate void 1937c478bd9Sstevel@tonic-gate sm_lqifree(sm_lqi_t *lqi) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate int mu_owned; 1967c478bd9Sstevel@tonic-gate sm_lqi_t **pplqi; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(lqi->sm_umutex)); 1997c478bd9Sstevel@tonic-gate ASSERT(SM_RQ(lqi) != 0); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Clear all state associated with this lower queue except 2037c478bd9Sstevel@tonic-gate * the identity of the queues themselves and the link id which 2047c478bd9Sstevel@tonic-gate * can only be cleared by issuing a streams I_PUNLINK ioctl. 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * The association of a lower queue is a two step process: 2077c478bd9Sstevel@tonic-gate * 1. initialise the lower q data structure on I_PLINK 2087c478bd9Sstevel@tonic-gate * 2. associate an upper q with the lower q on SM_CMD_ASSOCIATE. 2097c478bd9Sstevel@tonic-gate * 2107c478bd9Sstevel@tonic-gate * If step 2 has ocurred then 2117c478bd9Sstevel@tonic-gate * remove this lower queue info from the logical unit. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate if (lqi->sm_uqi) { 2147c478bd9Sstevel@tonic-gate sm_dbg('Y', ("lqifree unit %d, ", lqi->sm_uqi->sm_lunit)); 2157c478bd9Sstevel@tonic-gate if ((mu_owned = mutex_owned(lqi->sm_uqi->sm_umutex)) == 0) 2167c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi->sm_uqi); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate pplqi = &lqi->sm_uqi->sm_lqs; 2197c478bd9Sstevel@tonic-gate while (*pplqi != lqi) { 2207c478bd9Sstevel@tonic-gate ASSERT(*pplqi); 2217c478bd9Sstevel@tonic-gate pplqi = &((*pplqi)->sm_nlqi); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate *pplqi = lqi->sm_nlqi; 2247c478bd9Sstevel@tonic-gate lqi->sm_uqi->sm_nlqs--; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate if (mu_owned == 0) 2277c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi->sm_uqi); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate lqi->sm_uqi = 0; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * Given a q return the associated lower queue data structure or NULL. 2357c478bd9Sstevel@tonic-gate * Return the data locked. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate static sm_lqi_t * 2387c478bd9Sstevel@tonic-gate get_lqi_byq(queue_t *q) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate int i; 2417c478bd9Sstevel@tonic-gate sm_lqi_t *lqi, *flqi = 0; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 2447c478bd9Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 2457c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 2467c478bd9Sstevel@tonic-gate if (flqi == 0 && lqi->sm_linkid == 0) /* assumes muxids != 0 */ 2477c478bd9Sstevel@tonic-gate flqi = lqi; 2487c478bd9Sstevel@tonic-gate else if (SM_RQ(lqi) == q || SM_WQ(lqi) == q) { 2497c478bd9Sstevel@tonic-gate if (flqi) 2507c478bd9Sstevel@tonic-gate UNLOCK_UNIT(flqi); 2517c478bd9Sstevel@tonic-gate return (lqi); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate else 2547c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate return (flqi); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * Given a streams link identifier return the associated lower queue data 2617c478bd9Sstevel@tonic-gate * structure or NULL. 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate sm_lqi_t * 2647c478bd9Sstevel@tonic-gate get_lqi_byid(int linkid) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate int i; 2677c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (linkid == 0) 2707c478bd9Sstevel@tonic-gate return (NULL); 2717c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 2727c478bd9Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 2737c478bd9Sstevel@tonic-gate if (lqi->sm_linkid == linkid) 2747c478bd9Sstevel@tonic-gate return (lqi); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate return (NULL); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Given a dev_t for a lower stream return the associated lower queue data 2817c478bd9Sstevel@tonic-gate * structure or NULL. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate sm_lqi_t * 2847c478bd9Sstevel@tonic-gate get_lqi_bydevt(dev_t dev) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate int i; 2877c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if (dev == NODEV) 2907c478bd9Sstevel@tonic-gate return (NULL); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 2937c478bd9Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 2947c478bd9Sstevel@tonic-gate if (lqi->sm_dev == dev) 2957c478bd9Sstevel@tonic-gate return (lqi); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate return (NULL); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * Determine whether the input flag is set on at least 3027c478bd9Sstevel@tonic-gate * howmany queues. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate static int 3057c478bd9Sstevel@tonic-gate sm_is_flag_set(sm_uqi_t *uqi, uint_t flag, uint_t howmany) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (howmany == 0) 3107c478bd9Sstevel@tonic-gate return (0); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 3137c478bd9Sstevel@tonic-gate if (lqi->sm_flags & flag) 3147c478bd9Sstevel@tonic-gate if (--howmany == 0) 3157c478bd9Sstevel@tonic-gate return (1); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate return (0); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * How many usable queues are associated with a given upper stream 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate static int 3247c478bd9Sstevel@tonic-gate sm_uwq_error(sm_uqi_t *uqi) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate return (sm_is_flag_set(uqi, (WERROR_MODE|HANGUP_MODE), uqi->sm_nlqs)); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * How many of the queues associated with a given upper stream 3317c478bd9Sstevel@tonic-gate * - do not - have the given flags set. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate static int 3347c478bd9Sstevel@tonic-gate sm_q_count(sm_uqi_t *uqi, uint_t flag) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 3377c478bd9Sstevel@tonic-gate int count = 0; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 3407c478bd9Sstevel@tonic-gate if ((lqi->sm_flags & flag) == 0) 3417c478bd9Sstevel@tonic-gate count++; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate return (count); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * How many of the queues associated with a given upper stream 3487c478bd9Sstevel@tonic-gate * - do not - have the given flags set. 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate static int 3517c478bd9Sstevel@tonic-gate sm_qs_without(sm_uqi_t *uqi, uint_t flag, uint_t ioflag) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 3547c478bd9Sstevel@tonic-gate int count = 0; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 3577c478bd9Sstevel@tonic-gate if ((lqi->sm_flags & flag) == 0 && 3587c478bd9Sstevel@tonic-gate (lqi->sm_ioflag & ioflag) == 0) 3597c478bd9Sstevel@tonic-gate count++; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate return (count); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * How many usable queues are associated with a given upper stream 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate static int 3687c478bd9Sstevel@tonic-gate sm_good_qs(sm_uqi_t *uqi) 3697c478bd9Sstevel@tonic-gate { 3707c478bd9Sstevel@tonic-gate return (sm_q_count(uqi, (WERROR_MODE|HANGUP_MODE))); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate static int 3747c478bd9Sstevel@tonic-gate sm_cnt_oqs(sm_uqi_t *uqi) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate return (sm_qs_without(uqi, (WERROR_MODE|HANGUP_MODE), 3777c478bd9Sstevel@tonic-gate (uint_t)FOROUTPUT)); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * Send an ioctl downstream and remember that it was sent so that 3827c478bd9Sstevel@tonic-gate * its response can be caught on the way back up. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate static void 3857c478bd9Sstevel@tonic-gate sm_issue_ioctl(void *arg) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate sm_lqi_t *lqi = arg; 3887c478bd9Sstevel@tonic-gate uint_t cmdflag = 0; 3897c478bd9Sstevel@tonic-gate queue_t *q = SM_WQ(lqi); 3907c478bd9Sstevel@tonic-gate int iocmd, size; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate lqi->sm_bid = 0; 3957c478bd9Sstevel@tonic-gate if ((lqi->sm_flags & (WERROR_MODE|HANGUP_MODE)) == 0 && 3967c478bd9Sstevel@tonic-gate (lqi->sm_flags & (WANT_CDSTAT|WANT_TCSET))) { 3977c478bd9Sstevel@tonic-gate mblk_t *pioc; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (lqi->sm_flags & WANT_TCSET) { 4007c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~WANT_TCSET; 4017c478bd9Sstevel@tonic-gate iocmd = TCSETS; 4027c478bd9Sstevel@tonic-gate cmdflag = WANT_TCSET; 4037c478bd9Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_SC) { 4047c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~WANT_SC; 4057c478bd9Sstevel@tonic-gate iocmd = TIOCGSOFTCAR; 4067c478bd9Sstevel@tonic-gate cmdflag = WANT_SC; 4077c478bd9Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_CD) { 4087c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~WANT_CD; 4097c478bd9Sstevel@tonic-gate iocmd = TIOCMGET; 4107c478bd9Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_CL) { 4117c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~WANT_CL; 4127c478bd9Sstevel@tonic-gate iocmd = TCGETS; 4137c478bd9Sstevel@tonic-gate cmdflag = WANT_CL; 4147c478bd9Sstevel@tonic-gate } else { 4157c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 4167c478bd9Sstevel@tonic-gate return; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if (pioc = mkiocb(iocmd)) { 4207c478bd9Sstevel@tonic-gate if (cmdflag == WANT_TCSET) { 4217c478bd9Sstevel@tonic-gate pioc->b_cont = 4227c478bd9Sstevel@tonic-gate sm_allocb(sizeof (struct termios), 4237c478bd9Sstevel@tonic-gate BPRI_MED); 4247c478bd9Sstevel@tonic-gate if (pioc->b_cont == 0) { 4257c478bd9Sstevel@tonic-gate freemsg(pioc); 4267c478bd9Sstevel@tonic-gate pioc = 0; 4277c478bd9Sstevel@tonic-gate } else { 4287c478bd9Sstevel@tonic-gate struct termios *tc = (struct termios *) 4297c478bd9Sstevel@tonic-gate pioc->b_cont->b_wptr; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate bzero((caddr_t)tc, 4327c478bd9Sstevel@tonic-gate sizeof (struct termios)); 4337c478bd9Sstevel@tonic-gate tc->c_cflag = lqi->sm_ttycommon-> 4347c478bd9Sstevel@tonic-gate t_cflag; 4357c478bd9Sstevel@tonic-gate pioc->b_cont->b_rptr = 4367c478bd9Sstevel@tonic-gate pioc->b_cont->b_wptr; 4377c478bd9Sstevel@tonic-gate pioc->b_cont->b_wptr += 4387c478bd9Sstevel@tonic-gate sizeof (struct termios); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate size = sizeof (struct iocblk) + 4417c478bd9Sstevel@tonic-gate sizeof (struct termios); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate else 4447c478bd9Sstevel@tonic-gate size = sizeof (struct iocblk); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate else 4477c478bd9Sstevel@tonic-gate size = sizeof (struct iocblk); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if (pioc != 0) { 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate lqi->sm_piocid = ((struct iocblk *)pioc->b_rptr)-> 4527c478bd9Sstevel@tonic-gate ioc_id; 4537c478bd9Sstevel@tonic-gate lqi->sm_flags |= SM_IOCPENDING; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* lqi->sm_flags |= cmdflag; */ 4567c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 4577c478bd9Sstevel@tonic-gate (void) putq(q, pioc); 4587c478bd9Sstevel@tonic-gate } else { 4597c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 4607c478bd9Sstevel@tonic-gate lqi->sm_bid = qbufcall(WR(q), size, BPRI_MED, 4617c478bd9Sstevel@tonic-gate sm_issue_ioctl, lqi); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate else 4657c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Associate one of the drivers minor nodes with a serial device. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate int 4727c478bd9Sstevel@tonic-gate sm_associate(int unit, sm_lqi_t *plqi, ulong_t tag, uint_t ioflag, char *dp) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 4757c478bd9Sstevel@tonic-gate int rval = 0; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate sm_dbg('Y', ("sm_associate(%d, %d, %d): ", 4787c478bd9Sstevel@tonic-gate (plqi) ? plqi->sm_linkid : 0, unit, ioflag)); 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * Check the data is valid. 4817c478bd9Sstevel@tonic-gate * Associate a lower queue with a logical unit. 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate if (unit < 0 || unit >= NLUNITS || plqi == 0 || 4857c478bd9Sstevel@tonic-gate (uqi = get_uqi(sm_ssp, unit)) == 0) { 4867c478bd9Sstevel@tonic-gate sm_dbg('@', (" invalid: lqi=0x%p lui=0x%p:", plqi, uqi)); 4877c478bd9Sstevel@tonic-gate rval = EINVAL; 4887c478bd9Sstevel@tonic-gate } else { 4897c478bd9Sstevel@tonic-gate if ((ioflag & FORIO) == 0) 4907c478bd9Sstevel@tonic-gate ioflag = FORIO; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate LOCK_UNIT(plqi); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate if (plqi->sm_uqi) { 4957c478bd9Sstevel@tonic-gate if (plqi->sm_uqi->sm_lunit == unit) { 4967c478bd9Sstevel@tonic-gate if ((ioflag & (uint_t)FORIO) != 0) 4977c478bd9Sstevel@tonic-gate plqi->sm_ioflag = 4987c478bd9Sstevel@tonic-gate (ioflag & (uint_t)FORIO); 4997c478bd9Sstevel@tonic-gate rval = 0; 5007c478bd9Sstevel@tonic-gate } else { 5017c478bd9Sstevel@tonic-gate sm_dbg('@', ("already associated with unit %d:", 5027c478bd9Sstevel@tonic-gate plqi->sm_uqi->sm_lunit)); 5037c478bd9Sstevel@tonic-gate rval = EINVAL; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate } else { 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate LOCK_UNIT(uqi); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if ((ioflag & (uint_t)FORIO) != 0) 5107c478bd9Sstevel@tonic-gate plqi->sm_ioflag = (ioflag & (uint_t)FORIO); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = uqi->sm_ttycommon-> 5137c478bd9Sstevel@tonic-gate t_cflag; 5147c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = uqi->sm_ttycommon-> 5157c478bd9Sstevel@tonic-gate t_flags; 5167c478bd9Sstevel@tonic-gate plqi->sm_uqi = uqi; 5177c478bd9Sstevel@tonic-gate plqi->sm_mbits = 0; 5187c478bd9Sstevel@tonic-gate plqi->sm_tag = tag; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (*dp == '/') 5217c478bd9Sstevel@tonic-gate (void) strncpy(plqi->sm_path, dp, MAXPATHLEN); 5227c478bd9Sstevel@tonic-gate else 5237c478bd9Sstevel@tonic-gate *(plqi->sm_path) = '\0'; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate plqi->sm_flags |= WANT_TCSET; 5267c478bd9Sstevel@tonic-gate #ifdef ADD2FRONT 5277c478bd9Sstevel@tonic-gate plqi->sm_nlqi = uqi->sm_lqs; 5287c478bd9Sstevel@tonic-gate uqi->sm_lqs = plqi; 5297c478bd9Sstevel@tonic-gate #else 5307c478bd9Sstevel@tonic-gate plqi->sm_nlqi = 0; 5317c478bd9Sstevel@tonic-gate if (uqi->sm_lqs) { 5327c478bd9Sstevel@tonic-gate sm_lqi_t *lq; 5337c478bd9Sstevel@tonic-gate for (lq = uqi->sm_lqs; lq->sm_nlqi; 5347c478bd9Sstevel@tonic-gate lq = lq->sm_nlqi) { 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate lq->sm_nlqi = plqi; 5377c478bd9Sstevel@tonic-gate } else 5387c478bd9Sstevel@tonic-gate uqi->sm_lqs = plqi; 5397c478bd9Sstevel@tonic-gate #endif 5407c478bd9Sstevel@tonic-gate uqi->sm_nlqs++; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate (void) ttymux_device_init(plqi); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate UNLOCK_UNIT(uqi); 5457c478bd9Sstevel@tonic-gate rval = 0; 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate * Everything looks good so it's now ok to enable lower 5487c478bd9Sstevel@tonic-gate * queue processing. 5497c478bd9Sstevel@tonic-gate * Note the lower queue should be enabled as soon as 5507c478bd9Sstevel@tonic-gate * I_PLINK returns (used in sm_get_ttymodes etc). 5517c478bd9Sstevel@tonic-gate * Schedule ioctls to obtain the terminal settings. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_waitq) 5557c478bd9Sstevel@tonic-gate plqi->sm_uqflags |= SM_UQVALID; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate qenable(SM_RQ(plqi)); 5587c478bd9Sstevel@tonic-gate if (plqi->sm_flags & (WANT_CDSTAT|WANT_TCSET)) { 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * Bypass the lower half of the driver (hence 5617c478bd9Sstevel@tonic-gate * no qwriter) and apply the current termio 5627c478bd9Sstevel@tonic-gate * settings on the lower stream. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); 5657c478bd9Sstevel@tonic-gate if (plqi->sm_bid) { 5667c478bd9Sstevel@tonic-gate qunbufcall(SM_WQ(plqi), plqi->sm_bid); 5677c478bd9Sstevel@tonic-gate plqi->sm_bid = 0; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Only set cflags on the lower q if we know 5717c478bd9Sstevel@tonic-gate * the settings on any other lower queue. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate sm_issue_ioctl(plqi); 5747c478bd9Sstevel@tonic-gate LOCK_UNIT(plqi); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate sm_dbg('Y', ("sm_associate: rval=%d.\n", rval)); 5827c478bd9Sstevel@tonic-gate return (rval); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Break an association between one of the driver's minor nodes and 5877c478bd9Sstevel@tonic-gate * a serial device. 5887c478bd9Sstevel@tonic-gate */ 5897c478bd9Sstevel@tonic-gate int 5907c478bd9Sstevel@tonic-gate sm_disassociate(int unit, sm_lqi_t *plqi, ulong_t tag) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 5937c478bd9Sstevel@tonic-gate int rval = 0; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate sm_dbg('Y', ("sm_disassociate: link %d, unit %d: ", 5967c478bd9Sstevel@tonic-gate (plqi) ? plqi->sm_linkid : 0, unit)); 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Check the data is valid. 5997c478bd9Sstevel@tonic-gate * Disassociate a lower queue with a logical unit. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate if (unit < 0 || unit >= NLUNITS || plqi == 0 || 6027c478bd9Sstevel@tonic-gate (uqi = get_uqi(sm_ssp, unit)) == 0) { 6037c478bd9Sstevel@tonic-gate sm_dbg('@', ("invalid: lqi=0x%p lui=0x%p", plqi, uqi)); 6047c478bd9Sstevel@tonic-gate rval = EINVAL; 6057c478bd9Sstevel@tonic-gate } else { 6067c478bd9Sstevel@tonic-gate LOCK_UNIT(plqi); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (plqi->sm_uqi == NULL) { 6097c478bd9Sstevel@tonic-gate sm_dbg('@', ("unit not associated")); 6107c478bd9Sstevel@tonic-gate rval = EINVAL; 6117c478bd9Sstevel@tonic-gate } else if (plqi->sm_uqi->sm_lunit != unit) { 6127c478bd9Sstevel@tonic-gate sm_dbg('@', ("unit and linkid not related", 6137c478bd9Sstevel@tonic-gate plqi->sm_uqi->sm_lunit)); 6147c478bd9Sstevel@tonic-gate rval = EINVAL; 6157c478bd9Sstevel@tonic-gate } else if (plqi->sm_tag != tag) { 6167c478bd9Sstevel@tonic-gate sm_dbg('@', 6177c478bd9Sstevel@tonic-gate ("Invalid tag for TTYMUX_DISASSOC ioctl\n")); 6187c478bd9Sstevel@tonic-gate rval = EPERM; 6197c478bd9Sstevel@tonic-gate } else { 6207c478bd9Sstevel@tonic-gate sm_dbg('Y', ("disassociating ")); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate (void) ttymux_device_fini(plqi); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Indicate that carrier status is no 6267c478bd9Sstevel@tonic-gate * longer required and that the upper 6277c478bd9Sstevel@tonic-gate * queue should not be used by plqi 6287c478bd9Sstevel@tonic-gate */ 6297c478bd9Sstevel@tonic-gate plqi->sm_flags &= ~(WANT_CDSTAT|WANT_TCSET); 6307c478bd9Sstevel@tonic-gate plqi->sm_uqflags &= ~(SM_UQVALID|SM_OBPCNDEV); 6317c478bd9Sstevel@tonic-gate plqi->sm_ioflag = 0u; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate sm_lqifree(plqi); 6347c478bd9Sstevel@tonic-gate rval = 0; 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate sm_dbg('Y', (" rval=%d.\n", rval)); 6397c478bd9Sstevel@tonic-gate return (rval); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * Streams helper routines; 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * Schedule a qbufcall for an upper queue. 6497c478bd9Sstevel@tonic-gate * Must be called within the perimiter of the parameter q. 6507c478bd9Sstevel@tonic-gate * fn must reenable the q. 6517c478bd9Sstevel@tonic-gate * Called: 6527c478bd9Sstevel@tonic-gate * whenever a message must be placed on multiple queues and allocb fails; 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate static void 6557c478bd9Sstevel@tonic-gate sm_sched_uqcb(queue_t *q, int memreq, int pri, void (*fn)()) 6567c478bd9Sstevel@tonic-gate { 6577c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = q->q_ptr; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate if (uqi->sm_ttybid != 0) 6607c478bd9Sstevel@tonic-gate qunbufcall(q, uqi->sm_ttybid); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate noenable(q); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate uqi->sm_ttybid = qbufcall(q, memreq, pri, fn, uqi); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * qbufcall routine to restart the queues when memory is available. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate static void 6717c478bd9Sstevel@tonic-gate sm_reenable_q(sm_uqi_t *uqi) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate queue_t *wq = SM_WQ(uqi); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & SM_STOPPED) == 0) { 6767c478bd9Sstevel@tonic-gate enableok(wq); 6777c478bd9Sstevel@tonic-gate qenable(wq); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Place a message on the write queue of each stream associated with 6837c478bd9Sstevel@tonic-gate * the given upper stream. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate static void 6867c478bd9Sstevel@tonic-gate sm_senddown(sm_uqi_t *uqi) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 6917c478bd9Sstevel@tonic-gate if (lqi->sm_mp != 0) { 6927c478bd9Sstevel@tonic-gate putnext(SM_WQ(lqi), lqi->sm_mp); 6937c478bd9Sstevel@tonic-gate lqi->sm_mp = 0; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* 6997c478bd9Sstevel@tonic-gate * For each lower device that should receive a write message duplicate 7007c478bd9Sstevel@tonic-gate * the message block. 7017c478bd9Sstevel@tonic-gate */ 7027c478bd9Sstevel@tonic-gate static int 7037c478bd9Sstevel@tonic-gate sm_dupmsg(sm_uqi_t *uqi, mblk_t *mp) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 7067c478bd9Sstevel@tonic-gate mblk_t *origmp = mp; 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 7097c478bd9Sstevel@tonic-gate lqi->sm_mp = 0; 7107c478bd9Sstevel@tonic-gate if (lqi->sm_flags & WERROR_MODE) { 7117c478bd9Sstevel@tonic-gate continue; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate if ((lqi->sm_ioflag & (uint_t)FOROUTPUT) == 0) { 7147c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) 7157c478bd9Sstevel@tonic-gate continue; 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate if (lqi->sm_nlqi == 0) { 7187c478bd9Sstevel@tonic-gate lqi->sm_mp = mp; 7197c478bd9Sstevel@tonic-gate origmp = NULL; 7207c478bd9Sstevel@tonic-gate } else if ((lqi->sm_mp = sm_copymsg(mp)) == 0) { 7217c478bd9Sstevel@tonic-gate sm_lqi_t *flqi; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate for (flqi = uqi->sm_lqs; flqi != lqi; 7247c478bd9Sstevel@tonic-gate flqi = flqi->sm_nlqi) { 7257c478bd9Sstevel@tonic-gate if (lqi->sm_mp) { 7267c478bd9Sstevel@tonic-gate /* must have been sm_copymsg */ 7277c478bd9Sstevel@tonic-gate sm_freemsg(lqi->sm_mp); 7287c478bd9Sstevel@tonic-gate lqi->sm_mp = 0; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate return (sm_cnt_oqs(uqi) * msgdsize(mp)); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate if (origmp != NULL) 7357c478bd9Sstevel@tonic-gate freemsg(origmp); 7367c478bd9Sstevel@tonic-gate return (0); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * Return 1 if all associated lower devices have room for another message 7417c478bd9Sstevel@tonic-gate * otherwise return 0. 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate static int 7447c478bd9Sstevel@tonic-gate sm_cansenddown(sm_uqi_t *uqi) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate register sm_lqi_t *lqi; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate if (uqi->sm_lqs == 0) 7507c478bd9Sstevel@tonic-gate return (0); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 7537c478bd9Sstevel@tonic-gate if ((lqi->sm_flags & WERROR_MODE) == 0 && 7547c478bd9Sstevel@tonic-gate canputnext(SM_WQ(lqi)) == 0) 7557c478bd9Sstevel@tonic-gate return (0); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate return (1); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * Put a message down all associated lower queues. 7627c478bd9Sstevel@tonic-gate * Return 1 if the q function was called. 7637c478bd9Sstevel@tonic-gate */ 7647c478bd9Sstevel@tonic-gate static int 7657c478bd9Sstevel@tonic-gate sm_putqs(queue_t *q, mblk_t *mp, int (*qfn)()) 7667c478bd9Sstevel@tonic-gate { 7677c478bd9Sstevel@tonic-gate register sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 7687c478bd9Sstevel@tonic-gate register int memreq; 7697c478bd9Sstevel@tonic-gate int pri = (DB_TYPE(mp) < QPCTL) ? BPRI_MED : BPRI_HI; 7707c478bd9Sstevel@tonic-gate int rval = 0; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate if (uqi->sm_lqs == 0 || (uqi->sm_flags & WERROR_MODE)) { 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate sm_dbg('Q', ("sm_putqs: freeing (0x%p 0x%p).\n", uqi->sm_lqs, 7757c478bd9Sstevel@tonic-gate uqi->sm_flags)); 7767c478bd9Sstevel@tonic-gate freemsg(mp); 7777c478bd9Sstevel@tonic-gate } else if (pri != BPRI_HI && sm_cansenddown(uqi) == 0) { 7787c478bd9Sstevel@tonic-gate /* a lower q is flow controlled */ 7797c478bd9Sstevel@tonic-gate (void) qfn(q, mp); 7807c478bd9Sstevel@tonic-gate rval = 1; 7817c478bd9Sstevel@tonic-gate } else if ((memreq = sm_dupmsg(uqi, mp)) == 0) { 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate sm_senddown(uqi); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate } else { 7867c478bd9Sstevel@tonic-gate sm_log("sm_putqs: msg 0x%x - can't alloc %d bytes (pri %d).\n", 7877c478bd9Sstevel@tonic-gate DB_TYPE(mp), memreq, pri); 7887c478bd9Sstevel@tonic-gate sm_sched_uqcb(q, memreq, pri, sm_reenable_q); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate (void) qfn(q, mp); 7917c478bd9Sstevel@tonic-gate rval = 1; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate return (rval); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* 7997c478bd9Sstevel@tonic-gate * Service a streams link and unlink requests. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate static void 8027c478bd9Sstevel@tonic-gate sm_link_req(queue_t *wq, mblk_t *mp) 8037c478bd9Sstevel@tonic-gate { 8047c478bd9Sstevel@tonic-gate struct linkblk *linkp; 8057c478bd9Sstevel@tonic-gate int rval; 8067c478bd9Sstevel@tonic-gate int cmd; 8077c478bd9Sstevel@tonic-gate sm_lqi_t *plqi; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_IOCTL); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 8127c478bd9Sstevel@tonic-gate switch (cmd) { 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate case I_LINK: 8157c478bd9Sstevel@tonic-gate case I_PLINK: 8167c478bd9Sstevel@tonic-gate sm_dbg('G', ("sm_link_req: M_IOCTL %x (I_PLINK).\n", cmd)); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * 1. Sanity check the link block. 8227c478bd9Sstevel@tonic-gate * 2. Validate that the queue is not already linked 8237c478bd9Sstevel@tonic-gate * (and resources available). 8247c478bd9Sstevel@tonic-gate * 3. Validate that the lower queue is not associated with 8257c478bd9Sstevel@tonic-gate * a logical unit. 8267c478bd9Sstevel@tonic-gate * 4. Remember that this lower queue is linked to the driver. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate if ((linkp == NULL) || (MBLKL(mp) < sizeof (*linkp)) || 8297c478bd9Sstevel@tonic-gate linkp->l_qbot == NULL) { 8307c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: invalid link block.\n")); 8317c478bd9Sstevel@tonic-gate rval = EINVAL; 8327c478bd9Sstevel@tonic-gate } else if ((plqi = get_lqi_byq(linkp->l_qbot)) == 0) { 8337c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: out of resources.\n")); 8347c478bd9Sstevel@tonic-gate rval = EBUSY; /* out of resources */ 8357c478bd9Sstevel@tonic-gate } else if (plqi->sm_uqi) { 8367c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */ 8377c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: already associated.\n")); 8387c478bd9Sstevel@tonic-gate rval = EBUSY; /* already linked */ 8397c478bd9Sstevel@tonic-gate } else { 8407c478bd9Sstevel@tonic-gate SM_WQ(plqi) = linkp->l_qbot; 8417c478bd9Sstevel@tonic-gate SM_RQ(plqi) = OTHERQ(linkp->l_qbot); 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate linkp->l_qbot->q_ptr = 8447c478bd9Sstevel@tonic-gate OTHERQ(linkp->l_qbot)->q_ptr = plqi; 8457c478bd9Sstevel@tonic-gate plqi->sm_linkid = linkp->l_index; 8467c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */ 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate sm_dbg('H', ("sm_link_req: linkid = %d.\n", 8497c478bd9Sstevel@tonic-gate linkp->l_index)); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate sm_setdip(linkp->l_qbot, plqi); 8527c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = 0; 8537c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = 0; 8547c478bd9Sstevel@tonic-gate plqi->sm_mbits = 0; 8557c478bd9Sstevel@tonic-gate (void) ttymux_device_init(plqi); 8567c478bd9Sstevel@tonic-gate rval = 0; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate break; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate case I_UNLINK: 8627c478bd9Sstevel@tonic-gate case I_PUNLINK: 8637c478bd9Sstevel@tonic-gate sm_dbg('G', ("sm_link_req: M_IOCTL (I_PUNLINK).\n")); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate if ((linkp == NULL) || 8687c478bd9Sstevel@tonic-gate (MBLKL(mp) < sizeof (*linkp)) || 8697c478bd9Sstevel@tonic-gate linkp->l_qbot == NULL) { 8707c478bd9Sstevel@tonic-gate rval = EINVAL; 8717c478bd9Sstevel@tonic-gate } else if ((plqi = get_lqi_byid(linkp->l_index)) == 0) { 8727c478bd9Sstevel@tonic-gate rval = EINVAL; 8737c478bd9Sstevel@tonic-gate } else { 8747c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 8757c478bd9Sstevel@tonic-gate int werrmode; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * Mark the lower q as invalid. 8797c478bd9Sstevel@tonic-gate */ 8807c478bd9Sstevel@tonic-gate sm_dbg('G', ("I_PUNLINK: freeing link %d\n", 8817c478bd9Sstevel@tonic-gate linkp->l_index)); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate if (plqi->sm_bid) { 8847c478bd9Sstevel@tonic-gate qunbufcall(SM_RQ(plqi), plqi->sm_bid); 8857c478bd9Sstevel@tonic-gate plqi->sm_bid = 0; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate if (plqi->sm_ttybid) { 8887c478bd9Sstevel@tonic-gate qunbufcall(SM_RQ(plqi), plqi->sm_ttybid); 8897c478bd9Sstevel@tonic-gate plqi->sm_ttybid = 0; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate uqi = plqi->sm_uqi; 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate (void) ttymux_device_fini(plqi); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate if (uqi) 8987c478bd9Sstevel@tonic-gate (void) sm_disassociate(uqi->sm_lunit, 8997c478bd9Sstevel@tonic-gate plqi, plqi->sm_tag); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate LOCK_UNIT(plqi); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate plqi->sm_piocid = 0; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate werrmode = (plqi->sm_flags & (WERROR_MODE|HANGUP_MODE)) 9067c478bd9Sstevel@tonic-gate ? 1 : 0; 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate plqi->sm_mbits = 0; 9097c478bd9Sstevel@tonic-gate plqi->sm_flags = 0; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate ttycommon_close(plqi->sm_ttycommon); 9127c478bd9Sstevel@tonic-gate /* SM_RQ(plqi) = SM_WQ(plqi) = 0; */ 9137c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = 0; 9147c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = 0; 9157c478bd9Sstevel@tonic-gate plqi->sm_ttycommon->t_iflag = 0; 9167c478bd9Sstevel@tonic-gate plqi->sm_linkid = 0; 9177c478bd9Sstevel@tonic-gate plqi->sm_dev = NODEV; 9187c478bd9Sstevel@tonic-gate plqi->sm_hadkadbchar = 0; 9197c478bd9Sstevel@tonic-gate plqi->sm_nachar = sm_ssp->sm_abs; 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate UNLOCK_UNIT(plqi); 9227c478bd9Sstevel@tonic-gate if (uqi && 9237c478bd9Sstevel@tonic-gate werrmode && 9247c478bd9Sstevel@tonic-gate (uqi->sm_flags & FULLY_OPEN) && 9257c478bd9Sstevel@tonic-gate sm_uwq_error(uqi) && 9267c478bd9Sstevel@tonic-gate putnextctl(SM_RQ(uqi), M_HANGUP) == 0) { 9277c478bd9Sstevel@tonic-gate sm_log("sm_link_req: putnextctl(M_HANGUP)" 9287c478bd9Sstevel@tonic-gate " failed.\n"); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate rval = 0; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate break; 9357c478bd9Sstevel@tonic-gate default: 9367c478bd9Sstevel@tonic-gate rval = EINVAL; 9377c478bd9Sstevel@tonic-gate } 938cdb79230Sja97890 if (rval != 0) 939cdb79230Sja97890 miocnak(wq, mp, 0, rval); 940cdb79230Sja97890 else 941cdb79230Sja97890 miocack(wq, mp, 0, 0); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate static int 9457c478bd9Sstevel@tonic-gate sm_getiocinfo(mblk_t *mp, struct sm_iocinfo *info) 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 9487c478bd9Sstevel@tonic-gate case M_COPYOUT: 9497c478bd9Sstevel@tonic-gate info->sm_id = ((struct copyreq *)mp->b_rptr)->cq_id; 9507c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct copyreq *)mp->b_rptr)->cq_cmd; 9517c478bd9Sstevel@tonic-gate info->sm_data = (((struct copyreq *)mp->b_rptr)->cq_size && 9527c478bd9Sstevel@tonic-gate mp->b_cont) ? (void *)mp->b_cont->b_rptr : 0; 9537c478bd9Sstevel@tonic-gate break; 9547c478bd9Sstevel@tonic-gate case M_COPYIN: 9557c478bd9Sstevel@tonic-gate info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id; 9567c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd; 9577c478bd9Sstevel@tonic-gate info->sm_data = 0; 9587c478bd9Sstevel@tonic-gate break; 9597c478bd9Sstevel@tonic-gate case M_IOCACK: 9607c478bd9Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 9617c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 9627c478bd9Sstevel@tonic-gate /* the se driver has bug so we cannot use ioc_count */ 9637c478bd9Sstevel@tonic-gate info->sm_data = (((struct iocblk *)mp->b_rptr)-> 9647c478bd9Sstevel@tonic-gate ioc_error == 0 && mp->b_cont) ? 9657c478bd9Sstevel@tonic-gate (void *)mp->b_cont->b_rptr : 0; 9667c478bd9Sstevel@tonic-gate break; 9677c478bd9Sstevel@tonic-gate case M_IOCNAK: 9687c478bd9Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 9697c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 9707c478bd9Sstevel@tonic-gate info->sm_data = 0; 9717c478bd9Sstevel@tonic-gate break; 9727c478bd9Sstevel@tonic-gate case M_IOCDATA: 9737c478bd9Sstevel@tonic-gate info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id; 9747c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd; 9757c478bd9Sstevel@tonic-gate info->sm_data = (((struct copyresp *)mp->b_rptr)-> 9767c478bd9Sstevel@tonic-gate cp_rval == 0 && mp->b_cont) ? 9777c478bd9Sstevel@tonic-gate (void *)mp->b_cont->b_rptr : 0; 9787c478bd9Sstevel@tonic-gate break; 9797c478bd9Sstevel@tonic-gate case M_IOCTL: 9807c478bd9Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 9817c478bd9Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 9827c478bd9Sstevel@tonic-gate info->sm_data = 0; 9837c478bd9Sstevel@tonic-gate break; 9847c478bd9Sstevel@tonic-gate default: 9857c478bd9Sstevel@tonic-gate return (EINVAL); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate return (0); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * Record the termio settings that have been set on the upper stream 9927c478bd9Sstevel@tonic-gate */ 9937c478bd9Sstevel@tonic-gate static int 9947c478bd9Sstevel@tonic-gate sm_update_ttyinfo(mblk_t *mp, sm_uqi_t *uqi) 9957c478bd9Sstevel@tonic-gate { 9967c478bd9Sstevel@tonic-gate int err; 9977c478bd9Sstevel@tonic-gate struct sm_iocinfo info; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if ((err = sm_getiocinfo(mp, &info)) != 0) 10007c478bd9Sstevel@tonic-gate return (err); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate switch (info.sm_cmd) { 10037c478bd9Sstevel@tonic-gate case TIOCSPPS: 10047c478bd9Sstevel@tonic-gate case TIOCGPPS: 10057c478bd9Sstevel@tonic-gate case TIOCGPPSEV: 10067c478bd9Sstevel@tonic-gate return (ENOTSUP); 10077c478bd9Sstevel@tonic-gate case TIOCGWINSZ: 10087c478bd9Sstevel@tonic-gate case TIOCSWINSZ: 10097c478bd9Sstevel@tonic-gate break; 10107c478bd9Sstevel@tonic-gate case TCSBRK: 10117c478bd9Sstevel@tonic-gate case TIOCSBRK: 10127c478bd9Sstevel@tonic-gate case TIOCCBRK: 10137c478bd9Sstevel@tonic-gate break; 10147c478bd9Sstevel@tonic-gate case TCSETSF: 10157c478bd9Sstevel@tonic-gate uqi->sm_flags |= FLUSHR_PEND; 10167c478bd9Sstevel@tonic-gate sm_dbg('I', ("TCSETSF: FLUSH is pending\n")); 10177c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 10187c478bd9Sstevel@tonic-gate case TCSETSW: 10197c478bd9Sstevel@tonic-gate case TCSETS: 10207c478bd9Sstevel@tonic-gate case TCGETS: 10217c478bd9Sstevel@tonic-gate if (info.sm_data != 0) { 10227c478bd9Sstevel@tonic-gate ((struct termios *)info.sm_data)->c_cflag &= 10237c478bd9Sstevel@tonic-gate (tcflag_t)(~uqi->sm_cmask); 10247c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 10257c478bd9Sstevel@tonic-gate ((struct termios *)info.sm_data)->c_cflag; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate break; 10287c478bd9Sstevel@tonic-gate case TCSETAF: 10297c478bd9Sstevel@tonic-gate sm_dbg('I', ("TCSETAF: FLUSH is pending\n")); 10307c478bd9Sstevel@tonic-gate uqi->sm_flags |= FLUSHR_PEND; 10317c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 10327c478bd9Sstevel@tonic-gate case TCSETAW: 10337c478bd9Sstevel@tonic-gate case TCSETA: 10347c478bd9Sstevel@tonic-gate case TCGETA: 10357c478bd9Sstevel@tonic-gate if (info.sm_data != 0) { 10367c478bd9Sstevel@tonic-gate ((struct termio *)info.sm_data)->c_cflag &= 10377c478bd9Sstevel@tonic-gate (tcflag_t)(~uqi->sm_cmask); 10387c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 10397c478bd9Sstevel@tonic-gate (tcflag_t)((struct termio *)info.sm_data)->c_cflag; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate break; 10427c478bd9Sstevel@tonic-gate case TIOCSSOFTCAR: 10437c478bd9Sstevel@tonic-gate case TIOCGSOFTCAR: 10447c478bd9Sstevel@tonic-gate if (info.sm_data != 0) { 10457c478bd9Sstevel@tonic-gate if (*(int *)info.sm_data == 1) 10467c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_flags |= TS_SOFTCAR; 10477c478bd9Sstevel@tonic-gate else 10487c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate break; 10517c478bd9Sstevel@tonic-gate case TIOCMSET: 10527c478bd9Sstevel@tonic-gate case TIOCMGET: 10537c478bd9Sstevel@tonic-gate if (info.sm_data != 0) 10547c478bd9Sstevel@tonic-gate uqi->sm_mbits = *(int *)info.sm_data; 10557c478bd9Sstevel@tonic-gate break; 10567c478bd9Sstevel@tonic-gate case TIOCMBIS: 10577c478bd9Sstevel@tonic-gate if (info.sm_data != 0) 10587c478bd9Sstevel@tonic-gate uqi->sm_mbits |= *(int *)info.sm_data; 10597c478bd9Sstevel@tonic-gate break; 10607c478bd9Sstevel@tonic-gate case TIOCMBIC: 10617c478bd9Sstevel@tonic-gate if (info.sm_data != 0) 10627c478bd9Sstevel@tonic-gate uqi->sm_mbits &= ~(*(int *)info.sm_data); 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate default: 10657c478bd9Sstevel@tonic-gate return (EINVAL); 10667c478bd9Sstevel@tonic-gate /* NOTREACHED */ 10677c478bd9Sstevel@tonic-gate } /* end switch cmd */ 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if ((uqi->sm_mbits & TIOCM_CD) || 10707c478bd9Sstevel@tonic-gate (uqi->sm_ttycommon->t_flags & TS_SOFTCAR) || 10717c478bd9Sstevel@tonic-gate (uqi->sm_ttycommon->t_cflag & CLOCAL)) 10727c478bd9Sstevel@tonic-gate uqi->sm_flags |= SM_CARON; 10737c478bd9Sstevel@tonic-gate else 10747c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate return (0); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * SECTION 10817c478bd9Sstevel@tonic-gate * STREAM's interface to the OS. 10827c478bd9Sstevel@tonic-gate * Routines directly callable from the OS. 10837c478bd9Sstevel@tonic-gate */ 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * Processes high priority messages comming from modules above the 10877c478bd9Sstevel@tonic-gate * multiplexor. 10887c478bd9Sstevel@tonic-gate * Return 1 if the queue was disabled. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate static int 10917c478bd9Sstevel@tonic-gate sm_hp_uwput(queue_t *wq, mblk_t *mp) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)(wq->q_ptr); 10947c478bd9Sstevel@tonic-gate int rval = 0; 10957c478bd9Sstevel@tonic-gate sm_lqi_t *plqi; 10967c478bd9Sstevel@tonic-gate int msgtype = DB_TYPE(mp); 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate switch (msgtype) { 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate case M_FLUSH: 11017c478bd9Sstevel@tonic-gate /* 11027c478bd9Sstevel@tonic-gate * How to flush the bottom half: 11037c478bd9Sstevel@tonic-gate * putctl1(SM_WQ(plqi), *mp->b_rptr) 11047c478bd9Sstevel@tonic-gate * will work on the bottom half but if FLUSHR is set 11057c478bd9Sstevel@tonic-gate * when is the right time to flush the upper read queue. 11067c478bd9Sstevel@tonic-gate * 11077c478bd9Sstevel@tonic-gate * Could set uqi->sm_flags & WANT_FLUSH but then what happens 11087c478bd9Sstevel@tonic-gate * if FLUSHR is set and the driver sends up a FLUSHR 11097c478bd9Sstevel@tonic-gate * before it handles the current FLUSHR request 11107c478bd9Sstevel@tonic-gate * (if only there was an id for the message that could 11117c478bd9Sstevel@tonic-gate * be matched when it returns back from the drivers. 11127c478bd9Sstevel@tonic-gate * 11137c478bd9Sstevel@tonic-gate * Thus I'm going by the book - the bottom half acts like 11147c478bd9Sstevel@tonic-gate * a stream head and turns around FLUSHW back down to 11157c478bd9Sstevel@tonic-gate * the driver (see lrput). The upper half acts like a 11167c478bd9Sstevel@tonic-gate * driver and turns around FLUSHR: 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_hp_uwput: FLUSH request 0x%x\n", *mp->b_rptr)); 11207c478bd9Sstevel@tonic-gate /* flush the upper write queue */ 11217c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 11227c478bd9Sstevel@tonic-gate flushq(wq, FLUSHDATA); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * flush each associated lower write queue 11267c478bd9Sstevel@tonic-gate * and pass down the driver (ignore the FLUSHR and deal with 11277c478bd9Sstevel@tonic-gate * it when it comes back up the read side. 11287c478bd9Sstevel@tonic-gate */ 11297c478bd9Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 11307c478bd9Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0 && 11317c478bd9Sstevel@tonic-gate SM_WQ(plqi)) { 11327c478bd9Sstevel@tonic-gate sm_dbg('I', ("flush lq 0x%p\n", SM_WQ(plqi))); 11337c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 11347c478bd9Sstevel@tonic-gate flushq(SM_WQ(plqi), FLUSHDATA); 11357c478bd9Sstevel@tonic-gate (void) putnextctl1(SM_WQ(plqi), M_FLUSH, 11367c478bd9Sstevel@tonic-gate *mp->b_rptr); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate case M_STARTI: 11427c478bd9Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 11437c478bd9Sstevel@tonic-gate plqi->sm_flags &= ~SM_ISTOPPED; 11447c478bd9Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 11457c478bd9Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate case M_STOPI: 11507c478bd9Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 11517c478bd9Sstevel@tonic-gate plqi->sm_flags |= SM_ISTOPPED; 11527c478bd9Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 11537c478bd9Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate break; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate case M_STOP: /* must never be queued */ 11587c478bd9Sstevel@tonic-gate uqi->sm_flags |= SM_STOPPED; 11597c478bd9Sstevel@tonic-gate noenable(wq); 11607c478bd9Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) 11617c478bd9Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 11627c478bd9Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate rval = 1; 11657c478bd9Sstevel@tonic-gate break; 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate case M_START: /* never be queued */ 11687c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_STOPPED; 11697c478bd9Sstevel@tonic-gate enableok(wq); 11707c478bd9Sstevel@tonic-gate qenable(wq); 11717c478bd9Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) 11727c478bd9Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 11737c478bd9Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate break; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate case M_PCSIG: 11787c478bd9Sstevel@tonic-gate case M_COPYOUT: 11797c478bd9Sstevel@tonic-gate case M_COPYIN: 11807c478bd9Sstevel@tonic-gate case M_IOCACK: 11817c478bd9Sstevel@tonic-gate case M_IOCNAK: 11827c478bd9Sstevel@tonic-gate /* Wrong direction for message */ 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate case M_READ: 11857c478bd9Sstevel@tonic-gate break; 11867c478bd9Sstevel@tonic-gate case M_PCPROTO: 11877c478bd9Sstevel@tonic-gate case M_PCRSE: 11887c478bd9Sstevel@tonic-gate default: 11897c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_hp_uwput: default case %d.\n", msgtype)); 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate } /* end switch on high pri message type */ 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate freemsg(mp); 11947c478bd9Sstevel@tonic-gate return (rval); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate static int 11987c478bd9Sstevel@tonic-gate sm_default_uwioctl(queue_t *wq, mblk_t *mp, int (*qfn)()) 11997c478bd9Sstevel@tonic-gate { 12007c478bd9Sstevel@tonic-gate int err; 12017c478bd9Sstevel@tonic-gate struct iocblk *iobp; 12027c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate uqi = (sm_uqi_t *)(wq->q_ptr); 12057c478bd9Sstevel@tonic-gate iobp = (struct iocblk *)mp->b_rptr; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate switch (iobp->ioc_cmd) { 12087c478bd9Sstevel@tonic-gate case TIOCEXCL: 12097c478bd9Sstevel@tonic-gate case TIOCNXCL: 12107c478bd9Sstevel@tonic-gate case TIOCSTI: 1211cdb79230Sja97890 /* 1212cdb79230Sja97890 * The three ioctl types we support do not require any 1213cdb79230Sja97890 * additional allocation and should not return a pending 1214cdb79230Sja97890 * ioctl state. For this reason it is safe for us to ignore 1215cdb79230Sja97890 * the return value from ttycommon_ioctl(). 1216cdb79230Sja97890 * Additionally, we translate any error response from 1217cdb79230Sja97890 * ttycommon_ioctl() into EINVAL. 1218cdb79230Sja97890 */ 12197c478bd9Sstevel@tonic-gate (void) ttycommon_ioctl(uqi->sm_ttycommon, wq, mp, &err); 1220cdb79230Sja97890 if (err < 0) 1221cdb79230Sja97890 miocnak(wq, mp, 0, EINVAL); 1222cdb79230Sja97890 else 1223cdb79230Sja97890 miocack(wq, mp, 0, 0); 12247c478bd9Sstevel@tonic-gate return (0); 12257c478bd9Sstevel@tonic-gate default: 12267c478bd9Sstevel@tonic-gate break; 12277c478bd9Sstevel@tonic-gate } 1228cdb79230Sja97890 if ((err = sm_update_ttyinfo(mp, uqi)) != 0) { 1229cdb79230Sja97890 miocnak(wq, mp, 0, err); 12307c478bd9Sstevel@tonic-gate return (0); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * If uqi->sm_siocdata.sm_iocid just overwrite it since the stream 12357c478bd9Sstevel@tonic-gate * head will have timed it out 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_iocid = iobp->ioc_id; 12387c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_acked = 0; 12397c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_nacks = sm_good_qs(uqi); 12407c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_acnt = 0; 12417c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_policy = uqi->sm_policy; 12427c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_flags = 0; 12437c478bd9Sstevel@tonic-gate sm_dbg('Z', (" want %d acks for id %d.\n", 12447c478bd9Sstevel@tonic-gate uqi->sm_siocdata.sm_nacks, iobp->ioc_id)); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate return (sm_putqs(wq, mp, qfn)); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * 12517c478bd9Sstevel@tonic-gate * sm_uwput - put function for an upper STREAM write. 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate static int 12547c478bd9Sstevel@tonic-gate sm_uwput(queue_t *wq, mblk_t *mp) 12557c478bd9Sstevel@tonic-gate { 12567c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 12577c478bd9Sstevel@tonic-gate uchar_t msgtype; 12587c478bd9Sstevel@tonic-gate int cmd; 12597c478bd9Sstevel@tonic-gate struct iocblk *iobp; 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate uqi = (sm_uqi_t *)(wq->q_ptr); 12627c478bd9Sstevel@tonic-gate msgtype = DB_TYPE(mp); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate ASSERT(uqi != 0 && sm_ssp != 0); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate if (msgtype >= QPCTL && msgtype != M_IOCDATA) { 12677c478bd9Sstevel@tonic-gate (void) sm_hp_uwput(wq, mp); 12687c478bd9Sstevel@tonic-gate return (0); 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 12727c478bd9Sstevel@tonic-gate case M_DATA: 12737c478bd9Sstevel@tonic-gate case M_DELAY: 12747c478bd9Sstevel@tonic-gate case M_BREAK: 12757c478bd9Sstevel@tonic-gate default: 12767c478bd9Sstevel@tonic-gate (void) sm_putqs(wq, mp, putq); 12777c478bd9Sstevel@tonic-gate break; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate case M_CTL: 12807c478bd9Sstevel@tonic-gate if (((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_CANONQUERY) { 12817c478bd9Sstevel@tonic-gate (void) putnextctl1(OTHERQ(wq), M_CTL, MC_NOCANON); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate freemsg(mp); 12847c478bd9Sstevel@tonic-gate break; 12857c478bd9Sstevel@tonic-gate case M_IOCDATA: /* not handled as high pri because may need to putbq */ 12867c478bd9Sstevel@tonic-gate sm_dbg('M', ("sm_uwput(M_IOCDATA)\n")); 12877c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 12887c478bd9Sstevel@tonic-gate case M_IOCTL: 12897c478bd9Sstevel@tonic-gate cmd = (msgtype == M_IOCDATA) ? 12907c478bd9Sstevel@tonic-gate ((struct copyresp *)mp->b_rptr)->cp_cmd : 12917c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd; 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate iobp = (struct iocblk *)mp->b_rptr; 12947c478bd9Sstevel@tonic-gate iobp->ioc_rval = 0; 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate sm_dbg('M', ("sm_uwput(M_IOCTL:%d)\n", cmd)); 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate switch (cmd) { 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate case CONSGETABORTENABLE: 13017c478bd9Sstevel@tonic-gate iobp->ioc_error = ttymux_abort_ioctl(mp); 13027c478bd9Sstevel@tonic-gate DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK; 13037c478bd9Sstevel@tonic-gate qreply(wq, mp); 13047c478bd9Sstevel@tonic-gate break; 13057c478bd9Sstevel@tonic-gate case CONSSETABORTENABLE: 13067c478bd9Sstevel@tonic-gate iobp->ioc_error = 13077c478bd9Sstevel@tonic-gate secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0 ? 13087c478bd9Sstevel@tonic-gate EPERM : ttymux_abort_ioctl(mp); 13097c478bd9Sstevel@tonic-gate DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK; 13107c478bd9Sstevel@tonic-gate qreply(wq, mp); 13117c478bd9Sstevel@tonic-gate break; 13127c478bd9Sstevel@tonic-gate case TTYMUX_SETABORT: 13137c478bd9Sstevel@tonic-gate if (secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0) { 13147c478bd9Sstevel@tonic-gate iobp->ioc_error = EPERM; 13157c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_IOCNAK; 13167c478bd9Sstevel@tonic-gate qreply(wq, mp); 13177c478bd9Sstevel@tonic-gate break; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 13207c478bd9Sstevel@tonic-gate case TTYMUX_GETABORT: 13217c478bd9Sstevel@tonic-gate case TTYMUX_GETABORTSTR: 13227c478bd9Sstevel@tonic-gate case TTYMUX_ASSOC: 13237c478bd9Sstevel@tonic-gate case TTYMUX_DISASSOC: 13247c478bd9Sstevel@tonic-gate case TTYMUX_SETCTL: 13257c478bd9Sstevel@tonic-gate case TTYMUX_GETLINK: 13267c478bd9Sstevel@tonic-gate case TTYMUX_CONSDEV: 13277c478bd9Sstevel@tonic-gate case TTYMUX_GETCTL: 13287c478bd9Sstevel@tonic-gate case TTYMUX_LIST: 13297c478bd9Sstevel@tonic-gate (void) sm_ioctl_cmd(uqi, mp); 13307c478bd9Sstevel@tonic-gate qreply(wq, mp); 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate case I_LINK: 13337c478bd9Sstevel@tonic-gate case I_PLINK: 13347c478bd9Sstevel@tonic-gate case I_UNLINK: 13357c478bd9Sstevel@tonic-gate case I_PUNLINK: 13367c478bd9Sstevel@tonic-gate qwriter(wq, mp, sm_link_req, PERIM_OUTER); 13377c478bd9Sstevel@tonic-gate break; 13387c478bd9Sstevel@tonic-gate case TCSETSW: 13397c478bd9Sstevel@tonic-gate case TCSETSF: 13407c478bd9Sstevel@tonic-gate case TCSETAW: 13417c478bd9Sstevel@tonic-gate case TCSETAF: 13427c478bd9Sstevel@tonic-gate case TCSBRK: 13437c478bd9Sstevel@tonic-gate if (wq->q_first) { 13447c478bd9Sstevel@tonic-gate sm_dbg('A', ("sm_uwput: TCSET-> on srv q.\n")); 13457c478bd9Sstevel@tonic-gate /* keep message order intact */ 13467c478bd9Sstevel@tonic-gate (void) putq(wq, mp); 13477c478bd9Sstevel@tonic-gate break; 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 13507c478bd9Sstevel@tonic-gate default: 13517c478bd9Sstevel@tonic-gate (void) sm_default_uwioctl(wq, mp, putq); 13527c478bd9Sstevel@tonic-gate break; 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate break; /* M_IOCTL */ 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate } /* end switch on message type */ 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate return (0); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* 13637c478bd9Sstevel@tonic-gate * sm_uwsrv - service function for an upper STREAM write. 13647c478bd9Sstevel@tonic-gate * 'sm_uwsrv' takes a q parameter. The q parameter specifies the queue 13657c478bd9Sstevel@tonic-gate * which is to be serviced. This function reads the messages which are on 13667c478bd9Sstevel@tonic-gate * this service queue and passes them to the appropriate lower driver queue. 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate static int 13697c478bd9Sstevel@tonic-gate sm_uwsrv(queue_t *q) 13707c478bd9Sstevel@tonic-gate { 13717c478bd9Sstevel@tonic-gate mblk_t *mp; 13727c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)(q->q_ptr); 13737c478bd9Sstevel@tonic-gate int msgtype; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate ASSERT(q == SM_WQ(uqi)); 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * Empty the queue unless explicitly stopped. 13797c478bd9Sstevel@tonic-gate */ 13807c478bd9Sstevel@tonic-gate while (mp = getq(q)) { 13817c478bd9Sstevel@tonic-gate msgtype = DB_TYPE(mp); 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate if (msgtype >= QPCTL && msgtype != M_IOCDATA) 13847c478bd9Sstevel@tonic-gate if (sm_hp_uwput(q, mp)) { 13857c478bd9Sstevel@tonic-gate sm_dbg('T', ("sm_uwsrv: flowcontrolled.\n")); 13867c478bd9Sstevel@tonic-gate break; /* indicates that the is disabled */ 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate else 13897c478bd9Sstevel@tonic-gate continue; 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate if (uqi->sm_flags & SM_STOPPED) { 13927c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 13937c478bd9Sstevel@tonic-gate sm_dbg('T', ("sm_uwsrv: SM_STOPPED.\n")); 13947c478bd9Sstevel@tonic-gate break; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* 13987c478bd9Sstevel@tonic-gate * Read any ttycommon data that may 13997c478bd9Sstevel@tonic-gate * change (TS_SOFTCAR, CREAD, etc.). 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 14027c478bd9Sstevel@tonic-gate case M_IOCTL: 14037c478bd9Sstevel@tonic-gate case M_IOCDATA: 14047c478bd9Sstevel@tonic-gate if (sm_default_uwioctl(q, mp, putbq)) 14057c478bd9Sstevel@tonic-gate return (0); 14067c478bd9Sstevel@tonic-gate break; 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate default: 14097c478bd9Sstevel@tonic-gate if (sm_putqs(q, mp, putbq)) 14107c478bd9Sstevel@tonic-gate return (0); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate return (0); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * Lower write side service routine used for backenabling upstream 14187c478bd9Sstevel@tonic-gate * flow control. 14197c478bd9Sstevel@tonic-gate */ 14207c478bd9Sstevel@tonic-gate static int 14217c478bd9Sstevel@tonic-gate sm_lwsrv(queue_t *q) 14227c478bd9Sstevel@tonic-gate { 14237c478bd9Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 14247c478bd9Sstevel@tonic-gate queue_t *uwq; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 14277c478bd9Sstevel@tonic-gate if (lqi->sm_uqflags & SM_UQVALID) { 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * It's safe to lock uqi since lwsrv runs asynchronously 14307c478bd9Sstevel@tonic-gate * with the upper write routines so this cannot be an 14317c478bd9Sstevel@tonic-gate * upper half thread. While holding the lqi lock and 14327c478bd9Sstevel@tonic-gate * if SM_UQVALID is set we are guaranteed that 14337c478bd9Sstevel@tonic-gate * lqi->sm_uqi will be valid. 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_lwsrv: re-enabling upper queue.\n")); 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate uwq = SM_WQ(lqi->sm_uqi); 14387c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 14397c478bd9Sstevel@tonic-gate qenable(uwq); 14407c478bd9Sstevel@tonic-gate } else { 14417c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate return (0); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * Upper read queue ioctl response handler for messages 14487c478bd9Sstevel@tonic-gate * passed from the lower half of the driver. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate static int 14517c478bd9Sstevel@tonic-gate sm_uriocack(queue_t *rq, mblk_t *mp) 14527c478bd9Sstevel@tonic-gate { 14537c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)rq->q_ptr; 14547c478bd9Sstevel@tonic-gate int err, flag; 14557c478bd9Sstevel@tonic-gate sm_iocdata_t *iodp; 14567c478bd9Sstevel@tonic-gate struct sm_iocinfo info; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate if ((err = sm_getiocinfo(mp, &info)) != 0) { 14597c478bd9Sstevel@tonic-gate sm_dbg('I', ("Unknown ioctl response\n")); 14607c478bd9Sstevel@tonic-gate return (err); 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (info.sm_id == uqi->sm_piocdata.sm_iocid) { 14647c478bd9Sstevel@tonic-gate iodp = &uqi->sm_piocdata; 14657c478bd9Sstevel@tonic-gate } else if (info.sm_id == uqi->sm_siocdata.sm_iocid) { 14667c478bd9Sstevel@tonic-gate iodp = &uqi->sm_siocdata; 14677c478bd9Sstevel@tonic-gate } else { 14687c478bd9Sstevel@tonic-gate sm_log("Unexpected ioctl response\n"); 14697c478bd9Sstevel@tonic-gate sm_dbg('I', ("Unexpected ioctl response (id %d)\n", 14707c478bd9Sstevel@tonic-gate info.sm_id)); 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate /* 14737c478bd9Sstevel@tonic-gate * If the response is sent up it will result in 14747c478bd9Sstevel@tonic-gate * duplicate ioctl responses. The ioctl has probably been 14757c478bd9Sstevel@tonic-gate * timed out by the stream head so dispose of the response 14767c478bd9Sstevel@tonic-gate * (since it has arrived too late. 14777c478bd9Sstevel@tonic-gate */ 14787c478bd9Sstevel@tonic-gate goto out; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate flag = SM_COPYIN; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 14847c478bd9Sstevel@tonic-gate case M_COPYOUT: 14857c478bd9Sstevel@tonic-gate flag = SM_COPYOUT; 14867c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 14877c478bd9Sstevel@tonic-gate case M_COPYIN: 14887c478bd9Sstevel@tonic-gate if (iodp->sm_flags & flag) 14897c478bd9Sstevel@tonic-gate goto out; 14907c478bd9Sstevel@tonic-gate iodp->sm_flags |= flag; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate break; 14937c478bd9Sstevel@tonic-gate case M_IOCACK: 14947c478bd9Sstevel@tonic-gate iodp->sm_ackcnt += 1; 14957c478bd9Sstevel@tonic-gate iodp->sm_acnt += 1; 14967c478bd9Sstevel@tonic-gate if (iodp->sm_policy == FIRSTACK) { 14977c478bd9Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) 14987c478bd9Sstevel@tonic-gate iodp->sm_iocid = 0; 14997c478bd9Sstevel@tonic-gate if (iodp->sm_acnt == 1) 15007c478bd9Sstevel@tonic-gate iodp->sm_acked = 1; 15017c478bd9Sstevel@tonic-gate else 15027c478bd9Sstevel@tonic-gate goto out; 15037c478bd9Sstevel@tonic-gate } else { 15047c478bd9Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) { 15057c478bd9Sstevel@tonic-gate iodp->sm_iocid = 0; 15067c478bd9Sstevel@tonic-gate iodp->sm_acked = 1; 15077c478bd9Sstevel@tonic-gate } else 15087c478bd9Sstevel@tonic-gate goto out; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate break; 15117c478bd9Sstevel@tonic-gate case M_IOCNAK: 15127c478bd9Sstevel@tonic-gate iodp->sm_nakcnt += 1; 15137c478bd9Sstevel@tonic-gate iodp->sm_acnt += 1; 15147c478bd9Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) { 15157c478bd9Sstevel@tonic-gate iodp->sm_iocid = 0; 15167c478bd9Sstevel@tonic-gate if (iodp->sm_acked == 0) { 15177c478bd9Sstevel@tonic-gate iodp->sm_acked = 1; 15187c478bd9Sstevel@tonic-gate break; 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate goto out; 15227c478bd9Sstevel@tonic-gate default: 15237c478bd9Sstevel@tonic-gate goto out; 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * Merge the tty settings each of the associated lower streams. 15287c478bd9Sstevel@tonic-gate */ 15297c478bd9Sstevel@tonic-gate if (info.sm_data) 15307c478bd9Sstevel@tonic-gate (void) sm_update_ttyinfo(mp, uqi); 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate if (iodp == &uqi->sm_piocdata) { 15337c478bd9Sstevel@tonic-gate if (iodp->sm_iocid == 0) { 15347c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_IOCPENDING; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate } else { 15377c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_uriocack: forwarding response for %d.\n", 15387c478bd9Sstevel@tonic-gate info.sm_id)); 15397c478bd9Sstevel@tonic-gate putnext(rq, mp); 15407c478bd9Sstevel@tonic-gate return (0); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate out: 15437c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_uriocack: freeing response for %d.\n", info.sm_id)); 15447c478bd9Sstevel@tonic-gate freemsg(mp); 15457c478bd9Sstevel@tonic-gate return (0); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate /* 15497c478bd9Sstevel@tonic-gate * Transfer a message from the lower read side of the multiplexer onto 15507c478bd9Sstevel@tonic-gate * the associated upper stream. 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate static int 15537c478bd9Sstevel@tonic-gate sm_ursendup(queue_t *q, mblk_t *mp) 15547c478bd9Sstevel@tonic-gate { 15557c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate if (!canputnext(q) && DB_TYPE(mp) < QPCTL) { 15587c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_ursendup: flow controlled.\n")); 15597c478bd9Sstevel@tonic-gate return (1); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 15637c478bd9Sstevel@tonic-gate case M_COPYIN: 15647c478bd9Sstevel@tonic-gate case M_COPYOUT: 15657c478bd9Sstevel@tonic-gate case M_IOCACK: 15667c478bd9Sstevel@tonic-gate case M_IOCNAK: 15677c478bd9Sstevel@tonic-gate (void) sm_uriocack(q, mp); 15687c478bd9Sstevel@tonic-gate break; 15697c478bd9Sstevel@tonic-gate case M_HANGUP: 15707c478bd9Sstevel@tonic-gate if (sm_uwq_error(uqi)) { 15717c478bd9Sstevel@tonic-gate /* there are no usable lower q's */ 15727c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 15737c478bd9Sstevel@tonic-gate putnext(q, mp); 15747c478bd9Sstevel@tonic-gate } else { 15757c478bd9Sstevel@tonic-gate /* there are still usable q's - don't send up */ 15767c478bd9Sstevel@tonic-gate freemsg(mp); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate break; 15797c478bd9Sstevel@tonic-gate case M_ERROR: 15807c478bd9Sstevel@tonic-gate if (sm_uwq_error(uqi)) { 15817c478bd9Sstevel@tonic-gate /* there are no usable lower q's */ 15827c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 15837c478bd9Sstevel@tonic-gate putnext(q, mp); 15847c478bd9Sstevel@tonic-gate } else if (*mp->b_rptr == NOERROR) { 15857c478bd9Sstevel@tonic-gate /* the error has cleared */ 15867c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~ERROR_MODE; 15877c478bd9Sstevel@tonic-gate putnext(q, mp); 15887c478bd9Sstevel@tonic-gate } else { 15897c478bd9Sstevel@tonic-gate /* there are still usable q's - don't send up */ 15907c478bd9Sstevel@tonic-gate freemsg(mp); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate break; 15937c478bd9Sstevel@tonic-gate case M_FLUSH: 15947c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 15957c478bd9Sstevel@tonic-gate putnext(q, mp); /* time to use FLUSHR_PEND flag */ 15967c478bd9Sstevel@tonic-gate break; 15977c478bd9Sstevel@tonic-gate case M_CTL: 15987c478bd9Sstevel@tonic-gate /* wrong direction - must have come from sm_close */ 15997c478bd9Sstevel@tonic-gate uqi->sm_flags |= SM_CLOSE; 16007c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_ursrv: had SM_CLOSE.\n")); 16017c478bd9Sstevel@tonic-gate freemsg(mp); 16027c478bd9Sstevel@tonic-gate break; 16037c478bd9Sstevel@tonic-gate case M_UNHANGUP: 16047c478bd9Sstevel@tonic-gate /* just pass them all up - they're harmless */ 16057c478bd9Sstevel@tonic-gate uqi->sm_flags |= SM_CARON; 16067c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 16077c478bd9Sstevel@tonic-gate default: 16087c478bd9Sstevel@tonic-gate putnext(q, mp); 16097c478bd9Sstevel@tonic-gate break; 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate return (0); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * sm_urput - put function for a lower STREAM read. 16177c478bd9Sstevel@tonic-gate */ 16187c478bd9Sstevel@tonic-gate static int 16197c478bd9Sstevel@tonic-gate sm_urput(queue_t *q, mblk_t *mp) 16207c478bd9Sstevel@tonic-gate { 16217c478bd9Sstevel@tonic-gate if (sm_ursendup(q, mp) != 0) 16227c478bd9Sstevel@tonic-gate (void) putq(q, mp); 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate return (0); 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate /* 16287c478bd9Sstevel@tonic-gate * Upper read side service routine. 16297c478bd9Sstevel@tonic-gate * Read side needs to be fast so only check for duplicate M_IOCTL acks. 16307c478bd9Sstevel@tonic-gate */ 16317c478bd9Sstevel@tonic-gate static int 16327c478bd9Sstevel@tonic-gate sm_ursrv(queue_t *q) 16337c478bd9Sstevel@tonic-gate { 16347c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 16357c478bd9Sstevel@tonic-gate mblk_t *mp; 16367c478bd9Sstevel@tonic-gate int flags = uqi->sm_flags; 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate while ((mp = getq(q))) { 16397c478bd9Sstevel@tonic-gate if (sm_ursendup(q, mp) != 0) { 16407c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_ursrv: flow controlled.\n")); 16417c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 16427c478bd9Sstevel@tonic-gate uqi->sm_flags |= WANT_RENB; 16437c478bd9Sstevel@tonic-gate break; 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * If the q service was called because it was no longer 16497c478bd9Sstevel@tonic-gate * flow controled then enable each of the driver queues. 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate if ((flags & WANT_RENB) && !(uqi->sm_flags & WANT_RENB)) { 16527c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 16537c478bd9Sstevel@tonic-gate queue_t *drq; /* read q of linked driver */ 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~WANT_RENB; 16567c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 16577c478bd9Sstevel@tonic-gate drq = SM_RQ(lqi)->q_next; 16587c478bd9Sstevel@tonic-gate if (drq && drq->q_first != 0) 16597c478bd9Sstevel@tonic-gate qenable(drq); 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate return (0); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * Check a message sent from a linked device for abort requests and 16687c478bd9Sstevel@tonic-gate * for flow control. 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate static int 16717c478bd9Sstevel@tonic-gate sm_lrmsg_check(queue_t *q, mblk_t *mp) 16727c478bd9Sstevel@tonic-gate { 16737c478bd9Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 16767c478bd9Sstevel@tonic-gate case M_DATA: 16777c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate * check for abort - only allow abort on I/O consoles 16807c478bd9Sstevel@tonic-gate * known to OBP - 16817c478bd9Sstevel@tonic-gate * fix it when we do polled io 16827c478bd9Sstevel@tonic-gate */ 16837c478bd9Sstevel@tonic-gate if ((lqi->sm_ioflag & (uint_t)FORINPUT) == 0) { 16847c478bd9Sstevel@tonic-gate freemsg(mp); 16857c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 16867c478bd9Sstevel@tonic-gate return (1); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_OBPCNDEV) && 16897c478bd9Sstevel@tonic-gate lqi->sm_ctrla_abort_on && 16907c478bd9Sstevel@tonic-gate abort_enable == KIOCABORTALTERNATE) { 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate uchar_t *rxc; 16937c478bd9Sstevel@tonic-gate boolean_t aborted = B_FALSE; 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate for (rxc = mp->b_rptr; 16967c478bd9Sstevel@tonic-gate rxc != mp->b_wptr; 16977c478bd9Sstevel@tonic-gate rxc++) 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate if (*rxc == *lqi->sm_nachar) { 17007c478bd9Sstevel@tonic-gate lqi->sm_nachar++; 17017c478bd9Sstevel@tonic-gate if (*lqi->sm_nachar == '\0') { 17027c478bd9Sstevel@tonic-gate abort_sequence_enter( 17037c478bd9Sstevel@tonic-gate (char *)NULL); 17047c478bd9Sstevel@tonic-gate lqi->sm_nachar = sm_ssp->sm_abs; 17057c478bd9Sstevel@tonic-gate aborted = B_TRUE; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate } else 17087c478bd9Sstevel@tonic-gate lqi->sm_nachar = (*rxc == *sm_ssp-> 17097c478bd9Sstevel@tonic-gate sm_abs) ? 17107c478bd9Sstevel@tonic-gate sm_ssp-> 17117c478bd9Sstevel@tonic-gate sm_abs + 1 : 17127c478bd9Sstevel@tonic-gate sm_ssp->sm_abs; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate if (aborted) { 17157c478bd9Sstevel@tonic-gate freemsg(mp); 17167c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17177c478bd9Sstevel@tonic-gate return (1); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17217c478bd9Sstevel@tonic-gate break; 17227c478bd9Sstevel@tonic-gate case M_BREAK: /* we'll eventually see this as a flush */ 17237c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 17247c478bd9Sstevel@tonic-gate /* 17257c478bd9Sstevel@tonic-gate * Only allow abort on OBP devices. When polled I/O is 17267c478bd9Sstevel@tonic-gate * supported allow abort on any console device. 17277c478bd9Sstevel@tonic-gate * Parity errors are reported upstream as breaks so 17287c478bd9Sstevel@tonic-gate * ensure that there is no data in the message before 17297c478bd9Sstevel@tonic-gate * deciding whether to abort. 17307c478bd9Sstevel@tonic-gate */ 17317c478bd9Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_OBPCNDEV) && /* console stream */ 17327c478bd9Sstevel@tonic-gate (mp->b_wptr - mp->b_rptr == 0 && 17337c478bd9Sstevel@tonic-gate msgdsize(mp) == 0)) { /* not due to parity */ 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if (lqi->sm_break_abort_on && 17367c478bd9Sstevel@tonic-gate abort_enable != KIOCABORTALTERNATE) 17377c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate freemsg(mp); 17407c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17417c478bd9Sstevel@tonic-gate return (1); 17427c478bd9Sstevel@tonic-gate } else { 17437c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate break; 17467c478bd9Sstevel@tonic-gate default: 17477c478bd9Sstevel@tonic-gate break; 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) >= QPCTL) 17517c478bd9Sstevel@tonic-gate return (0); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); /* lock out the upper half */ 17547c478bd9Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_UQVALID) && SM_RQ(lqi->sm_uqi)) { 17557c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17567c478bd9Sstevel@tonic-gate if (!canput(SM_RQ(lqi->sm_uqi))) { 17577c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_lrmsg_check: flow controlled.\n")); 17587c478bd9Sstevel@tonic-gate (void) putq(q, mp); 17597c478bd9Sstevel@tonic-gate return (1); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate } else { 17627c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate return (0); 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate /* 17697c478bd9Sstevel@tonic-gate * sm_sendup - deliver a message to the upper read side of the multiplexer 17707c478bd9Sstevel@tonic-gate */ 17717c478bd9Sstevel@tonic-gate static int 17727c478bd9Sstevel@tonic-gate sm_sendup(queue_t *q, mblk_t *mp) 17737c478bd9Sstevel@tonic-gate { 17747c478bd9Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate if (sm_ssp == NULL) { 17777c478bd9Sstevel@tonic-gate freemsg(mp); 17787c478bd9Sstevel@tonic-gate return (0); 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * Check for CD status change messages from driver. 17837c478bd9Sstevel@tonic-gate * (Remark: this is an se driver thread running at soft interupt 17847c478bd9Sstevel@tonic-gate * priority and the waiters are in user context). 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 17877c478bd9Sstevel@tonic-gate case M_DATA: 17887c478bd9Sstevel@tonic-gate case M_BREAK: /* we'll eventually see this as a flush */ 17897c478bd9Sstevel@tonic-gate break; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate /* high priority messages */ 17927c478bd9Sstevel@tonic-gate case M_IOCACK: 17937c478bd9Sstevel@tonic-gate case M_IOCNAK: 17947c478bd9Sstevel@tonic-gate if ((lqi->sm_flags & SM_IOCPENDING) && lqi->sm_piocid == 17957c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_id) { 17967c478bd9Sstevel@tonic-gate freemsg(mp); 17977c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~SM_IOCPENDING; 17987c478bd9Sstevel@tonic-gate sm_issue_ioctl(lqi); 17997c478bd9Sstevel@tonic-gate return (0); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate break; 18027c478bd9Sstevel@tonic-gate case M_UNHANGUP: 18037c478bd9Sstevel@tonic-gate /* 18047c478bd9Sstevel@tonic-gate * If the driver can send an M_UNHANGUP it must be able to 18057c478bd9Sstevel@tonic-gate * accept messages from above (ie clear WERROR_MODE if set). 18067c478bd9Sstevel@tonic-gate */ 18077c478bd9Sstevel@tonic-gate sm_dbg('E', ("lrput: M_UNHANGUP\n")); 18087c478bd9Sstevel@tonic-gate lqi->sm_mbits |= TIOCM_CD; 18097c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~(WERROR_MODE|HANGUP_MODE); 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate break; 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate case M_HANGUP: 18147c478bd9Sstevel@tonic-gate sm_dbg('E', ("lrput: MHANGUP\n")); 18157c478bd9Sstevel@tonic-gate lqi->sm_mbits &= ~TIOCM_CD; 18167c478bd9Sstevel@tonic-gate lqi->sm_flags |= (WERROR_MODE|HANGUP_MODE); 18177c478bd9Sstevel@tonic-gate break; 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate case M_ERROR: 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate sm_dbg('E', ("lrput: MERROR\n")); 18227c478bd9Sstevel@tonic-gate /* 18237c478bd9Sstevel@tonic-gate * Tell the driver to flush rd/wr queue if its read/write error. 18247c478bd9Sstevel@tonic-gate * if its a read/write error flush rq/wq (type in first bytes). 18257c478bd9Sstevel@tonic-gate */ 18267c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) == 2) { 18277c478bd9Sstevel@tonic-gate uchar_t rw = 0; 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate if (*mp->b_rptr == NOERROR) { 18307c478bd9Sstevel@tonic-gate /* not in error anymore */ 18317c478bd9Sstevel@tonic-gate lqi->sm_flags &= ~ERROR_MODE; 18327c478bd9Sstevel@tonic-gate lqi->sm_flags |= WANT_CD; 18337c478bd9Sstevel@tonic-gate } else { 18347c478bd9Sstevel@tonic-gate if (*mp->b_rptr != 0) { 18357c478bd9Sstevel@tonic-gate /* read error */ 18367c478bd9Sstevel@tonic-gate rw |= FLUSHR; 18377c478bd9Sstevel@tonic-gate lqi->sm_flags |= RERROR_MODE; 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate mp->b_rptr++; 18407c478bd9Sstevel@tonic-gate if (*mp->b_rptr != 0) { 18417c478bd9Sstevel@tonic-gate /* write error */ 18427c478bd9Sstevel@tonic-gate rw |= FLUSHW; 18437c478bd9Sstevel@tonic-gate lqi->sm_flags |= WERROR_MODE; 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate mp->b_rptr--; 18477c478bd9Sstevel@tonic-gate /* has next driver done qprocsoff */ 18487c478bd9Sstevel@tonic-gate if (rw && OTHERQ(q)->q_next != NULL) { 18497c478bd9Sstevel@tonic-gate (void) putnextctl1(OTHERQ(q), M_FLUSH, 18507c478bd9Sstevel@tonic-gate rw); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate } else if (*mp->b_rptr != 0 && OTHERQ(q)->q_next != NULL) { 18547c478bd9Sstevel@tonic-gate sm_dbg('E', ("lrput: old style MERROR (?)\n")); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate lqi->sm_flags |= (RERROR_MODE | WERROR_MODE); 18577c478bd9Sstevel@tonic-gate (void) putnextctl1(OTHERQ(q), M_FLUSH, FLUSHRW); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate break; 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate case M_PCSIG: 18627c478bd9Sstevel@tonic-gate case M_SIG: 18637c478bd9Sstevel@tonic-gate break; 18647c478bd9Sstevel@tonic-gate case M_COPYOUT: 18657c478bd9Sstevel@tonic-gate case M_COPYIN: 18667c478bd9Sstevel@tonic-gate break; 18677c478bd9Sstevel@tonic-gate case M_FLUSH: 18687c478bd9Sstevel@tonic-gate /* flush the read queue and pass on up */ 18697c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 18707c478bd9Sstevel@tonic-gate break; 18717c478bd9Sstevel@tonic-gate default: 18727c478bd9Sstevel@tonic-gate break; 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); /* lock out the upper half */ 18767c478bd9Sstevel@tonic-gate if (lqi->sm_uqflags & SM_UQVALID && SM_RQ(lqi->sm_uqi)) { 18777c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 18787c478bd9Sstevel@tonic-gate (void) putq(SM_RQ(lqi->sm_uqi), mp); 18797c478bd9Sstevel@tonic-gate return (0); 18807c478bd9Sstevel@tonic-gate } else { 18817c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_sendup: uq not valid\n")); 18827c478bd9Sstevel@tonic-gate freemsg(mp); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate return (0); 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * sm_lrput - put function for a lower STREAM read. 18917c478bd9Sstevel@tonic-gate */ 18927c478bd9Sstevel@tonic-gate static int 18937c478bd9Sstevel@tonic-gate sm_lrput(queue_t *q, mblk_t *mp) 18947c478bd9Sstevel@tonic-gate { 18957c478bd9Sstevel@tonic-gate if (sm_lrmsg_check(q, mp) == 0) 18967c478bd9Sstevel@tonic-gate (void) sm_sendup(q, mp); 18977c478bd9Sstevel@tonic-gate return (0); 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate /* 19017c478bd9Sstevel@tonic-gate * sm_lrsrv - service function for the lower read STREAM. 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate static int 19047c478bd9Sstevel@tonic-gate sm_lrsrv(queue_t *q) 19057c478bd9Sstevel@tonic-gate { 19067c478bd9Sstevel@tonic-gate mblk_t *mp; 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate sm_dbg('I', ("sm_lrsrv: not controlled.\n")); 19097c478bd9Sstevel@tonic-gate while (mp = getq(q)) 19107c478bd9Sstevel@tonic-gate (void) sm_sendup(q, mp); 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate return (0); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate /* 19167c478bd9Sstevel@tonic-gate * Check whether a thread is allowed to open the requested device. 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate static int 19197c478bd9Sstevel@tonic-gate sm_ok_to_open(sm_uqi_t *uqi, int protocol, cred_t *credp, int *abort_waiters) 19207c478bd9Sstevel@tonic-gate { 19217c478bd9Sstevel@tonic-gate int rval = 0; 19227c478bd9Sstevel@tonic-gate int proto; 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate *abort_waiters = 0; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate switch (protocol) { 19277c478bd9Sstevel@tonic-gate case ASYNC_DEVICE: /* Standard async protocol */ 19287c478bd9Sstevel@tonic-gate if ((uqi->sm_protocol == NULL_PROTOCOL) || 19297c478bd9Sstevel@tonic-gate (uqi->sm_protocol == ASYN_PROTOCOL)) { 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * Lock out other incompatible protocol requests. 19327c478bd9Sstevel@tonic-gate */ 19337c478bd9Sstevel@tonic-gate proto = ASYN_PROTOCOL; 19347c478bd9Sstevel@tonic-gate rval = 0; 19357c478bd9Sstevel@tonic-gate } else 19367c478bd9Sstevel@tonic-gate rval = EBUSY; 19377c478bd9Sstevel@tonic-gate break; 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate case OUTLINE: /* Outdial protocol */ 19407c478bd9Sstevel@tonic-gate if ((uqi->sm_protocol == NULL_PROTOCOL) || 19417c478bd9Sstevel@tonic-gate (uqi->sm_protocol == OUTD_PROTOCOL)) { 19427c478bd9Sstevel@tonic-gate proto = OUTD_PROTOCOL; 19437c478bd9Sstevel@tonic-gate rval = 0; 19447c478bd9Sstevel@tonic-gate } else if (uqi->sm_protocol == ASYN_PROTOCOL) { 19457c478bd9Sstevel@tonic-gate /* 19467c478bd9Sstevel@tonic-gate * check for dialout request on a line that is already 19477c478bd9Sstevel@tonic-gate * open for dial in: 19487c478bd9Sstevel@tonic-gate * kick off any thread that is waiting to fully open 19497c478bd9Sstevel@tonic-gate */ 19507c478bd9Sstevel@tonic-gate if (uqi->sm_flags & FULLY_OPEN) 19517c478bd9Sstevel@tonic-gate rval = EBUSY; 19527c478bd9Sstevel@tonic-gate else { 19537c478bd9Sstevel@tonic-gate proto = OUTD_PROTOCOL; 19547c478bd9Sstevel@tonic-gate *abort_waiters = 1; 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate } else 19577c478bd9Sstevel@tonic-gate rval = EBUSY; 19587c478bd9Sstevel@tonic-gate break; 19597c478bd9Sstevel@tonic-gate default: 19607c478bd9Sstevel@tonic-gate rval = ENOTSUP; 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate if (rval == 0 && 19647c478bd9Sstevel@tonic-gate (uqi->sm_ttycommon->t_flags & TS_XCLUDE) && 19657c478bd9Sstevel@tonic-gate secpolicy_excl_open(credp) != 0) { 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate if (uqi->sm_flags & FULLY_OPEN) { 19687c478bd9Sstevel@tonic-gate rval = EBUSY; /* exclusive device already open */ 19697c478bd9Sstevel@tonic-gate } else { 19707c478bd9Sstevel@tonic-gate /* NB TS_XCLUDE cant be set during open so NOTREACHED */ 19717c478bd9Sstevel@tonic-gate /* force any waiters to yield TS_XCLUDE */ 19727c478bd9Sstevel@tonic-gate *abort_waiters = 1; 19737c478bd9Sstevel@tonic-gate } 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate if (rval == 0) 19777c478bd9Sstevel@tonic-gate uqi->sm_protocol = proto; 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate sm_dbg('A', ("ok_to_open (0x%p, %d) proto=%d rval %d (wabort=%d)", 19807c478bd9Sstevel@tonic-gate uqi, protocol, uqi->sm_protocol, rval, *abort_waiters)); 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate return (rval); 19837c478bd9Sstevel@tonic-gate } 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate /* wait for memory to become available whilst performing a qwait */ 19867c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19877c478bd9Sstevel@tonic-gate static void dummy_callback(void *arg) 19887c478bd9Sstevel@tonic-gate {} 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 19917c478bd9Sstevel@tonic-gate static int 19927c478bd9Sstevel@tonic-gate sm_dump_msg(queue_t *q, mblk_t *mp) 19937c478bd9Sstevel@tonic-gate { 19947c478bd9Sstevel@tonic-gate freemsg(mp); 19957c478bd9Sstevel@tonic-gate return (0); 19967c478bd9Sstevel@tonic-gate } 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate /* 19997c478bd9Sstevel@tonic-gate * Wait for a message to arrive - must be called with exclusive 20007c478bd9Sstevel@tonic-gate * access at the outer perimiter. 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate static int 20037c478bd9Sstevel@tonic-gate sm_qwait_sig(sm_uqi_t *uqi, queue_t *q) 20047c478bd9Sstevel@tonic-gate { 20057c478bd9Sstevel@tonic-gate int err; 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_qwait_sig: waiting.\n")); 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate uqi->sm_waitq = q; 20107c478bd9Sstevel@tonic-gate uqi->sm_nwaiters++; /* required by the close routine */ 20117c478bd9Sstevel@tonic-gate err = qwait_sig(q); 20127c478bd9Sstevel@tonic-gate if (--uqi->sm_nwaiters == 0) 20137c478bd9Sstevel@tonic-gate uqi->sm_waitq = 0; 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate if (err == 0) 20167c478bd9Sstevel@tonic-gate err = EINTR; 20177c478bd9Sstevel@tonic-gate else if (q->q_ptr == 0) /* can happen if there are multiple waiters */ 20187c478bd9Sstevel@tonic-gate err = -1; 20197c478bd9Sstevel@tonic-gate else if (uqi->sm_flags & SM_CLOSE) { 20207c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~SM_CLOSE; 20217c478bd9Sstevel@tonic-gate err = 1; /* a different protocol has closed its stream */ 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate else 20247c478bd9Sstevel@tonic-gate err = 0; /* was worth waiting for */ 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_qwait_sig: rval %d\n", err)); 20277c478bd9Sstevel@tonic-gate return (err); 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate /* 20317c478bd9Sstevel@tonic-gate * Defer the opening of one the drivers devices until the state of each 20327c478bd9Sstevel@tonic-gate * associated lower stream is known. 20337c478bd9Sstevel@tonic-gate */ 20347c478bd9Sstevel@tonic-gate static int 20357c478bd9Sstevel@tonic-gate sm_defer_open(sm_uqi_t *uqi, queue_t *q) 20367c478bd9Sstevel@tonic-gate { 20377c478bd9Sstevel@tonic-gate uint_t cmdflags = WANT_CDSTAT; 20387c478bd9Sstevel@tonic-gate int err, nqs; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate while ((nqs = sm_good_qs(uqi)) == 0) { 20417c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: no good qs\n")); 20427c478bd9Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 20437c478bd9Sstevel@tonic-gate return (err); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate while ((uqi->sm_flags & SM_CARON) == 0) { 20477c478bd9Sstevel@tonic-gate int iocmd; 20487c478bd9Sstevel@tonic-gate mblk_t *pioc; 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: flags 0x%x cmdflags 0x%x\n", 20517c478bd9Sstevel@tonic-gate uqi->sm_flags, cmdflags)); 20527c478bd9Sstevel@tonic-gate if (cmdflags == 0) { 20537c478bd9Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 20547c478bd9Sstevel@tonic-gate return (err); 20557c478bd9Sstevel@tonic-gate continue; /* waiting for an M_UNHANGUP */ 20567c478bd9Sstevel@tonic-gate } else if (cmdflags & WANT_SC) { 20577c478bd9Sstevel@tonic-gate cmdflags &= ~WANT_SC; 20587c478bd9Sstevel@tonic-gate iocmd = TIOCGSOFTCAR; 20597c478bd9Sstevel@tonic-gate } else if (cmdflags & WANT_CD) { 20607c478bd9Sstevel@tonic-gate cmdflags &= ~WANT_CD; 20617c478bd9Sstevel@tonic-gate iocmd = TIOCMGET; 20627c478bd9Sstevel@tonic-gate } else if (cmdflags & WANT_CL) { 20637c478bd9Sstevel@tonic-gate cmdflags &= ~WANT_CL; 20647c478bd9Sstevel@tonic-gate iocmd = TCGETS; 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate if (uqi->sm_piocdata.sm_iocid == 0) { 20687c478bd9Sstevel@tonic-gate while ((pioc = mkiocb(iocmd)) == 0) { 20697c478bd9Sstevel@tonic-gate bufcall_id_t id = 20707c478bd9Sstevel@tonic-gate qbufcall(q, sizeof (struct iocblk), 20717c478bd9Sstevel@tonic-gate BPRI_MED, dummy_callback, 0); 20727c478bd9Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) { 20737c478bd9Sstevel@tonic-gate /* wait for the bufcall */ 20747c478bd9Sstevel@tonic-gate qunbufcall(q, id); 20757c478bd9Sstevel@tonic-gate return (err); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate qunbufcall(q, id); 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate uqi->sm_flags |= SM_IOCPENDING; 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_iocid = 20837c478bd9Sstevel@tonic-gate ((struct iocblk *)pioc->b_rptr)->ioc_id; 20847c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_acked = 0; 20857c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_nacks = nqs; 20867c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_acnt = 0; 20877c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_ackcnt = uqi-> 20887c478bd9Sstevel@tonic-gate sm_piocdata.sm_nakcnt = 0; 20897c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_policy = uqi->sm_policy; 20907c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_flags = SM_INTERNALIOC; 20917c478bd9Sstevel@tonic-gate if (sm_putqs(WR(q), pioc, sm_dump_msg) != 0) { 20927c478bd9Sstevel@tonic-gate uqi->sm_piocdata.sm_iocid = 0; 20937c478bd9Sstevel@tonic-gate sm_log("sm_defer_open: bad putqs\n"); 20947c478bd9Sstevel@tonic-gate return (-1); 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: flags 0x%x\n", uqi->sm_flags)); 20997c478bd9Sstevel@tonic-gate while ((uqi->sm_flags & SM_CARON) == 0 && 21007c478bd9Sstevel@tonic-gate (uqi->sm_flags & SM_IOCPENDING) != 0) 21017c478bd9Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 21027c478bd9Sstevel@tonic-gate return (err); 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate sm_dbg('C', ("defer_open: uq flags 0x%x.\n", uqi->sm_flags)); 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate sm_dbg('C', ("defer_open: return 0.\n")); 21077c478bd9Sstevel@tonic-gate return (0); 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate static int 21117c478bd9Sstevel@tonic-gate sm_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 21127c478bd9Sstevel@tonic-gate { 21137c478bd9Sstevel@tonic-gate int ftstat; 21147c478bd9Sstevel@tonic-gate int unit; 21157c478bd9Sstevel@tonic-gate int protocol; 21167c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 21177c478bd9Sstevel@tonic-gate int abort_waiters; 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate if (sm_ssp == NULL) 21207c478bd9Sstevel@tonic-gate return (ENXIO); 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * sflag = 0 => streams device. 21237c478bd9Sstevel@tonic-gate */ 21247c478bd9Sstevel@tonic-gate if (sflag != 0 || DEV_TO_UNIT(*devp) >= NLUNITS) { 21257c478bd9Sstevel@tonic-gate sm_dbg('C', ("open: sflag=%d or bad dev_t.\n", sflag)); 21267c478bd9Sstevel@tonic-gate return (ENXIO); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate unit = DEV_TO_UNIT(*devp); 21307c478bd9Sstevel@tonic-gate protocol = DEV_TO_PROTOBITS(*devp); 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate uqi = get_uqi(sm_ssp, unit); 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate sm_dbg('C', ("open(0x%p, %d, 0x%x) :- unit=%d, proto=%d, uqi=0x%p\n", 21357c478bd9Sstevel@tonic-gate rq, *devp, flag, unit, protocol, uqi)); 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate if (uqi == 0) 21387c478bd9Sstevel@tonic-gate return (ENXIO); 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate if (sm_refuse_opens && unit > smctlunit && uqi->sm_nlqs == 0) 21417c478bd9Sstevel@tonic-gate return (ENXIO); 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate if (uqi->sm_flags & EXCL_OPEN && (flag & FEXCL)) { 21447c478bd9Sstevel@tonic-gate return (EBUSY); /* device in use */ 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate if ((flag & FEXCL)) { 21487c478bd9Sstevel@tonic-gate if (secpolicy_excl_open(credp) != 0) 21497c478bd9Sstevel@tonic-gate return (EPERM); 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_nwaiters > 0) 21527c478bd9Sstevel@tonic-gate return (EBUSY); /* device in use */ 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate uqi->sm_flags |= EXCL_OPEN; 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate if (uqi->sm_protocol == NULL_PROTOCOL) { 21587c478bd9Sstevel@tonic-gate struct termios *termiosp; 21597c478bd9Sstevel@tonic-gate int len; 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 21627c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM, "ttymodes", (caddr_t)&termiosp, &len) 21637c478bd9Sstevel@tonic-gate == DDI_PROP_SUCCESS && 21647c478bd9Sstevel@tonic-gate (len == sizeof (struct termios))) { 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate sm_dbg('C', ("open: c_cflag=0x%x\n", 21677c478bd9Sstevel@tonic-gate termiosp->c_cflag)); 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_iflag = termiosp->c_iflag; 21707c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = termiosp->c_cflag; 21717c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_stopc = termiosp->c_cc[VSTOP]; 21727c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_startc = termiosp->c_cc[VSTART]; 21737c478bd9Sstevel@tonic-gate 21747c478bd9Sstevel@tonic-gate /* 21757c478bd9Sstevel@tonic-gate * IGNBRK,BRKINT,INPCK,IXON,IXANY,IXOFF - drivers 21767c478bd9Sstevel@tonic-gate * PARMRK,IGNPAR,ISTRIP - how to report parity 21777c478bd9Sstevel@tonic-gate * INLCR,IGNCR,ICRNL,IUCLC - ldterm (sophisticated I/O) 21787c478bd9Sstevel@tonic-gate * IXON, IXANY, IXOFF - flow control input 21797c478bd9Sstevel@tonic-gate * CBAUD,CSIZE,CS5-8,CSTOPB,PARENB,PARODD,HUPCL, 21807c478bd9Sstevel@tonic-gate * RCV1EN,XMT1EN,LOBLK,XCLUDE,CRTSXOFF,CRTSCTS, 21817c478bd9Sstevel@tonic-gate * CIBAUD,PAREXT,CBAUDEXT,CIBAUDEXT,CREAD,CLOCAL 21827c478bd9Sstevel@tonic-gate */ 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate kmem_free(termiosp, len); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate else 21877c478bd9Sstevel@tonic-gate bzero((caddr_t)uqi->sm_ttycommon, 21887c478bd9Sstevel@tonic-gate sizeof (uqi->sm_ttycommon)); 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate if (*devp == rconsdev) { 21917c478bd9Sstevel@tonic-gate uqi->sm_cmask = sm_cmask; 21927c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_flags |= TS_SOFTCAR; 21937c478bd9Sstevel@tonic-gate } else { 21947c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR; 21957c478bd9Sstevel@tonic-gate } 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate /* 21987c478bd9Sstevel@tonic-gate * Clear the default CLOCAL and TS_SOFTCAR flags since 21997c478bd9Sstevel@tonic-gate * they must correspond to the settings on the real devices. 22007c478bd9Sstevel@tonic-gate */ 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag &= ~(uqi->sm_cmask|CLOCAL); 22037c478bd9Sstevel@tonic-gate uqi->sm_mbits = 0; 22047c478bd9Sstevel@tonic-gate uqi->sm_policy = FIRSTACK; 22057c478bd9Sstevel@tonic-gate if (unit == 0 && sm_ssp->sm_ms == 0) 22067c478bd9Sstevel@tonic-gate sm_ssp->sm_ms = (sm_mux_state_t *) 22077c478bd9Sstevel@tonic-gate space_fetch(TTYMUXPTR); 22087c478bd9Sstevel@tonic-gate if (sm_ssp->sm_ms) { 22097c478bd9Sstevel@tonic-gate if (sm_ssp->sm_ms->sm_cons_stdin.sm_dev == *devp || 22107c478bd9Sstevel@tonic-gate sm_ssp->sm_ms->sm_cons_stdout.sm_dev == *devp) 22117c478bd9Sstevel@tonic-gate sm_ssp->sm_lconsole = uqi; 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate /* 22167c478bd9Sstevel@tonic-gate * Does this thread need to wait? 22177c478bd9Sstevel@tonic-gate */ 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_open: %d %d 0x%p 0x%x\n", 22207c478bd9Sstevel@tonic-gate !(flag & (FNDELAY|FNONBLOCK)), !(protocol == OUTLINE), uqi->sm_lqs, 22217c478bd9Sstevel@tonic-gate uqi->sm_flags)); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate tryopen: 22247c478bd9Sstevel@tonic-gate 22257c478bd9Sstevel@tonic-gate abort_waiters = 0; 22267c478bd9Sstevel@tonic-gate if (ftstat = sm_ok_to_open(uqi, protocol, credp, &abort_waiters)) { 22277c478bd9Sstevel@tonic-gate sm_dbg('C', ("open failed stat=%d.\n", ftstat)); 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0 && uqi->sm_nwaiters == 0) 22307c478bd9Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 22317c478bd9Sstevel@tonic-gate if (flag & FEXCL) 22327c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~EXCL_OPEN; 22337c478bd9Sstevel@tonic-gate return (ftstat); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate if (abort_waiters) { 22377c478bd9Sstevel@tonic-gate uqi->sm_dev = *devp; 22387c478bd9Sstevel@tonic-gate /* different device wants to use the unit */ 22397c478bd9Sstevel@tonic-gate SM_RQ(uqi) = rq; 22407c478bd9Sstevel@tonic-gate SM_WQ(uqi) = WR(rq); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate if (rq->q_ptr == 0) { 22437c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate uqi->sm_dev = *devp; 22467c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = uqi; 22477c478bd9Sstevel@tonic-gate SM_RQ(uqi) = rq; 22487c478bd9Sstevel@tonic-gate SM_WQ(uqi) = WR(rq); 22497c478bd9Sstevel@tonic-gate qprocson(rq); 22507c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 22517c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 22527c478bd9Sstevel@tonic-gate lqi->sm_uqflags |= SM_UQVALID; 22537c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_open: SM_UQVALID set on lqs.\n")); 22577c478bd9Sstevel@tonic-gate } 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate if (*devp != rconsdev && BLOCKING(uqi, protocol, flag)) { 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate uqi->sm_flags |= WANT_CDSTAT; 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate do { 22647c478bd9Sstevel@tonic-gate /* 22657c478bd9Sstevel@tonic-gate * Wait for notifications of changes in the CLOCAL 22667c478bd9Sstevel@tonic-gate * and TS_SOFTCAR flags and a TIOCM_CD flag of a 22677c478bd9Sstevel@tonic-gate * TIOCMGET request (come in on the write side queue). 22687c478bd9Sstevel@tonic-gate */ 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate if ((ftstat = sm_defer_open(uqi, rq)) != EINTR) { 22717c478bd9Sstevel@tonic-gate if (ftstat) { 22727c478bd9Sstevel@tonic-gate goto tryopen; 22737c478bd9Sstevel@tonic-gate } else { 22747c478bd9Sstevel@tonic-gate continue; 22757c478bd9Sstevel@tonic-gate } 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate if (uqi->sm_nwaiters == 0) { /* clean up */ 22797c478bd9Sstevel@tonic-gate /* 22807c478bd9Sstevel@tonic-gate * only opens on an asynchronous 22817c478bd9Sstevel@tonic-gate * protocols reach here so checking 22827c478bd9Sstevel@tonic-gate * nwaiters == 0 is sufficient to 22837c478bd9Sstevel@tonic-gate * ensure that no other thread 22847c478bd9Sstevel@tonic-gate * is waiting on this logical unit 22857c478bd9Sstevel@tonic-gate */ 22867c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0) { 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate uqi->sm_dev = NODEV; 22917c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_open FULLY_OPEN=0\n")); 22927c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; 22937c478bd9Sstevel@tonic-gate lqi = lqi->sm_nlqi) { 22947c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 22957c478bd9Sstevel@tonic-gate lqi->sm_uqflags &= ~SM_UQVALID; 22967c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate qprocsoff(rq); 23007c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = 0; 23017c478bd9Sstevel@tonic-gate SM_RQ(uqi) = 0; 23027c478bd9Sstevel@tonic-gate SM_WQ(uqi) = 0; 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate } 23057c478bd9Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0 && 23067c478bd9Sstevel@tonic-gate uqi->sm_nwaiters == 0) 23077c478bd9Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 23087c478bd9Sstevel@tonic-gate if (flag & FEXCL) 23097c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~EXCL_OPEN; 23107c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_open: done (ret %d).\n", ftstat)); 23117c478bd9Sstevel@tonic-gate return (ftstat); 23127c478bd9Sstevel@tonic-gate } while (BLOCKING(uqi, protocol, flag)); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate uqi->sm_flags |= FULLY_OPEN; 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_open done (ret %d).\n", ftstat)); 23187c478bd9Sstevel@tonic-gate return (ftstat); 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate /* 23227c478bd9Sstevel@tonic-gate * Multiplexer device close routine. 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23257c478bd9Sstevel@tonic-gate static int 23267c478bd9Sstevel@tonic-gate sm_close(queue_t *rq, int flag, cred_t *credp) 23277c478bd9Sstevel@tonic-gate { 23287c478bd9Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)rq->q_ptr; 23297c478bd9Sstevel@tonic-gate sm_lqi_t *lqi; 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate if (sm_ssp == NULL) 23327c478bd9Sstevel@tonic-gate return (ENXIO); 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate if (uqi == NULL) { 23357c478bd9Sstevel@tonic-gate sm_dbg('C', ("close: WARN:- q 0x%p already closed.\n", rq)); 23367c478bd9Sstevel@tonic-gate return (ENXIO); 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate sm_dbg('C', ("close: uqi=0x%p unit=%d q=0x%p)\n", uqi, uqi->sm_lunit, 23407c478bd9Sstevel@tonic-gate rq)); 23417c478bd9Sstevel@tonic-gate 23427c478bd9Sstevel@tonic-gate if (SM_RQ(uqi) != rq) 23437c478bd9Sstevel@tonic-gate sm_dbg('C', ("sm_close: rq != current uqi queue\n")); 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate if (uqi->sm_ttybid) { 23467c478bd9Sstevel@tonic-gate qunbufcall(SM_RQ(uqi), uqi->sm_ttybid); 23477c478bd9Sstevel@tonic-gate uqi->sm_ttybid = 0; 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate /* 23517c478bd9Sstevel@tonic-gate * Tell all the linked queues that the upper queue has gone 23527c478bd9Sstevel@tonic-gate * Note close will never get called on a stream while there is a 23537c478bd9Sstevel@tonic-gate * thread blocked trying to open the same stream. 23547c478bd9Sstevel@tonic-gate * If there is a blocked open on a different stream but on 23557c478bd9Sstevel@tonic-gate * the same logical unit it will reset the lower queue flags. 23567c478bd9Sstevel@tonic-gate */ 23577c478bd9Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 23587c478bd9Sstevel@tonic-gate LOCK_UNIT(lqi); 23597c478bd9Sstevel@tonic-gate lqi->sm_uqflags &= ~SM_UQVALID; 23607c478bd9Sstevel@tonic-gate UNLOCK_UNIT(lqi); 23617c478bd9Sstevel@tonic-gate } 23627c478bd9Sstevel@tonic-gate 23637c478bd9Sstevel@tonic-gate /* 23647c478bd9Sstevel@tonic-gate * Turn off the STREAMs queue processing for this queue. 23657c478bd9Sstevel@tonic-gate */ 23667c478bd9Sstevel@tonic-gate qprocsoff(rq); 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate /* 23697c478bd9Sstevel@tonic-gate * Similarly we will never get here if there is thread trying to 23707c478bd9Sstevel@tonic-gate * open ths stream. 23717c478bd9Sstevel@tonic-gate */ 23727c478bd9Sstevel@tonic-gate LOCK_UNIT(uqi); 23737c478bd9Sstevel@tonic-gate if (uqi->sm_waitq == 0) 23747c478bd9Sstevel@tonic-gate uqi->sm_flags = (uqi->sm_flags & SM_OBPCNDEV) ? SM_OBPCNDEV : 23757c478bd9Sstevel@tonic-gate 0U; 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate uqi->sm_dev = NODEV; 23787c478bd9Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 23797c478bd9Sstevel@tonic-gate ttycommon_close(uqi->sm_ttycommon); 23807c478bd9Sstevel@tonic-gate /* it just frees any pending ioctl */ 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 0; 23837c478bd9Sstevel@tonic-gate uqi->sm_ttycommon->t_flags = 0; 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate /* 23867c478bd9Sstevel@tonic-gate * Reset the queue pointers to NULL. 23877c478bd9Sstevel@tonic-gate * If a thread is qwaiting in the open routine it will recheck 23887c478bd9Sstevel@tonic-gate * the q_ptr. 23897c478bd9Sstevel@tonic-gate */ 23907c478bd9Sstevel@tonic-gate rq->q_ptr = NULL; 23917c478bd9Sstevel@tonic-gate WR(rq)->q_ptr = NULL; 23927c478bd9Sstevel@tonic-gate UNLOCK_UNIT(uqi); 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate if (sm_ssp->sm_lconsole == uqi) { 23957c478bd9Sstevel@tonic-gate /* this will never be the outdial device closing */ 23967c478bd9Sstevel@tonic-gate sm_ssp->sm_lconsole = 0; 23977c478bd9Sstevel@tonic-gate } 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * If there is another thread waiting for this close then unblock 24007c478bd9Sstevel@tonic-gate * the thread by putting a message on its read queue. 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate if (uqi->sm_waitq) { 24037c478bd9Sstevel@tonic-gate sm_dbg('C', ("close(0x%p): doing putctl on 0x%p\n", 24047c478bd9Sstevel@tonic-gate rq, uqi->sm_waitq)); 24057c478bd9Sstevel@tonic-gate if (rq == uqi->sm_waitq) 24067c478bd9Sstevel@tonic-gate sm_log("close: waitq and closeq are same q\n"); 24077c478bd9Sstevel@tonic-gate (void) putctl(uqi->sm_waitq, M_CTL); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate uqi->sm_flags &= ~(EXCL_OPEN | FULLY_OPEN); 24117c478bd9Sstevel@tonic-gate sm_dbg('C', ("close: returning ok.\n")); 24127c478bd9Sstevel@tonic-gate return (0); 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate 24157c478bd9Sstevel@tonic-gate /* 24167c478bd9Sstevel@tonic-gate * Initialise the software abort sequence for use when one of the 24177c478bd9Sstevel@tonic-gate * driver's nodes provides the system console. 24187c478bd9Sstevel@tonic-gate */ 24197c478bd9Sstevel@tonic-gate static void 24207c478bd9Sstevel@tonic-gate sm_set_abort() 24217c478bd9Sstevel@tonic-gate { 24227c478bd9Sstevel@tonic-gate char ds[3] = { '\r', '~', CNTRL('b') }; 24237c478bd9Sstevel@tonic-gate char as[SM_MAX_ABSLEN]; 24247c478bd9Sstevel@tonic-gate int len = SM_MAX_ABSLEN; 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, sm_ssp->sm_dip, PROP_LEN_AND_VAL_BUF, 0, 24277c478bd9Sstevel@tonic-gate "abort-str", as, &len) != DDI_PROP_SUCCESS || 24287c478bd9Sstevel@tonic-gate (len = strlen(as)) < SM_MIN_ABSLEN) { 24297c478bd9Sstevel@tonic-gate (void) strcpy(as, ds); 24307c478bd9Sstevel@tonic-gate len = strlen(as); 24317c478bd9Sstevel@tonic-gate } else { 24327c478bd9Sstevel@tonic-gate char *s; 24337c478bd9Sstevel@tonic-gate int i; 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate for (s = as, i = 0; i < len-1; i++, s++) { 24367c478bd9Sstevel@tonic-gate if (as[i] == '^' && as[i+1] >= 'a' && as[i+1] <= 'z') { 24377c478bd9Sstevel@tonic-gate *s = as[i+1] - 'a' + 1; 24387c478bd9Sstevel@tonic-gate i++; 24397c478bd9Sstevel@tonic-gate } else { 24407c478bd9Sstevel@tonic-gate *s = as[i]; 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate } 24437c478bd9Sstevel@tonic-gate *s++ = as[i]; 24447c478bd9Sstevel@tonic-gate *s = '\0'; 24457c478bd9Sstevel@tonic-gate len = strlen(as); 24467c478bd9Sstevel@tonic-gate } 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate if (len < SM_MIN_ABSLEN) 24497c478bd9Sstevel@tonic-gate (void) strcpy(sm_ssp->sm_abs, ds); 24507c478bd9Sstevel@tonic-gate else 24517c478bd9Sstevel@tonic-gate (void) strcpy(sm_ssp->sm_abs, as); 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate /* 24557c478bd9Sstevel@tonic-gate * 24567c478bd9Sstevel@tonic-gate * sm_attach - initialisation routine per driver instance. 24577c478bd9Sstevel@tonic-gate */ 24587c478bd9Sstevel@tonic-gate static int 24597c478bd9Sstevel@tonic-gate sm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 24607c478bd9Sstevel@tonic-gate { 24617c478bd9Sstevel@tonic-gate int unit; 24627c478bd9Sstevel@tonic-gate char name[32]; 24637c478bd9Sstevel@tonic-gate sm_uqi_t *uqi; 24647c478bd9Sstevel@tonic-gate sm_lqi_t *lqip; 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate /* 24677c478bd9Sstevel@tonic-gate * Is this an attach? 24687c478bd9Sstevel@tonic-gate */ 24697c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) { 24707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate /* 24747c478bd9Sstevel@tonic-gate * Validate the instance number (sm is a single instance driver). 24757c478bd9Sstevel@tonic-gate */ 24767c478bd9Sstevel@tonic-gate if (sm_ssp) { /* only one instance allowed */ 24777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24787c478bd9Sstevel@tonic-gate } 24797c478bd9Sstevel@tonic-gate 24807c478bd9Sstevel@tonic-gate sm_instance = ddi_get_instance(dip); 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate /* 24837c478bd9Sstevel@tonic-gate * Create the default minor node which will become the console. 24847c478bd9Sstevel@tonic-gate * (create it with three different names).: 24857c478bd9Sstevel@tonic-gate * con which appears in the /dev filesystem; 24867c478bd9Sstevel@tonic-gate * input which matches the prom /multiplexer:input node; 24877c478bd9Sstevel@tonic-gate * output which matches the prom /multiplexer:input node 24887c478bd9Sstevel@tonic-gate * Create a minor node for control operations. 24897c478bd9Sstevel@tonic-gate */ 24907c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "con", S_IFCHR, 0, 24917c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 24927c478bd9Sstevel@tonic-gate ddi_create_minor_node(dip, "input", S_IFCHR, 0, 24937c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 24947c478bd9Sstevel@tonic-gate ddi_create_minor_node(dip, "output", S_IFCHR, 0, 24957c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 24967c478bd9Sstevel@tonic-gate ddi_create_minor_node(dip, "ctl", S_IFCHR, 1, 24977c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS) { 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sm_attach: create minors failed.\n"); 25007c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 25017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate smctlunit = 1; 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate /* 25077c478bd9Sstevel@tonic-gate * Allocate private state for this instance. 25087c478bd9Sstevel@tonic-gate */ 25097c478bd9Sstevel@tonic-gate sm_ssp = (sm_ss_t *)kmem_zalloc(sizeof (sm_ss_t), KM_SLEEP); 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate /* 25127c478bd9Sstevel@tonic-gate * Initialise per instance data. 25137c478bd9Sstevel@tonic-gate */ 25147c478bd9Sstevel@tonic-gate sm_ssp->sm_dip = dip; 25157c478bd9Sstevel@tonic-gate 25167c478bd9Sstevel@tonic-gate /* 25177c478bd9Sstevel@tonic-gate * Get required debug level. 25187c478bd9Sstevel@tonic-gate */ 25197c478bd9Sstevel@tonic-gate sm_ssp->sm_trflag = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25207c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-trlv", sm_default_trflag); 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate sm_max_units = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25237c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-max-units", sm_max_units); 25247c478bd9Sstevel@tonic-gate sm_minor_cnt = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25257c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-minor-cnt", 0); 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate sm_refuse_opens = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25287c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-refuse-opens", sm_refuse_opens); 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate sm_ssp->sm_ctrla_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25317c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-ctrla-abort-on", 1); 25327c478bd9Sstevel@tonic-gate sm_ssp->sm_break_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 25337c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-break-abort-on", 0); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate sm_set_abort(); 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate sm_ssp->sm_lqs = (sm_lqi_t *)kmem_zalloc(sizeof (sm_lqi_t) * MAX_LQS, 25387c478bd9Sstevel@tonic-gate KM_SLEEP); 25397c478bd9Sstevel@tonic-gate sm_ssp->sm_uqs = (sm_uqi_t *)kmem_zalloc(sizeof (sm_uqi_t) * NLUNITS, 25407c478bd9Sstevel@tonic-gate KM_SLEEP); 25417c478bd9Sstevel@tonic-gate 25427c478bd9Sstevel@tonic-gate for (unit = 2; unit < NLUNITS && unit < sm_minor_cnt + 2; unit++) { 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate if (snprintf(name, sizeof (name), "sm%c", 'a' + unit-2) > 25457c478bd9Sstevel@tonic-gate sizeof (name)) { 25467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 25477c478bd9Sstevel@tonic-gate "sm_attach: create device for unit %d failed.\n", 25487c478bd9Sstevel@tonic-gate unit); 25497c478bd9Sstevel@tonic-gate } else if (ddi_create_minor_node(dip, name, S_IFCHR, 25507c478bd9Sstevel@tonic-gate unit, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) { 25517c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 25527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate if (snprintf(name, sizeof (name), "sm%c,cu", 'a' + unit-2) > 25567c478bd9Sstevel@tonic-gate sizeof (name)) { 25577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 25587c478bd9Sstevel@tonic-gate "sm_attach: create cu device for unit %d failed.\n", 25597c478bd9Sstevel@tonic-gate unit); 25607c478bd9Sstevel@tonic-gate continue; 25617c478bd9Sstevel@tonic-gate } else if (ddi_create_minor_node(dip, name, S_IFCHR, 25627c478bd9Sstevel@tonic-gate unit|OUTLINE, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) { 25637c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 25647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 25657c478bd9Sstevel@tonic-gate } 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate uqi = get_uqi(sm_ssp, unit); 25717c478bd9Sstevel@tonic-gate uqi->sm_lqs = 0; 25727c478bd9Sstevel@tonic-gate uqi->sm_dev = NODEV; 25737c478bd9Sstevel@tonic-gate uqi->sm_nlqs = 0; 25747c478bd9Sstevel@tonic-gate uqi->sm_lunit = unit; 25757c478bd9Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 25767c478bd9Sstevel@tonic-gate mutex_init(uqi->sm_umutex, NULL, MUTEX_DRIVER, NULL); 25777c478bd9Sstevel@tonic-gate cv_init(uqi->sm_ucv, NULL, CV_DRIVER, NULL); 25787c478bd9Sstevel@tonic-gate mutex_init(&uqi->sm_ttycommon->t_excl, NULL, 25797c478bd9Sstevel@tonic-gate MUTEX_DRIVER, NULL); 25807c478bd9Sstevel@tonic-gate } 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 25837c478bd9Sstevel@tonic-gate lqip = get_lqi(sm_ssp, unit); 25847c478bd9Sstevel@tonic-gate lqip->sm_unit = unit; 25857c478bd9Sstevel@tonic-gate lqip->sm_hadkadbchar = 0; 25867c478bd9Sstevel@tonic-gate lqip->sm_nachar = sm_ssp->sm_abs; 25877c478bd9Sstevel@tonic-gate lqip->sm_ioflag = FORIO; 25887c478bd9Sstevel@tonic-gate lqip->sm_ctrla_abort_on = sm_ssp->sm_ctrla_abort_on; 25897c478bd9Sstevel@tonic-gate lqip->sm_break_abort_on = sm_ssp->sm_break_abort_on; 25907c478bd9Sstevel@tonic-gate mutex_init(lqip->sm_umutex, NULL, MUTEX_DRIVER, NULL); 25917c478bd9Sstevel@tonic-gate cv_init(lqip->sm_ucv, NULL, CV_DRIVER, NULL); 25927c478bd9Sstevel@tonic-gate mutex_init(&lqip->sm_ttycommon->t_excl, NULL, 25937c478bd9Sstevel@tonic-gate MUTEX_DRIVER, NULL); 25947c478bd9Sstevel@tonic-gate } 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate /* 26007c478bd9Sstevel@tonic-gate * 26017c478bd9Sstevel@tonic-gate * sm_detach - detach routine per driver instance. 26027c478bd9Sstevel@tonic-gate */ 26037c478bd9Sstevel@tonic-gate static int 26047c478bd9Sstevel@tonic-gate sm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 26057c478bd9Sstevel@tonic-gate { 26067c478bd9Sstevel@tonic-gate sm_uqi_t *lu; 26077c478bd9Sstevel@tonic-gate sm_lqi_t *pu; 26087c478bd9Sstevel@tonic-gate int unit; 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate /* 26117c478bd9Sstevel@tonic-gate * Is this a detach request for instance 0 (single instance driver). 26127c478bd9Sstevel@tonic-gate */ 26137c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 26147c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate if (sm_ssp == NULL) 26177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate sm_dbg('V', ("detach ...")); 26207c478bd9Sstevel@tonic-gate 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate /* 26237c478bd9Sstevel@tonic-gate * Check that all the upper and lower queues are closed. 26247c478bd9Sstevel@tonic-gate */ 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 26277c478bd9Sstevel@tonic-gate lu = &sm_ssp->sm_uqs[unit]; 26287c478bd9Sstevel@tonic-gate if (lu && lu->sm_protocol != NULL_PROTOCOL) { 26297c478bd9Sstevel@tonic-gate sm_dbg('V', ("detach: upper unit still open.\n")); 26307c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 26317c478bd9Sstevel@tonic-gate } 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 26347c478bd9Sstevel@tonic-gate pu = &sm_ssp->sm_lqs[unit]; 26357c478bd9Sstevel@tonic-gate if (pu && pu->sm_linkid != 0) { 26367c478bd9Sstevel@tonic-gate sm_dbg('V', ("detach: lower unit still linked (%d)\n", 26377c478bd9Sstevel@tonic-gate pu->sm_linkid)); 26387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 26397c478bd9Sstevel@tonic-gate } 26407c478bd9Sstevel@tonic-gate } 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 26437c478bd9Sstevel@tonic-gate lu = &sm_ssp->sm_uqs[unit]; 26447c478bd9Sstevel@tonic-gate mutex_destroy(lu->sm_umutex); 26457c478bd9Sstevel@tonic-gate cv_destroy(lu->sm_ucv); 26467c478bd9Sstevel@tonic-gate mutex_destroy(&lu->sm_ttycommon->t_excl); 26477c478bd9Sstevel@tonic-gate } 26487c478bd9Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 26497c478bd9Sstevel@tonic-gate pu = &sm_ssp->sm_lqs[unit]; 26507c478bd9Sstevel@tonic-gate mutex_destroy(pu->sm_umutex); 26517c478bd9Sstevel@tonic-gate cv_destroy(pu->sm_ucv); 26527c478bd9Sstevel@tonic-gate mutex_destroy(&pu->sm_ttycommon->t_excl); 26537c478bd9Sstevel@tonic-gate } 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * Tidy up per instance state. 26577c478bd9Sstevel@tonic-gate */ 26587c478bd9Sstevel@tonic-gate kmem_free(sm_ssp->sm_lqs, sizeof (sm_lqi_t) * MAX_LQS); 26597c478bd9Sstevel@tonic-gate kmem_free(sm_ssp->sm_uqs, sizeof (sm_uqi_t) * NLUNITS); 26607c478bd9Sstevel@tonic-gate kmem_free(sm_ssp, sizeof (sm_ss_t)); 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate sm_ssp = 0; 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate /* 26657c478bd9Sstevel@tonic-gate * Remove all of the devices created in attach. 26667c478bd9Sstevel@tonic-gate */ 26677c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 26707c478bd9Sstevel@tonic-gate } 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate /* 26737c478bd9Sstevel@tonic-gate * SECTION 26747c478bd9Sstevel@tonic-gate * Driver interface to the OS. 26757c478bd9Sstevel@tonic-gate */ 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate /* 26787c478bd9Sstevel@tonic-gate * The driver is responsible for managing the mapping between the file system 26797c478bd9Sstevel@tonic-gate * device types (major/minor pairs) and the corresponding instance of the driver 26807c478bd9Sstevel@tonic-gate * or device information pointer (dip). 26817c478bd9Sstevel@tonic-gate * sm_info - return the instance or dip corresponding to the dev_t. 26827c478bd9Sstevel@tonic-gate */ 26837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 26847c478bd9Sstevel@tonic-gate static int 26857c478bd9Sstevel@tonic-gate sm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 26867c478bd9Sstevel@tonic-gate { 26877c478bd9Sstevel@tonic-gate int res = DDI_SUCCESS; 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate switch (infocmd) { 26907c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 26917c478bd9Sstevel@tonic-gate if (sm_ssp == NULL) 26927c478bd9Sstevel@tonic-gate res = DDI_FAILURE; 26937c478bd9Sstevel@tonic-gate else 26947c478bd9Sstevel@tonic-gate *result = (void *)sm_ssp->sm_dip; 26957c478bd9Sstevel@tonic-gate break; 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 26987c478bd9Sstevel@tonic-gate *result = (void*)0; /* single instance driver */ 26997c478bd9Sstevel@tonic-gate break; 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate default: 27027c478bd9Sstevel@tonic-gate res = DDI_FAILURE; 27037c478bd9Sstevel@tonic-gate break; 27047c478bd9Sstevel@tonic-gate } 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate return (res); 27077c478bd9Sstevel@tonic-gate } 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate /* 27107c478bd9Sstevel@tonic-gate * End of driver implementation 27117c478bd9Sstevel@tonic-gate */ 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate /* 27147c478bd9Sstevel@tonic-gate * Loadable module interface to the kernel 27157c478bd9Sstevel@tonic-gate */ 27167c478bd9Sstevel@tonic-gate 27177c478bd9Sstevel@tonic-gate /* 27187c478bd9Sstevel@tonic-gate * Firstly the Streams specific interface 27197c478bd9Sstevel@tonic-gate */ 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate /* 27227c478bd9Sstevel@tonic-gate * Solaris driver/STREAM initialisation structures. 27237c478bd9Sstevel@tonic-gate */ 27247c478bd9Sstevel@tonic-gate static struct module_info uinfo = 27257c478bd9Sstevel@tonic-gate { 27267c478bd9Sstevel@tonic-gate SM_MOD_ID, 27277c478bd9Sstevel@tonic-gate TTYMUX_DRVNAME, 27287c478bd9Sstevel@tonic-gate 0, /* min packet size */ 27297c478bd9Sstevel@tonic-gate INFPSZ, /* max packet size */ 27307c478bd9Sstevel@tonic-gate 2048, /* high water mark */ 27317c478bd9Sstevel@tonic-gate 256, /* low water mark */ 27327c478bd9Sstevel@tonic-gate }; 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate /* 27357c478bd9Sstevel@tonic-gate * Use zero water marks becuase the lower queues are used only for flow control. 27367c478bd9Sstevel@tonic-gate */ 27377c478bd9Sstevel@tonic-gate static struct module_info linfo = 27387c478bd9Sstevel@tonic-gate { 27397c478bd9Sstevel@tonic-gate SM_MOD_ID, 27407c478bd9Sstevel@tonic-gate TTYMUX_DRVNAME, 27417c478bd9Sstevel@tonic-gate 0, /* min packet size */ 27427c478bd9Sstevel@tonic-gate INFPSZ, /* max packet size */ 27437c478bd9Sstevel@tonic-gate 0, /* high water mark */ 27447c478bd9Sstevel@tonic-gate 0 /* low water mark */ 27457c478bd9Sstevel@tonic-gate }; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate /* 27497c478bd9Sstevel@tonic-gate * Solaris upper read STREAM initialisation structure. 27507c478bd9Sstevel@tonic-gate */ 27517c478bd9Sstevel@tonic-gate static struct qinit urinit = 27527c478bd9Sstevel@tonic-gate { 27537c478bd9Sstevel@tonic-gate sm_urput, /* put */ 27547c478bd9Sstevel@tonic-gate sm_ursrv, /* service */ 27557c478bd9Sstevel@tonic-gate sm_open, /* open */ 27567c478bd9Sstevel@tonic-gate sm_close, /* close */ 27577c478bd9Sstevel@tonic-gate NULL, /* admin */ 27587c478bd9Sstevel@tonic-gate &uinfo, /* module info */ 27597c478bd9Sstevel@tonic-gate NULL /* stats */ 27607c478bd9Sstevel@tonic-gate }; 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate /* 27637c478bd9Sstevel@tonic-gate * Solaris upper write STREAM initialisation structure. 27647c478bd9Sstevel@tonic-gate */ 27657c478bd9Sstevel@tonic-gate static struct qinit uwinit = 27667c478bd9Sstevel@tonic-gate { 27677c478bd9Sstevel@tonic-gate sm_uwput, 27687c478bd9Sstevel@tonic-gate sm_uwsrv, 27697c478bd9Sstevel@tonic-gate NULL, 27707c478bd9Sstevel@tonic-gate NULL, 27717c478bd9Sstevel@tonic-gate NULL, 27727c478bd9Sstevel@tonic-gate &uinfo, 27737c478bd9Sstevel@tonic-gate NULL 27747c478bd9Sstevel@tonic-gate }; 27757c478bd9Sstevel@tonic-gate 27767c478bd9Sstevel@tonic-gate /* 27777c478bd9Sstevel@tonic-gate * Solaris lower read STREAM initialisation structure. 27787c478bd9Sstevel@tonic-gate */ 27797c478bd9Sstevel@tonic-gate static struct qinit lrinit = 27807c478bd9Sstevel@tonic-gate { 27817c478bd9Sstevel@tonic-gate sm_lrput, 27827c478bd9Sstevel@tonic-gate sm_lrsrv, 27837c478bd9Sstevel@tonic-gate NULL, 27847c478bd9Sstevel@tonic-gate NULL, NULL, 27857c478bd9Sstevel@tonic-gate &linfo, 27867c478bd9Sstevel@tonic-gate NULL 27877c478bd9Sstevel@tonic-gate }; 27887c478bd9Sstevel@tonic-gate 27897c478bd9Sstevel@tonic-gate /* 27907c478bd9Sstevel@tonic-gate * Solaris lower write STREAM initialisation structure. 27917c478bd9Sstevel@tonic-gate */ 27927c478bd9Sstevel@tonic-gate static struct qinit lwinit = 27937c478bd9Sstevel@tonic-gate { 27947c478bd9Sstevel@tonic-gate putq, 27957c478bd9Sstevel@tonic-gate sm_lwsrv, 27967c478bd9Sstevel@tonic-gate NULL, 27977c478bd9Sstevel@tonic-gate NULL, 27987c478bd9Sstevel@tonic-gate NULL, 27997c478bd9Sstevel@tonic-gate &linfo, 28007c478bd9Sstevel@tonic-gate NULL 28017c478bd9Sstevel@tonic-gate }; 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate /* 28047c478bd9Sstevel@tonic-gate * Multiplexing STREAM structure. 28057c478bd9Sstevel@tonic-gate */ 28067c478bd9Sstevel@tonic-gate struct streamtab sm_streamtab = 28077c478bd9Sstevel@tonic-gate { 28087c478bd9Sstevel@tonic-gate &urinit, 28097c478bd9Sstevel@tonic-gate &uwinit, 28107c478bd9Sstevel@tonic-gate &lrinit, 28117c478bd9Sstevel@tonic-gate &lwinit 28127c478bd9Sstevel@tonic-gate }; 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate /* 28157c478bd9Sstevel@tonic-gate * Driver operations structure (struct cb_ops) and 28167c478bd9Sstevel@tonic-gate * driver dynamic loading functions (struct dev_ops). 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate /* 28207c478bd9Sstevel@tonic-gate * Fold the Stream interface to the kernel into the driver interface 28217c478bd9Sstevel@tonic-gate * to the OS. 28227c478bd9Sstevel@tonic-gate */ 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sm_ops, \ 28257c478bd9Sstevel@tonic-gate nulldev, nulldev, \ 28267c478bd9Sstevel@tonic-gate sm_attach, sm_detach, nodev, \ 28277c478bd9Sstevel@tonic-gate sm_info, (D_NEW | D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL | D_MP), 2828*19397407SSherry Moore &sm_streamtab, ddi_quiesce_not_supported); 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate /* 28317c478bd9Sstevel@tonic-gate * Driver module information. 28327c478bd9Sstevel@tonic-gate */ 28337c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 28347c478bd9Sstevel@tonic-gate static struct modldrv modldrv = 28357c478bd9Sstevel@tonic-gate { 28367c478bd9Sstevel@tonic-gate &mod_driverops, 2837*19397407SSherry Moore "serial mux driver", 28387c478bd9Sstevel@tonic-gate &sm_ops 28397c478bd9Sstevel@tonic-gate }; 28407c478bd9Sstevel@tonic-gate 28417c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = 28427c478bd9Sstevel@tonic-gate { 28437c478bd9Sstevel@tonic-gate MODREV_1, 28447c478bd9Sstevel@tonic-gate &modldrv, 28457c478bd9Sstevel@tonic-gate NULL 28467c478bd9Sstevel@tonic-gate }; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate /* 28497c478bd9Sstevel@tonic-gate * Define the body of our interface to the OS. 28507c478bd9Sstevel@tonic-gate */ 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate /* 28537c478bd9Sstevel@tonic-gate * '_init' is called by Solaris to initialise any driver 28547c478bd9Sstevel@tonic-gate * specific state and to install the driver. 28557c478bd9Sstevel@tonic-gate */ 28567c478bd9Sstevel@tonic-gate int 28577c478bd9Sstevel@tonic-gate _init(void) 28587c478bd9Sstevel@tonic-gate { 28597c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate /* 28637c478bd9Sstevel@tonic-gate * _info - return this drivers interface to the kernel. 28647c478bd9Sstevel@tonic-gate */ 28657c478bd9Sstevel@tonic-gate int 28667c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 28677c478bd9Sstevel@tonic-gate { 28687c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate /* 28727c478bd9Sstevel@tonic-gate * _fini - the OS is finished with the services provided by the driver. 28737c478bd9Sstevel@tonic-gate * remove ourself and then remove any footprint that remains. 28747c478bd9Sstevel@tonic-gate */ 28757c478bd9Sstevel@tonic-gate int 28767c478bd9Sstevel@tonic-gate _fini(void) 28777c478bd9Sstevel@tonic-gate { 28787c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 28797c478bd9Sstevel@tonic-gate } 2880