1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * DESCRIPTION 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * ttymux - Multiplexer driver for multiplexing termio compliant streams onto 33*0Sstevel@tonic-gate * a single upper stream. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * ADD2FRONT macro can be used to specify the order in which a console 36*0Sstevel@tonic-gate * device is put in the queue of multiplexed physical serial devices, 37*0Sstevel@tonic-gate * during the association and disassociation of a console interface. 38*0Sstevel@tonic-gate * When this macro is defined, the device is placed in front of the queue, 39*0Sstevel@tonic-gate * otherwise by default it is placed at the end. 40*0Sstevel@tonic-gate * Console I/O happens to each of the physical devices in the order of 41*0Sstevel@tonic-gate * their position in this queue. 42*0Sstevel@tonic-gate */ 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #include <sys/types.h> 45*0Sstevel@tonic-gate #include <sys/file.h> 46*0Sstevel@tonic-gate #include <sys/stream.h> 47*0Sstevel@tonic-gate #include <sys/strsubr.h> 48*0Sstevel@tonic-gate #include <sys/strlog.h> 49*0Sstevel@tonic-gate #include <sys/strsun.h> 50*0Sstevel@tonic-gate #include <sys/modctl.h> 51*0Sstevel@tonic-gate #include <sys/debug.h> 52*0Sstevel@tonic-gate #include <sys/kbio.h> 53*0Sstevel@tonic-gate #include <sys/devops.h> 54*0Sstevel@tonic-gate #include <sys/errno.h> 55*0Sstevel@tonic-gate #include <sys/stat.h> 56*0Sstevel@tonic-gate #include <sys/kmem.h> 57*0Sstevel@tonic-gate #include <sys/ddi.h> 58*0Sstevel@tonic-gate #include <sys/consdev.h> 59*0Sstevel@tonic-gate #include <sys/tty.h> 60*0Sstevel@tonic-gate #include <sys/ptyvar.h> 61*0Sstevel@tonic-gate #include <sys/termio.h> 62*0Sstevel@tonic-gate #include <sys/fcntl.h> 63*0Sstevel@tonic-gate #include <sys/mkdev.h> 64*0Sstevel@tonic-gate #include <sys/ser_sync.h> 65*0Sstevel@tonic-gate #include <sys/esunddi.h> 66*0Sstevel@tonic-gate #include <sys/policy.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #include <sys/ttymux.h> 69*0Sstevel@tonic-gate #include "ttymux_impl.h" 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * Extern declarations 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate extern mblk_t *mkiocb(uint_t); 75*0Sstevel@tonic-gate extern int nulldev(); 76*0Sstevel@tonic-gate extern uintptr_t space_fetch(char *key); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate extern int sm_ioctl_cmd(sm_uqi_t *, mblk_t *); 79*0Sstevel@tonic-gate extern int ttymux_abort_ioctl(mblk_t *); 80*0Sstevel@tonic-gate extern int ttymux_device_fini(sm_lqi_t *); 81*0Sstevel@tonic-gate extern int ttymux_device_init(sm_lqi_t *); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * Exported interfaces 85*0Sstevel@tonic-gate */ 86*0Sstevel@tonic-gate int sm_disassociate(int, sm_lqi_t *, ulong_t); 87*0Sstevel@tonic-gate int sm_associate(int, sm_lqi_t *, ulong_t, uint_t, char *); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * Variables defined here and visible only internally 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate sm_ss_t *sm_ssp = 0; 93*0Sstevel@tonic-gate static int sm_instance = 0; 94*0Sstevel@tonic-gate static int smctlunit; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate static uint_t sm_default_trflag = 0; 97*0Sstevel@tonic-gate uint_t sm_max_units = 6; 98*0Sstevel@tonic-gate uint_t sm_minor_cnt = 0; 99*0Sstevel@tonic-gate static uint_t sm_refuse_opens = 0; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * Local definitions. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* force these flags to be unset on console devices */ 106*0Sstevel@tonic-gate static ulong_t sm_cmask = (ulong_t)(CRTSXOFF|CRTSCTS); 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate /* 109*0Sstevel@tonic-gate * SECTION 110*0Sstevel@tonic-gate * Implementation Section: 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate void 113*0Sstevel@tonic-gate sm_debug(char *msg, ...) 114*0Sstevel@tonic-gate { 115*0Sstevel@tonic-gate va_list args; 116*0Sstevel@tonic-gate char buf[256]; 117*0Sstevel@tonic-gate int sz; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate va_start(args, msg); 120*0Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), msg, args); 121*0Sstevel@tonic-gate va_end(args); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate if (sz < 0) 124*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1, 125*0Sstevel@tonic-gate SL_TRACE, "vsnprintf parse error\n"); 126*0Sstevel@tonic-gate else if (sz > sizeof (buf)) { 127*0Sstevel@tonic-gate char *b; 128*0Sstevel@tonic-gate size_t len = sz + 1; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate b = kmem_alloc(len, KM_SLEEP); 131*0Sstevel@tonic-gate va_start(args, msg); 132*0Sstevel@tonic-gate sz = vsnprintf(b, len, msg, args); 133*0Sstevel@tonic-gate va_end(args); 134*0Sstevel@tonic-gate if (sz > 0) 135*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), 136*0Sstevel@tonic-gate sm_instance, 1, SL_TRACE, b); 137*0Sstevel@tonic-gate kmem_free(b, len); 138*0Sstevel@tonic-gate } else { 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 141*0Sstevel@tonic-gate 1, SL_TRACE, buf); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate void 146*0Sstevel@tonic-gate sm_log(char *msg, ...) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate va_list args; 149*0Sstevel@tonic-gate char buf[128]; 150*0Sstevel@tonic-gate int sz; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate va_start(args, msg); 153*0Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), msg, args); 154*0Sstevel@tonic-gate va_end(args); 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate if (sz < 0) 157*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 1, 158*0Sstevel@tonic-gate SL_TRACE, "vsnprintf parse error\n"); 159*0Sstevel@tonic-gate else if (sz > sizeof (buf)) { 160*0Sstevel@tonic-gate char *b; 161*0Sstevel@tonic-gate size_t len = sz + 1; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate b = kmem_alloc(len, KM_SLEEP); 164*0Sstevel@tonic-gate va_start(args, msg); 165*0Sstevel@tonic-gate sz = vsnprintf(b, len, msg, args); 166*0Sstevel@tonic-gate va_end(args); 167*0Sstevel@tonic-gate if (sz > 0) 168*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), 169*0Sstevel@tonic-gate sm_instance, 1, SL_NOTE, b); 170*0Sstevel@tonic-gate kmem_free(b, len); 171*0Sstevel@tonic-gate } else { 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate (void) strlog(ddi_driver_major(sm_ssp->sm_dip), sm_instance, 174*0Sstevel@tonic-gate 1, SL_NOTE, buf); 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Should only be called if the caller can guarantee that the vnode 180*0Sstevel@tonic-gate * and/or the stream won't disappear while finding the dip. 181*0Sstevel@tonic-gate * This routine is only called during an I_PLINK request so it's safe. 182*0Sstevel@tonic-gate * The routine obtains the dev_t for a linked se stream. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate static void 185*0Sstevel@tonic-gate sm_setdip(queue_t *q, sm_lqi_t *lqi) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate lqi->sm_dev = q && STREAM(q) ? STREAM(q)->sd_vnode->v_rdev : NODEV; 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate /* 191*0Sstevel@tonic-gate * Called from driver close, state change reports and I_PUNLINK ioctl. 192*0Sstevel@tonic-gate * A lower stream has been unlinked - clean up the state associated with it. 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate void 195*0Sstevel@tonic-gate sm_lqifree(sm_lqi_t *lqi) 196*0Sstevel@tonic-gate { 197*0Sstevel@tonic-gate int mu_owned; 198*0Sstevel@tonic-gate sm_lqi_t **pplqi; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate ASSERT(mutex_owned(lqi->sm_umutex)); 201*0Sstevel@tonic-gate ASSERT(SM_RQ(lqi) != 0); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* 204*0Sstevel@tonic-gate * Clear all state associated with this lower queue except 205*0Sstevel@tonic-gate * the identity of the queues themselves and the link id which 206*0Sstevel@tonic-gate * can only be cleared by issuing a streams I_PUNLINK ioctl. 207*0Sstevel@tonic-gate * 208*0Sstevel@tonic-gate * The association of a lower queue is a two step process: 209*0Sstevel@tonic-gate * 1. initialise the lower q data structure on I_PLINK 210*0Sstevel@tonic-gate * 2. associate an upper q with the lower q on SM_CMD_ASSOCIATE. 211*0Sstevel@tonic-gate * 212*0Sstevel@tonic-gate * If step 2 has ocurred then 213*0Sstevel@tonic-gate * remove this lower queue info from the logical unit. 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate if (lqi->sm_uqi) { 216*0Sstevel@tonic-gate sm_dbg('Y', ("lqifree unit %d, ", lqi->sm_uqi->sm_lunit)); 217*0Sstevel@tonic-gate if ((mu_owned = mutex_owned(lqi->sm_uqi->sm_umutex)) == 0) 218*0Sstevel@tonic-gate LOCK_UNIT(lqi->sm_uqi); 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate pplqi = &lqi->sm_uqi->sm_lqs; 221*0Sstevel@tonic-gate while (*pplqi != lqi) { 222*0Sstevel@tonic-gate ASSERT(*pplqi); 223*0Sstevel@tonic-gate pplqi = &((*pplqi)->sm_nlqi); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate *pplqi = lqi->sm_nlqi; 226*0Sstevel@tonic-gate lqi->sm_uqi->sm_nlqs--; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (mu_owned == 0) 229*0Sstevel@tonic-gate UNLOCK_UNIT(lqi->sm_uqi); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate lqi->sm_uqi = 0; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate * Given a q return the associated lower queue data structure or NULL. 237*0Sstevel@tonic-gate * Return the data locked. 238*0Sstevel@tonic-gate */ 239*0Sstevel@tonic-gate static sm_lqi_t * 240*0Sstevel@tonic-gate get_lqi_byq(queue_t *q) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate int i; 243*0Sstevel@tonic-gate sm_lqi_t *lqi, *flqi = 0; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 246*0Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 247*0Sstevel@tonic-gate LOCK_UNIT(lqi); 248*0Sstevel@tonic-gate if (flqi == 0 && lqi->sm_linkid == 0) /* assumes muxids != 0 */ 249*0Sstevel@tonic-gate flqi = lqi; 250*0Sstevel@tonic-gate else if (SM_RQ(lqi) == q || SM_WQ(lqi) == q) { 251*0Sstevel@tonic-gate if (flqi) 252*0Sstevel@tonic-gate UNLOCK_UNIT(flqi); 253*0Sstevel@tonic-gate return (lqi); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate else 256*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate return (flqi); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * Given a streams link identifier return the associated lower queue data 263*0Sstevel@tonic-gate * structure or NULL. 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate sm_lqi_t * 266*0Sstevel@tonic-gate get_lqi_byid(int linkid) 267*0Sstevel@tonic-gate { 268*0Sstevel@tonic-gate int i; 269*0Sstevel@tonic-gate sm_lqi_t *lqi; 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if (linkid == 0) 272*0Sstevel@tonic-gate return (NULL); 273*0Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 274*0Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 275*0Sstevel@tonic-gate if (lqi->sm_linkid == linkid) 276*0Sstevel@tonic-gate return (lqi); 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate return (NULL); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate /* 282*0Sstevel@tonic-gate * Given a dev_t for a lower stream return the associated lower queue data 283*0Sstevel@tonic-gate * structure or NULL. 284*0Sstevel@tonic-gate */ 285*0Sstevel@tonic-gate sm_lqi_t * 286*0Sstevel@tonic-gate get_lqi_bydevt(dev_t dev) 287*0Sstevel@tonic-gate { 288*0Sstevel@tonic-gate int i; 289*0Sstevel@tonic-gate sm_lqi_t *lqi; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (dev == NODEV) 292*0Sstevel@tonic-gate return (NULL); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate for (i = 0; i < MAX_LQS; i++) { 295*0Sstevel@tonic-gate lqi = &sm_ssp->sm_lqs[i]; 296*0Sstevel@tonic-gate if (lqi->sm_dev == dev) 297*0Sstevel@tonic-gate return (lqi); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate return (NULL); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* 303*0Sstevel@tonic-gate * Determine whether the input flag is set on at least 304*0Sstevel@tonic-gate * howmany queues. 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate static int 307*0Sstevel@tonic-gate sm_is_flag_set(sm_uqi_t *uqi, uint_t flag, uint_t howmany) 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate sm_lqi_t *lqi; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate if (howmany == 0) 312*0Sstevel@tonic-gate return (0); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 315*0Sstevel@tonic-gate if (lqi->sm_flags & flag) 316*0Sstevel@tonic-gate if (--howmany == 0) 317*0Sstevel@tonic-gate return (1); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate return (0); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* 323*0Sstevel@tonic-gate * How many usable queues are associated with a given upper stream 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate static int 326*0Sstevel@tonic-gate sm_uwq_error(sm_uqi_t *uqi) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate return (sm_is_flag_set(uqi, (WERROR_MODE|HANGUP_MODE), uqi->sm_nlqs)); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate /* 332*0Sstevel@tonic-gate * How many of the queues associated with a given upper stream 333*0Sstevel@tonic-gate * - do not - have the given flags set. 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate static int 336*0Sstevel@tonic-gate sm_q_count(sm_uqi_t *uqi, uint_t flag) 337*0Sstevel@tonic-gate { 338*0Sstevel@tonic-gate sm_lqi_t *lqi; 339*0Sstevel@tonic-gate int count = 0; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 342*0Sstevel@tonic-gate if ((lqi->sm_flags & flag) == 0) 343*0Sstevel@tonic-gate count++; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate return (count); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * How many of the queues associated with a given upper stream 350*0Sstevel@tonic-gate * - do not - have the given flags set. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate static int 353*0Sstevel@tonic-gate sm_qs_without(sm_uqi_t *uqi, uint_t flag, uint_t ioflag) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate sm_lqi_t *lqi; 356*0Sstevel@tonic-gate int count = 0; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi; lqi = lqi->sm_nlqi) { 359*0Sstevel@tonic-gate if ((lqi->sm_flags & flag) == 0 && 360*0Sstevel@tonic-gate (lqi->sm_ioflag & ioflag) == 0) 361*0Sstevel@tonic-gate count++; 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate return (count); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * How many usable queues are associated with a given upper stream 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate static int 370*0Sstevel@tonic-gate sm_good_qs(sm_uqi_t *uqi) 371*0Sstevel@tonic-gate { 372*0Sstevel@tonic-gate return (sm_q_count(uqi, (WERROR_MODE|HANGUP_MODE))); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate static int 376*0Sstevel@tonic-gate sm_cnt_oqs(sm_uqi_t *uqi) 377*0Sstevel@tonic-gate { 378*0Sstevel@tonic-gate return (sm_qs_without(uqi, (WERROR_MODE|HANGUP_MODE), 379*0Sstevel@tonic-gate (uint_t)FOROUTPUT)); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * Send an ioctl downstream and remember that it was sent so that 384*0Sstevel@tonic-gate * its response can be caught on the way back up. 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate static void 387*0Sstevel@tonic-gate sm_issue_ioctl(void *arg) 388*0Sstevel@tonic-gate { 389*0Sstevel@tonic-gate sm_lqi_t *lqi = arg; 390*0Sstevel@tonic-gate uint_t cmdflag = 0; 391*0Sstevel@tonic-gate queue_t *q = SM_WQ(lqi); 392*0Sstevel@tonic-gate int iocmd, size; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate LOCK_UNIT(lqi); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate lqi->sm_bid = 0; 397*0Sstevel@tonic-gate if ((lqi->sm_flags & (WERROR_MODE|HANGUP_MODE)) == 0 && 398*0Sstevel@tonic-gate (lqi->sm_flags & (WANT_CDSTAT|WANT_TCSET))) { 399*0Sstevel@tonic-gate mblk_t *pioc; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate if (lqi->sm_flags & WANT_TCSET) { 402*0Sstevel@tonic-gate lqi->sm_flags &= ~WANT_TCSET; 403*0Sstevel@tonic-gate iocmd = TCSETS; 404*0Sstevel@tonic-gate cmdflag = WANT_TCSET; 405*0Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_SC) { 406*0Sstevel@tonic-gate lqi->sm_flags &= ~WANT_SC; 407*0Sstevel@tonic-gate iocmd = TIOCGSOFTCAR; 408*0Sstevel@tonic-gate cmdflag = WANT_SC; 409*0Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_CD) { 410*0Sstevel@tonic-gate lqi->sm_flags &= ~WANT_CD; 411*0Sstevel@tonic-gate iocmd = TIOCMGET; 412*0Sstevel@tonic-gate } else if (lqi->sm_flags & WANT_CL) { 413*0Sstevel@tonic-gate lqi->sm_flags &= ~WANT_CL; 414*0Sstevel@tonic-gate iocmd = TCGETS; 415*0Sstevel@tonic-gate cmdflag = WANT_CL; 416*0Sstevel@tonic-gate } else { 417*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 418*0Sstevel@tonic-gate return; 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate if (pioc = mkiocb(iocmd)) { 422*0Sstevel@tonic-gate if (cmdflag == WANT_TCSET) { 423*0Sstevel@tonic-gate pioc->b_cont = 424*0Sstevel@tonic-gate sm_allocb(sizeof (struct termios), 425*0Sstevel@tonic-gate BPRI_MED); 426*0Sstevel@tonic-gate if (pioc->b_cont == 0) { 427*0Sstevel@tonic-gate freemsg(pioc); 428*0Sstevel@tonic-gate pioc = 0; 429*0Sstevel@tonic-gate } else { 430*0Sstevel@tonic-gate struct termios *tc = (struct termios *) 431*0Sstevel@tonic-gate pioc->b_cont->b_wptr; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate bzero((caddr_t)tc, 434*0Sstevel@tonic-gate sizeof (struct termios)); 435*0Sstevel@tonic-gate tc->c_cflag = lqi->sm_ttycommon-> 436*0Sstevel@tonic-gate t_cflag; 437*0Sstevel@tonic-gate pioc->b_cont->b_rptr = 438*0Sstevel@tonic-gate pioc->b_cont->b_wptr; 439*0Sstevel@tonic-gate pioc->b_cont->b_wptr += 440*0Sstevel@tonic-gate sizeof (struct termios); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate size = sizeof (struct iocblk) + 443*0Sstevel@tonic-gate sizeof (struct termios); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate else 446*0Sstevel@tonic-gate size = sizeof (struct iocblk); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate else 449*0Sstevel@tonic-gate size = sizeof (struct iocblk); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if (pioc != 0) { 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate lqi->sm_piocid = ((struct iocblk *)pioc->b_rptr)-> 454*0Sstevel@tonic-gate ioc_id; 455*0Sstevel@tonic-gate lqi->sm_flags |= SM_IOCPENDING; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate /* lqi->sm_flags |= cmdflag; */ 458*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 459*0Sstevel@tonic-gate (void) putq(q, pioc); 460*0Sstevel@tonic-gate } else { 461*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 462*0Sstevel@tonic-gate lqi->sm_bid = qbufcall(WR(q), size, BPRI_MED, 463*0Sstevel@tonic-gate sm_issue_ioctl, lqi); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate else 467*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * Associate one of the drivers minor nodes with a serial device. 472*0Sstevel@tonic-gate */ 473*0Sstevel@tonic-gate int 474*0Sstevel@tonic-gate sm_associate(int unit, sm_lqi_t *plqi, ulong_t tag, uint_t ioflag, char *dp) 475*0Sstevel@tonic-gate { 476*0Sstevel@tonic-gate sm_uqi_t *uqi; 477*0Sstevel@tonic-gate int rval = 0; 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate sm_dbg('Y', ("sm_associate(%d, %d, %d): ", 480*0Sstevel@tonic-gate (plqi) ? plqi->sm_linkid : 0, unit, ioflag)); 481*0Sstevel@tonic-gate /* 482*0Sstevel@tonic-gate * Check the data is valid. 483*0Sstevel@tonic-gate * Associate a lower queue with a logical unit. 484*0Sstevel@tonic-gate */ 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (unit < 0 || unit >= NLUNITS || plqi == 0 || 487*0Sstevel@tonic-gate (uqi = get_uqi(sm_ssp, unit)) == 0) { 488*0Sstevel@tonic-gate sm_dbg('@', (" invalid: lqi=0x%p lui=0x%p:", plqi, uqi)); 489*0Sstevel@tonic-gate rval = EINVAL; 490*0Sstevel@tonic-gate } else { 491*0Sstevel@tonic-gate if ((ioflag & FORIO) == 0) 492*0Sstevel@tonic-gate ioflag = FORIO; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate LOCK_UNIT(plqi); 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate if (plqi->sm_uqi) { 497*0Sstevel@tonic-gate if (plqi->sm_uqi->sm_lunit == unit) { 498*0Sstevel@tonic-gate if ((ioflag & (uint_t)FORIO) != 0) 499*0Sstevel@tonic-gate plqi->sm_ioflag = 500*0Sstevel@tonic-gate (ioflag & (uint_t)FORIO); 501*0Sstevel@tonic-gate rval = 0; 502*0Sstevel@tonic-gate } else { 503*0Sstevel@tonic-gate sm_dbg('@', ("already associated with unit %d:", 504*0Sstevel@tonic-gate plqi->sm_uqi->sm_lunit)); 505*0Sstevel@tonic-gate rval = EINVAL; 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate } else { 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate LOCK_UNIT(uqi); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate if ((ioflag & (uint_t)FORIO) != 0) 512*0Sstevel@tonic-gate plqi->sm_ioflag = (ioflag & (uint_t)FORIO); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = uqi->sm_ttycommon-> 515*0Sstevel@tonic-gate t_cflag; 516*0Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = uqi->sm_ttycommon-> 517*0Sstevel@tonic-gate t_flags; 518*0Sstevel@tonic-gate plqi->sm_uqi = uqi; 519*0Sstevel@tonic-gate plqi->sm_mbits = 0; 520*0Sstevel@tonic-gate plqi->sm_tag = tag; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (*dp == '/') 523*0Sstevel@tonic-gate (void) strncpy(plqi->sm_path, dp, MAXPATHLEN); 524*0Sstevel@tonic-gate else 525*0Sstevel@tonic-gate *(plqi->sm_path) = '\0'; 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate plqi->sm_flags |= WANT_TCSET; 528*0Sstevel@tonic-gate #ifdef ADD2FRONT 529*0Sstevel@tonic-gate plqi->sm_nlqi = uqi->sm_lqs; 530*0Sstevel@tonic-gate uqi->sm_lqs = plqi; 531*0Sstevel@tonic-gate #else 532*0Sstevel@tonic-gate plqi->sm_nlqi = 0; 533*0Sstevel@tonic-gate if (uqi->sm_lqs) { 534*0Sstevel@tonic-gate sm_lqi_t *lq; 535*0Sstevel@tonic-gate for (lq = uqi->sm_lqs; lq->sm_nlqi; 536*0Sstevel@tonic-gate lq = lq->sm_nlqi) { 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate lq->sm_nlqi = plqi; 539*0Sstevel@tonic-gate } else 540*0Sstevel@tonic-gate uqi->sm_lqs = plqi; 541*0Sstevel@tonic-gate #endif 542*0Sstevel@tonic-gate uqi->sm_nlqs++; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate (void) ttymux_device_init(plqi); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate UNLOCK_UNIT(uqi); 547*0Sstevel@tonic-gate rval = 0; 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * Everything looks good so it's now ok to enable lower 550*0Sstevel@tonic-gate * queue processing. 551*0Sstevel@tonic-gate * Note the lower queue should be enabled as soon as 552*0Sstevel@tonic-gate * I_PLINK returns (used in sm_get_ttymodes etc). 553*0Sstevel@tonic-gate * Schedule ioctls to obtain the terminal settings. 554*0Sstevel@tonic-gate */ 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_waitq) 557*0Sstevel@tonic-gate plqi->sm_uqflags |= SM_UQVALID; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate qenable(SM_RQ(plqi)); 560*0Sstevel@tonic-gate if (plqi->sm_flags & (WANT_CDSTAT|WANT_TCSET)) { 561*0Sstevel@tonic-gate /* 562*0Sstevel@tonic-gate * Bypass the lower half of the driver (hence 563*0Sstevel@tonic-gate * no qwriter) and apply the current termio 564*0Sstevel@tonic-gate * settings on the lower stream. 565*0Sstevel@tonic-gate */ 566*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); 567*0Sstevel@tonic-gate if (plqi->sm_bid) { 568*0Sstevel@tonic-gate qunbufcall(SM_WQ(plqi), plqi->sm_bid); 569*0Sstevel@tonic-gate plqi->sm_bid = 0; 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * Only set cflags on the lower q if we know 573*0Sstevel@tonic-gate * the settings on any other lower queue. 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate sm_issue_ioctl(plqi); 576*0Sstevel@tonic-gate LOCK_UNIT(plqi); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate sm_dbg('Y', ("sm_associate: rval=%d.\n", rval)); 584*0Sstevel@tonic-gate return (rval); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* 588*0Sstevel@tonic-gate * Break an association between one of the driver's minor nodes and 589*0Sstevel@tonic-gate * a serial device. 590*0Sstevel@tonic-gate */ 591*0Sstevel@tonic-gate int 592*0Sstevel@tonic-gate sm_disassociate(int unit, sm_lqi_t *plqi, ulong_t tag) 593*0Sstevel@tonic-gate { 594*0Sstevel@tonic-gate sm_uqi_t *uqi; 595*0Sstevel@tonic-gate int rval = 0; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate sm_dbg('Y', ("sm_disassociate: link %d, unit %d: ", 598*0Sstevel@tonic-gate (plqi) ? plqi->sm_linkid : 0, unit)); 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Check the data is valid. 601*0Sstevel@tonic-gate * Disassociate a lower queue with a logical unit. 602*0Sstevel@tonic-gate */ 603*0Sstevel@tonic-gate if (unit < 0 || unit >= NLUNITS || plqi == 0 || 604*0Sstevel@tonic-gate (uqi = get_uqi(sm_ssp, unit)) == 0) { 605*0Sstevel@tonic-gate sm_dbg('@', ("invalid: lqi=0x%p lui=0x%p", plqi, uqi)); 606*0Sstevel@tonic-gate rval = EINVAL; 607*0Sstevel@tonic-gate } else { 608*0Sstevel@tonic-gate LOCK_UNIT(plqi); 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate if (plqi->sm_uqi == NULL) { 611*0Sstevel@tonic-gate sm_dbg('@', ("unit not associated")); 612*0Sstevel@tonic-gate rval = EINVAL; 613*0Sstevel@tonic-gate } else if (plqi->sm_uqi->sm_lunit != unit) { 614*0Sstevel@tonic-gate sm_dbg('@', ("unit and linkid not related", 615*0Sstevel@tonic-gate plqi->sm_uqi->sm_lunit)); 616*0Sstevel@tonic-gate rval = EINVAL; 617*0Sstevel@tonic-gate } else if (plqi->sm_tag != tag) { 618*0Sstevel@tonic-gate sm_dbg('@', 619*0Sstevel@tonic-gate ("Invalid tag for TTYMUX_DISASSOC ioctl\n")); 620*0Sstevel@tonic-gate rval = EPERM; 621*0Sstevel@tonic-gate } else { 622*0Sstevel@tonic-gate sm_dbg('Y', ("disassociating ")); 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate (void) ttymux_device_fini(plqi); 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate /* 627*0Sstevel@tonic-gate * Indicate that carrier status is no 628*0Sstevel@tonic-gate * longer required and that the upper 629*0Sstevel@tonic-gate * queue should not be used by plqi 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate plqi->sm_flags &= ~(WANT_CDSTAT|WANT_TCSET); 632*0Sstevel@tonic-gate plqi->sm_uqflags &= ~(SM_UQVALID|SM_OBPCNDEV); 633*0Sstevel@tonic-gate plqi->sm_ioflag = 0u; 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate sm_lqifree(plqi); 636*0Sstevel@tonic-gate rval = 0; 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); 639*0Sstevel@tonic-gate } 640*0Sstevel@tonic-gate sm_dbg('Y', (" rval=%d.\n", rval)); 641*0Sstevel@tonic-gate return (rval); 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * Streams helper routines; 647*0Sstevel@tonic-gate */ 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * Schedule a qbufcall for an upper queue. 651*0Sstevel@tonic-gate * Must be called within the perimiter of the parameter q. 652*0Sstevel@tonic-gate * fn must reenable the q. 653*0Sstevel@tonic-gate * Called: 654*0Sstevel@tonic-gate * whenever a message must be placed on multiple queues and allocb fails; 655*0Sstevel@tonic-gate */ 656*0Sstevel@tonic-gate static void 657*0Sstevel@tonic-gate sm_sched_uqcb(queue_t *q, int memreq, int pri, void (*fn)()) 658*0Sstevel@tonic-gate { 659*0Sstevel@tonic-gate sm_uqi_t *uqi = q->q_ptr; 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate if (uqi->sm_ttybid != 0) 662*0Sstevel@tonic-gate qunbufcall(q, uqi->sm_ttybid); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate noenable(q); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate uqi->sm_ttybid = qbufcall(q, memreq, pri, fn, uqi); 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate /* 670*0Sstevel@tonic-gate * qbufcall routine to restart the queues when memory is available. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate static void 673*0Sstevel@tonic-gate sm_reenable_q(sm_uqi_t *uqi) 674*0Sstevel@tonic-gate { 675*0Sstevel@tonic-gate queue_t *wq = SM_WQ(uqi); 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate if ((uqi->sm_flags & SM_STOPPED) == 0) { 678*0Sstevel@tonic-gate enableok(wq); 679*0Sstevel@tonic-gate qenable(wq); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Place a message on the write queue of each stream associated with 685*0Sstevel@tonic-gate * the given upper stream. 686*0Sstevel@tonic-gate */ 687*0Sstevel@tonic-gate static void 688*0Sstevel@tonic-gate sm_senddown(sm_uqi_t *uqi) 689*0Sstevel@tonic-gate { 690*0Sstevel@tonic-gate sm_lqi_t *lqi; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 693*0Sstevel@tonic-gate if (lqi->sm_mp != 0) { 694*0Sstevel@tonic-gate putnext(SM_WQ(lqi), lqi->sm_mp); 695*0Sstevel@tonic-gate lqi->sm_mp = 0; 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate /* 701*0Sstevel@tonic-gate * For each lower device that should receive a write message duplicate 702*0Sstevel@tonic-gate * the message block. 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate static int 705*0Sstevel@tonic-gate sm_dupmsg(sm_uqi_t *uqi, mblk_t *mp) 706*0Sstevel@tonic-gate { 707*0Sstevel@tonic-gate sm_lqi_t *lqi; 708*0Sstevel@tonic-gate mblk_t *origmp = mp; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 711*0Sstevel@tonic-gate lqi->sm_mp = 0; 712*0Sstevel@tonic-gate if (lqi->sm_flags & WERROR_MODE) { 713*0Sstevel@tonic-gate continue; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate if ((lqi->sm_ioflag & (uint_t)FOROUTPUT) == 0) { 716*0Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) 717*0Sstevel@tonic-gate continue; 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate if (lqi->sm_nlqi == 0) { 720*0Sstevel@tonic-gate lqi->sm_mp = mp; 721*0Sstevel@tonic-gate origmp = NULL; 722*0Sstevel@tonic-gate } else if ((lqi->sm_mp = sm_copymsg(mp)) == 0) { 723*0Sstevel@tonic-gate sm_lqi_t *flqi; 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate for (flqi = uqi->sm_lqs; flqi != lqi; 726*0Sstevel@tonic-gate flqi = flqi->sm_nlqi) { 727*0Sstevel@tonic-gate if (lqi->sm_mp) { 728*0Sstevel@tonic-gate /* must have been sm_copymsg */ 729*0Sstevel@tonic-gate sm_freemsg(lqi->sm_mp); 730*0Sstevel@tonic-gate lqi->sm_mp = 0; 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate return (sm_cnt_oqs(uqi) * msgdsize(mp)); 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate if (origmp != NULL) 737*0Sstevel@tonic-gate freemsg(origmp); 738*0Sstevel@tonic-gate return (0); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate /* 742*0Sstevel@tonic-gate * Return 1 if all associated lower devices have room for another message 743*0Sstevel@tonic-gate * otherwise return 0. 744*0Sstevel@tonic-gate */ 745*0Sstevel@tonic-gate static int 746*0Sstevel@tonic-gate sm_cansenddown(sm_uqi_t *uqi) 747*0Sstevel@tonic-gate { 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate register sm_lqi_t *lqi; 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate if (uqi->sm_lqs == 0) 752*0Sstevel@tonic-gate return (0); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 755*0Sstevel@tonic-gate if ((lqi->sm_flags & WERROR_MODE) == 0 && 756*0Sstevel@tonic-gate canputnext(SM_WQ(lqi)) == 0) 757*0Sstevel@tonic-gate return (0); 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate return (1); 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate /* 763*0Sstevel@tonic-gate * Put a message down all associated lower queues. 764*0Sstevel@tonic-gate * Return 1 if the q function was called. 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate static int 767*0Sstevel@tonic-gate sm_putqs(queue_t *q, mblk_t *mp, int (*qfn)()) 768*0Sstevel@tonic-gate { 769*0Sstevel@tonic-gate register sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 770*0Sstevel@tonic-gate register int memreq; 771*0Sstevel@tonic-gate int pri = (DB_TYPE(mp) < QPCTL) ? BPRI_MED : BPRI_HI; 772*0Sstevel@tonic-gate int rval = 0; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate if (uqi->sm_lqs == 0 || (uqi->sm_flags & WERROR_MODE)) { 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate sm_dbg('Q', ("sm_putqs: freeing (0x%p 0x%p).\n", uqi->sm_lqs, 777*0Sstevel@tonic-gate uqi->sm_flags)); 778*0Sstevel@tonic-gate freemsg(mp); 779*0Sstevel@tonic-gate } else if (pri != BPRI_HI && sm_cansenddown(uqi) == 0) { 780*0Sstevel@tonic-gate /* a lower q is flow controlled */ 781*0Sstevel@tonic-gate (void) qfn(q, mp); 782*0Sstevel@tonic-gate rval = 1; 783*0Sstevel@tonic-gate } else if ((memreq = sm_dupmsg(uqi, mp)) == 0) { 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate sm_senddown(uqi); 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate } else { 788*0Sstevel@tonic-gate sm_log("sm_putqs: msg 0x%x - can't alloc %d bytes (pri %d).\n", 789*0Sstevel@tonic-gate DB_TYPE(mp), memreq, pri); 790*0Sstevel@tonic-gate sm_sched_uqcb(q, memreq, pri, sm_reenable_q); 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate (void) qfn(q, mp); 793*0Sstevel@tonic-gate rval = 1; 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate } 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate return (rval); 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate /* 801*0Sstevel@tonic-gate * sm_reply - send an ioctl reply back up the queue. 802*0Sstevel@tonic-gate */ 803*0Sstevel@tonic-gate static void 804*0Sstevel@tonic-gate sm_reply(queue_t *q, mblk_t *mp, uchar_t type, int error) 805*0Sstevel@tonic-gate { 806*0Sstevel@tonic-gate struct iocblk *iocbp; 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate iocbp = (struct iocblk *)mp->b_rptr; 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate DB_TYPE(mp) = type; 811*0Sstevel@tonic-gate iocbp->ioc_count = 0; 812*0Sstevel@tonic-gate iocbp->ioc_error = error; 813*0Sstevel@tonic-gate qreply(q, mp); 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * Service a streams link and unlink requests. 818*0Sstevel@tonic-gate */ 819*0Sstevel@tonic-gate static void 820*0Sstevel@tonic-gate sm_link_req(queue_t *wq, mblk_t *mp) 821*0Sstevel@tonic-gate { 822*0Sstevel@tonic-gate struct linkblk *linkp; 823*0Sstevel@tonic-gate int rval; 824*0Sstevel@tonic-gate int cmd; 825*0Sstevel@tonic-gate sm_lqi_t *plqi; 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_IOCTL); 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 830*0Sstevel@tonic-gate switch (cmd) { 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate case I_LINK: 833*0Sstevel@tonic-gate case I_PLINK: 834*0Sstevel@tonic-gate sm_dbg('G', ("sm_link_req: M_IOCTL %x (I_PLINK).\n", cmd)); 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate /* 839*0Sstevel@tonic-gate * 1. Sanity check the link block. 840*0Sstevel@tonic-gate * 2. Validate that the queue is not already linked 841*0Sstevel@tonic-gate * (and resources available). 842*0Sstevel@tonic-gate * 3. Validate that the lower queue is not associated with 843*0Sstevel@tonic-gate * a logical unit. 844*0Sstevel@tonic-gate * 4. Remember that this lower queue is linked to the driver. 845*0Sstevel@tonic-gate */ 846*0Sstevel@tonic-gate if ((linkp == NULL) || (MBLKL(mp) < sizeof (*linkp)) || 847*0Sstevel@tonic-gate linkp->l_qbot == NULL) { 848*0Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: invalid link block.\n")); 849*0Sstevel@tonic-gate rval = EINVAL; 850*0Sstevel@tonic-gate } else if ((plqi = get_lqi_byq(linkp->l_qbot)) == 0) { 851*0Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: out of resources.\n")); 852*0Sstevel@tonic-gate rval = EBUSY; /* out of resources */ 853*0Sstevel@tonic-gate } else if (plqi->sm_uqi) { 854*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */ 855*0Sstevel@tonic-gate sm_dbg('I', ("sm_link_req: already associated.\n")); 856*0Sstevel@tonic-gate rval = EBUSY; /* already linked */ 857*0Sstevel@tonic-gate } else { 858*0Sstevel@tonic-gate SM_WQ(plqi) = linkp->l_qbot; 859*0Sstevel@tonic-gate SM_RQ(plqi) = OTHERQ(linkp->l_qbot); 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate linkp->l_qbot->q_ptr = 862*0Sstevel@tonic-gate OTHERQ(linkp->l_qbot)->q_ptr = plqi; 863*0Sstevel@tonic-gate plqi->sm_linkid = linkp->l_index; 864*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); /* was aquired by get_lqi_byq */ 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate sm_dbg('H', ("sm_link_req: linkid = %d.\n", 867*0Sstevel@tonic-gate linkp->l_index)); 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate sm_setdip(linkp->l_qbot, plqi); 870*0Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = 0; 871*0Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = 0; 872*0Sstevel@tonic-gate plqi->sm_mbits = 0; 873*0Sstevel@tonic-gate (void) ttymux_device_init(plqi); 874*0Sstevel@tonic-gate rval = 0; 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate break; 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate case I_UNLINK: 880*0Sstevel@tonic-gate case I_PUNLINK: 881*0Sstevel@tonic-gate sm_dbg('G', ("sm_link_req: M_IOCTL (I_PUNLINK).\n")); 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate linkp = (struct linkblk *)mp->b_cont->b_rptr; 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate if ((linkp == NULL) || 886*0Sstevel@tonic-gate (MBLKL(mp) < sizeof (*linkp)) || 887*0Sstevel@tonic-gate linkp->l_qbot == NULL) { 888*0Sstevel@tonic-gate rval = EINVAL; 889*0Sstevel@tonic-gate } else if ((plqi = get_lqi_byid(linkp->l_index)) == 0) { 890*0Sstevel@tonic-gate rval = EINVAL; 891*0Sstevel@tonic-gate } else { 892*0Sstevel@tonic-gate sm_uqi_t *uqi; 893*0Sstevel@tonic-gate int werrmode; 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate /* 896*0Sstevel@tonic-gate * Mark the lower q as invalid. 897*0Sstevel@tonic-gate */ 898*0Sstevel@tonic-gate sm_dbg('G', ("I_PUNLINK: freeing link %d\n", 899*0Sstevel@tonic-gate linkp->l_index)); 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate if (plqi->sm_bid) { 902*0Sstevel@tonic-gate qunbufcall(SM_RQ(plqi), plqi->sm_bid); 903*0Sstevel@tonic-gate plqi->sm_bid = 0; 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate if (plqi->sm_ttybid) { 906*0Sstevel@tonic-gate qunbufcall(SM_RQ(plqi), plqi->sm_ttybid); 907*0Sstevel@tonic-gate plqi->sm_ttybid = 0; 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate uqi = plqi->sm_uqi; 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate (void) ttymux_device_fini(plqi); 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate if (uqi) 916*0Sstevel@tonic-gate (void) sm_disassociate(uqi->sm_lunit, 917*0Sstevel@tonic-gate plqi, plqi->sm_tag); 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate LOCK_UNIT(plqi); 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate plqi->sm_piocid = 0; 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate werrmode = (plqi->sm_flags & (WERROR_MODE|HANGUP_MODE)) 924*0Sstevel@tonic-gate ? 1 : 0; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate plqi->sm_mbits = 0; 927*0Sstevel@tonic-gate plqi->sm_flags = 0; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate ttycommon_close(plqi->sm_ttycommon); 930*0Sstevel@tonic-gate /* SM_RQ(plqi) = SM_WQ(plqi) = 0; */ 931*0Sstevel@tonic-gate plqi->sm_ttycommon->t_flags = 0; 932*0Sstevel@tonic-gate plqi->sm_ttycommon->t_cflag = 0; 933*0Sstevel@tonic-gate plqi->sm_ttycommon->t_iflag = 0; 934*0Sstevel@tonic-gate plqi->sm_linkid = 0; 935*0Sstevel@tonic-gate plqi->sm_dev = NODEV; 936*0Sstevel@tonic-gate plqi->sm_hadkadbchar = 0; 937*0Sstevel@tonic-gate plqi->sm_nachar = sm_ssp->sm_abs; 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate UNLOCK_UNIT(plqi); 940*0Sstevel@tonic-gate if (uqi && 941*0Sstevel@tonic-gate werrmode && 942*0Sstevel@tonic-gate (uqi->sm_flags & FULLY_OPEN) && 943*0Sstevel@tonic-gate sm_uwq_error(uqi) && 944*0Sstevel@tonic-gate putnextctl(SM_RQ(uqi), M_HANGUP) == 0) { 945*0Sstevel@tonic-gate sm_log("sm_link_req: putnextctl(M_HANGUP)" 946*0Sstevel@tonic-gate " failed.\n"); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate rval = 0; 950*0Sstevel@tonic-gate } 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate break; 953*0Sstevel@tonic-gate default: 954*0Sstevel@tonic-gate rval = EINVAL; 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate sm_reply(wq, mp, (rval) ? M_IOCNAK : M_IOCACK, rval); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate static int 960*0Sstevel@tonic-gate sm_getiocinfo(mblk_t *mp, struct sm_iocinfo *info) 961*0Sstevel@tonic-gate { 962*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 963*0Sstevel@tonic-gate case M_COPYOUT: 964*0Sstevel@tonic-gate info->sm_id = ((struct copyreq *)mp->b_rptr)->cq_id; 965*0Sstevel@tonic-gate info->sm_cmd = ((struct copyreq *)mp->b_rptr)->cq_cmd; 966*0Sstevel@tonic-gate info->sm_data = (((struct copyreq *)mp->b_rptr)->cq_size && 967*0Sstevel@tonic-gate mp->b_cont) ? (void *)mp->b_cont->b_rptr : 0; 968*0Sstevel@tonic-gate break; 969*0Sstevel@tonic-gate case M_COPYIN: 970*0Sstevel@tonic-gate info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id; 971*0Sstevel@tonic-gate info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd; 972*0Sstevel@tonic-gate info->sm_data = 0; 973*0Sstevel@tonic-gate break; 974*0Sstevel@tonic-gate case M_IOCACK: 975*0Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 976*0Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 977*0Sstevel@tonic-gate /* the se driver has bug so we cannot use ioc_count */ 978*0Sstevel@tonic-gate info->sm_data = (((struct iocblk *)mp->b_rptr)-> 979*0Sstevel@tonic-gate ioc_error == 0 && mp->b_cont) ? 980*0Sstevel@tonic-gate (void *)mp->b_cont->b_rptr : 0; 981*0Sstevel@tonic-gate break; 982*0Sstevel@tonic-gate case M_IOCNAK: 983*0Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 984*0Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 985*0Sstevel@tonic-gate info->sm_data = 0; 986*0Sstevel@tonic-gate break; 987*0Sstevel@tonic-gate case M_IOCDATA: 988*0Sstevel@tonic-gate info->sm_id = ((struct copyresp *)mp->b_rptr)->cp_id; 989*0Sstevel@tonic-gate info->sm_cmd = ((struct copyresp *)mp->b_rptr)->cp_cmd; 990*0Sstevel@tonic-gate info->sm_data = (((struct copyresp *)mp->b_rptr)-> 991*0Sstevel@tonic-gate cp_rval == 0 && mp->b_cont) ? 992*0Sstevel@tonic-gate (void *)mp->b_cont->b_rptr : 0; 993*0Sstevel@tonic-gate break; 994*0Sstevel@tonic-gate case M_IOCTL: 995*0Sstevel@tonic-gate info->sm_id = ((struct iocblk *)mp->b_rptr)->ioc_id; 996*0Sstevel@tonic-gate info->sm_cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 997*0Sstevel@tonic-gate info->sm_data = 0; 998*0Sstevel@tonic-gate break; 999*0Sstevel@tonic-gate default: 1000*0Sstevel@tonic-gate return (EINVAL); 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate return (0); 1003*0Sstevel@tonic-gate } 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate /* 1006*0Sstevel@tonic-gate * Record the termio settings that have been set on the upper stream 1007*0Sstevel@tonic-gate */ 1008*0Sstevel@tonic-gate static int 1009*0Sstevel@tonic-gate sm_update_ttyinfo(mblk_t *mp, sm_uqi_t *uqi) 1010*0Sstevel@tonic-gate { 1011*0Sstevel@tonic-gate int err; 1012*0Sstevel@tonic-gate struct sm_iocinfo info; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate if ((err = sm_getiocinfo(mp, &info)) != 0) 1015*0Sstevel@tonic-gate return (err); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate switch (info.sm_cmd) { 1018*0Sstevel@tonic-gate case TIOCSPPS: 1019*0Sstevel@tonic-gate case TIOCGPPS: 1020*0Sstevel@tonic-gate case TIOCGPPSEV: 1021*0Sstevel@tonic-gate return (ENOTSUP); 1022*0Sstevel@tonic-gate case TIOCGWINSZ: 1023*0Sstevel@tonic-gate case TIOCSWINSZ: 1024*0Sstevel@tonic-gate break; 1025*0Sstevel@tonic-gate case TCSBRK: 1026*0Sstevel@tonic-gate case TIOCSBRK: 1027*0Sstevel@tonic-gate case TIOCCBRK: 1028*0Sstevel@tonic-gate break; 1029*0Sstevel@tonic-gate case TCSETSF: 1030*0Sstevel@tonic-gate uqi->sm_flags |= FLUSHR_PEND; 1031*0Sstevel@tonic-gate sm_dbg('I', ("TCSETSF: FLUSH is pending\n")); 1032*0Sstevel@tonic-gate /*FALLTHROUGH*/ 1033*0Sstevel@tonic-gate case TCSETSW: 1034*0Sstevel@tonic-gate case TCSETS: 1035*0Sstevel@tonic-gate case TCGETS: 1036*0Sstevel@tonic-gate if (info.sm_data != 0) { 1037*0Sstevel@tonic-gate ((struct termios *)info.sm_data)->c_cflag &= 1038*0Sstevel@tonic-gate (tcflag_t)(~uqi->sm_cmask); 1039*0Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 1040*0Sstevel@tonic-gate ((struct termios *)info.sm_data)->c_cflag; 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate break; 1043*0Sstevel@tonic-gate case TCSETAF: 1044*0Sstevel@tonic-gate sm_dbg('I', ("TCSETAF: FLUSH is pending\n")); 1045*0Sstevel@tonic-gate uqi->sm_flags |= FLUSHR_PEND; 1046*0Sstevel@tonic-gate /*FALLTHROUGH*/ 1047*0Sstevel@tonic-gate case TCSETAW: 1048*0Sstevel@tonic-gate case TCSETA: 1049*0Sstevel@tonic-gate case TCGETA: 1050*0Sstevel@tonic-gate if (info.sm_data != 0) { 1051*0Sstevel@tonic-gate ((struct termio *)info.sm_data)->c_cflag &= 1052*0Sstevel@tonic-gate (tcflag_t)(~uqi->sm_cmask); 1053*0Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 1054*0Sstevel@tonic-gate (tcflag_t)((struct termio *)info.sm_data)->c_cflag; 1055*0Sstevel@tonic-gate } 1056*0Sstevel@tonic-gate break; 1057*0Sstevel@tonic-gate case TIOCSSOFTCAR: 1058*0Sstevel@tonic-gate case TIOCGSOFTCAR: 1059*0Sstevel@tonic-gate if (info.sm_data != 0) { 1060*0Sstevel@tonic-gate if (*(int *)info.sm_data == 1) 1061*0Sstevel@tonic-gate uqi->sm_ttycommon->t_flags |= TS_SOFTCAR; 1062*0Sstevel@tonic-gate else 1063*0Sstevel@tonic-gate uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR; 1064*0Sstevel@tonic-gate } 1065*0Sstevel@tonic-gate break; 1066*0Sstevel@tonic-gate case TIOCMSET: 1067*0Sstevel@tonic-gate case TIOCMGET: 1068*0Sstevel@tonic-gate if (info.sm_data != 0) 1069*0Sstevel@tonic-gate uqi->sm_mbits = *(int *)info.sm_data; 1070*0Sstevel@tonic-gate break; 1071*0Sstevel@tonic-gate case TIOCMBIS: 1072*0Sstevel@tonic-gate if (info.sm_data != 0) 1073*0Sstevel@tonic-gate uqi->sm_mbits |= *(int *)info.sm_data; 1074*0Sstevel@tonic-gate break; 1075*0Sstevel@tonic-gate case TIOCMBIC: 1076*0Sstevel@tonic-gate if (info.sm_data != 0) 1077*0Sstevel@tonic-gate uqi->sm_mbits &= ~(*(int *)info.sm_data); 1078*0Sstevel@tonic-gate break; 1079*0Sstevel@tonic-gate default: 1080*0Sstevel@tonic-gate return (EINVAL); 1081*0Sstevel@tonic-gate /* NOTREACHED */ 1082*0Sstevel@tonic-gate } /* end switch cmd */ 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate if ((uqi->sm_mbits & TIOCM_CD) || 1085*0Sstevel@tonic-gate (uqi->sm_ttycommon->t_flags & TS_SOFTCAR) || 1086*0Sstevel@tonic-gate (uqi->sm_ttycommon->t_cflag & CLOCAL)) 1087*0Sstevel@tonic-gate uqi->sm_flags |= SM_CARON; 1088*0Sstevel@tonic-gate else 1089*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate return (0); 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate /* 1095*0Sstevel@tonic-gate * SECTION 1096*0Sstevel@tonic-gate * STREAM's interface to the OS. 1097*0Sstevel@tonic-gate * Routines directly callable from the OS. 1098*0Sstevel@tonic-gate */ 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate /* 1101*0Sstevel@tonic-gate * Processes high priority messages comming from modules above the 1102*0Sstevel@tonic-gate * multiplexor. 1103*0Sstevel@tonic-gate * Return 1 if the queue was disabled. 1104*0Sstevel@tonic-gate */ 1105*0Sstevel@tonic-gate static int 1106*0Sstevel@tonic-gate sm_hp_uwput(queue_t *wq, mblk_t *mp) 1107*0Sstevel@tonic-gate { 1108*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)(wq->q_ptr); 1109*0Sstevel@tonic-gate int rval = 0; 1110*0Sstevel@tonic-gate sm_lqi_t *plqi; 1111*0Sstevel@tonic-gate int msgtype = DB_TYPE(mp); 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gate switch (msgtype) { 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate case M_FLUSH: 1116*0Sstevel@tonic-gate /* 1117*0Sstevel@tonic-gate * How to flush the bottom half: 1118*0Sstevel@tonic-gate * putctl1(SM_WQ(plqi), *mp->b_rptr) 1119*0Sstevel@tonic-gate * will work on the bottom half but if FLUSHR is set 1120*0Sstevel@tonic-gate * when is the right time to flush the upper read queue. 1121*0Sstevel@tonic-gate * 1122*0Sstevel@tonic-gate * Could set uqi->sm_flags & WANT_FLUSH but then what happens 1123*0Sstevel@tonic-gate * if FLUSHR is set and the driver sends up a FLUSHR 1124*0Sstevel@tonic-gate * before it handles the current FLUSHR request 1125*0Sstevel@tonic-gate * (if only there was an id for the message that could 1126*0Sstevel@tonic-gate * be matched when it returns back from the drivers. 1127*0Sstevel@tonic-gate * 1128*0Sstevel@tonic-gate * Thus I'm going by the book - the bottom half acts like 1129*0Sstevel@tonic-gate * a stream head and turns around FLUSHW back down to 1130*0Sstevel@tonic-gate * the driver (see lrput). The upper half acts like a 1131*0Sstevel@tonic-gate * driver and turns around FLUSHR: 1132*0Sstevel@tonic-gate */ 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate sm_dbg('I', ("sm_hp_uwput: FLUSH request 0x%x\n", *mp->b_rptr)); 1135*0Sstevel@tonic-gate /* flush the upper write queue */ 1136*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 1137*0Sstevel@tonic-gate flushq(wq, FLUSHDATA); 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate /* 1140*0Sstevel@tonic-gate * flush each associated lower write queue 1141*0Sstevel@tonic-gate * and pass down the driver (ignore the FLUSHR and deal with 1142*0Sstevel@tonic-gate * it when it comes back up the read side. 1143*0Sstevel@tonic-gate */ 1144*0Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 1145*0Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0 && 1146*0Sstevel@tonic-gate SM_WQ(plqi)) { 1147*0Sstevel@tonic-gate sm_dbg('I', ("flush lq 0x%p\n", SM_WQ(plqi))); 1148*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) 1149*0Sstevel@tonic-gate flushq(SM_WQ(plqi), FLUSHDATA); 1150*0Sstevel@tonic-gate (void) putnextctl1(SM_WQ(plqi), M_FLUSH, 1151*0Sstevel@tonic-gate *mp->b_rptr); 1152*0Sstevel@tonic-gate } 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate break; 1155*0Sstevel@tonic-gate 1156*0Sstevel@tonic-gate case M_STARTI: 1157*0Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 1158*0Sstevel@tonic-gate plqi->sm_flags &= ~SM_ISTOPPED; 1159*0Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 1160*0Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate break; 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate case M_STOPI: 1165*0Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) { 1166*0Sstevel@tonic-gate plqi->sm_flags |= SM_ISTOPPED; 1167*0Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 1168*0Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate break; 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate case M_STOP: /* must never be queued */ 1173*0Sstevel@tonic-gate uqi->sm_flags |= SM_STOPPED; 1174*0Sstevel@tonic-gate noenable(wq); 1175*0Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) 1176*0Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 1177*0Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate rval = 1; 1180*0Sstevel@tonic-gate break; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate case M_START: /* never be queued */ 1183*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_STOPPED; 1184*0Sstevel@tonic-gate enableok(wq); 1185*0Sstevel@tonic-gate qenable(wq); 1186*0Sstevel@tonic-gate for (plqi = uqi->sm_lqs; plqi != 0; plqi = plqi->sm_nlqi) 1187*0Sstevel@tonic-gate if ((plqi->sm_flags & WERROR_MODE) == 0) 1188*0Sstevel@tonic-gate (void) putnextctl(SM_WQ(plqi), msgtype); 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate break; 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate case M_PCSIG: 1193*0Sstevel@tonic-gate case M_COPYOUT: 1194*0Sstevel@tonic-gate case M_COPYIN: 1195*0Sstevel@tonic-gate case M_IOCACK: 1196*0Sstevel@tonic-gate case M_IOCNAK: 1197*0Sstevel@tonic-gate /* Wrong direction for message */ 1198*0Sstevel@tonic-gate break; 1199*0Sstevel@tonic-gate case M_READ: 1200*0Sstevel@tonic-gate break; 1201*0Sstevel@tonic-gate case M_PCPROTO: 1202*0Sstevel@tonic-gate case M_PCRSE: 1203*0Sstevel@tonic-gate default: 1204*0Sstevel@tonic-gate sm_dbg('I', ("sm_hp_uwput: default case %d.\n", msgtype)); 1205*0Sstevel@tonic-gate break; 1206*0Sstevel@tonic-gate } /* end switch on high pri message type */ 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate freemsg(mp); 1209*0Sstevel@tonic-gate return (rval); 1210*0Sstevel@tonic-gate } 1211*0Sstevel@tonic-gate 1212*0Sstevel@tonic-gate static int 1213*0Sstevel@tonic-gate sm_default_uwioctl(queue_t *wq, mblk_t *mp, int (*qfn)()) 1214*0Sstevel@tonic-gate { 1215*0Sstevel@tonic-gate int err; 1216*0Sstevel@tonic-gate struct iocblk *iobp; 1217*0Sstevel@tonic-gate sm_uqi_t *uqi; 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate uqi = (sm_uqi_t *)(wq->q_ptr); 1220*0Sstevel@tonic-gate iobp = (struct iocblk *)mp->b_rptr; 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate switch (iobp->ioc_cmd) { 1223*0Sstevel@tonic-gate case TIOCEXCL: 1224*0Sstevel@tonic-gate case TIOCNXCL: 1225*0Sstevel@tonic-gate case TIOCSTI: 1226*0Sstevel@tonic-gate (void) ttycommon_ioctl(uqi->sm_ttycommon, wq, mp, &err); 1227*0Sstevel@tonic-gate sm_reply(wq, mp, err ? M_IOCACK : M_IOCNAK, err); 1228*0Sstevel@tonic-gate return (0); 1229*0Sstevel@tonic-gate default: 1230*0Sstevel@tonic-gate break; 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate err = sm_update_ttyinfo(mp, uqi); 1233*0Sstevel@tonic-gate if (err) { 1234*0Sstevel@tonic-gate iobp->ioc_error = err; 1235*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1236*0Sstevel@tonic-gate qreply(wq, mp); 1237*0Sstevel@tonic-gate return (0); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* 1241*0Sstevel@tonic-gate * If uqi->sm_siocdata.sm_iocid just overwrite it since the stream 1242*0Sstevel@tonic-gate * head will have timed it out 1243*0Sstevel@tonic-gate */ 1244*0Sstevel@tonic-gate uqi->sm_siocdata.sm_iocid = iobp->ioc_id; 1245*0Sstevel@tonic-gate uqi->sm_siocdata.sm_acked = 0; 1246*0Sstevel@tonic-gate uqi->sm_siocdata.sm_nacks = sm_good_qs(uqi); 1247*0Sstevel@tonic-gate uqi->sm_siocdata.sm_acnt = 0; 1248*0Sstevel@tonic-gate uqi->sm_siocdata.sm_policy = uqi->sm_policy; 1249*0Sstevel@tonic-gate uqi->sm_siocdata.sm_flags = 0; 1250*0Sstevel@tonic-gate sm_dbg('Z', (" want %d acks for id %d.\n", 1251*0Sstevel@tonic-gate uqi->sm_siocdata.sm_nacks, iobp->ioc_id)); 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate return (sm_putqs(wq, mp, qfn)); 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate /* 1257*0Sstevel@tonic-gate * 1258*0Sstevel@tonic-gate * sm_uwput - put function for an upper STREAM write. 1259*0Sstevel@tonic-gate */ 1260*0Sstevel@tonic-gate static int 1261*0Sstevel@tonic-gate sm_uwput(queue_t *wq, mblk_t *mp) 1262*0Sstevel@tonic-gate { 1263*0Sstevel@tonic-gate sm_uqi_t *uqi; 1264*0Sstevel@tonic-gate uchar_t msgtype; 1265*0Sstevel@tonic-gate int cmd; 1266*0Sstevel@tonic-gate struct iocblk *iobp; 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate uqi = (sm_uqi_t *)(wq->q_ptr); 1269*0Sstevel@tonic-gate msgtype = DB_TYPE(mp); 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate ASSERT(uqi != 0 && sm_ssp != 0); 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate if (msgtype >= QPCTL && msgtype != M_IOCDATA) { 1274*0Sstevel@tonic-gate (void) sm_hp_uwput(wq, mp); 1275*0Sstevel@tonic-gate return (0); 1276*0Sstevel@tonic-gate } 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1279*0Sstevel@tonic-gate case M_DATA: 1280*0Sstevel@tonic-gate case M_DELAY: 1281*0Sstevel@tonic-gate case M_BREAK: 1282*0Sstevel@tonic-gate default: 1283*0Sstevel@tonic-gate (void) sm_putqs(wq, mp, putq); 1284*0Sstevel@tonic-gate break; 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate case M_CTL: 1287*0Sstevel@tonic-gate if (((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_CANONQUERY) { 1288*0Sstevel@tonic-gate (void) putnextctl1(OTHERQ(wq), M_CTL, MC_NOCANON); 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate freemsg(mp); 1291*0Sstevel@tonic-gate break; 1292*0Sstevel@tonic-gate case M_IOCDATA: /* not handled as high pri because may need to putbq */ 1293*0Sstevel@tonic-gate sm_dbg('M', ("sm_uwput(M_IOCDATA)\n")); 1294*0Sstevel@tonic-gate /*FALLTHROUGH*/ 1295*0Sstevel@tonic-gate case M_IOCTL: 1296*0Sstevel@tonic-gate cmd = (msgtype == M_IOCDATA) ? 1297*0Sstevel@tonic-gate ((struct copyresp *)mp->b_rptr)->cp_cmd : 1298*0Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd; 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate iobp = (struct iocblk *)mp->b_rptr; 1301*0Sstevel@tonic-gate iobp->ioc_rval = 0; 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate sm_dbg('M', ("sm_uwput(M_IOCTL:%d)\n", cmd)); 1304*0Sstevel@tonic-gate 1305*0Sstevel@tonic-gate switch (cmd) { 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate case CONSGETABORTENABLE: 1308*0Sstevel@tonic-gate iobp->ioc_error = ttymux_abort_ioctl(mp); 1309*0Sstevel@tonic-gate DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK; 1310*0Sstevel@tonic-gate qreply(wq, mp); 1311*0Sstevel@tonic-gate break; 1312*0Sstevel@tonic-gate case CONSSETABORTENABLE: 1313*0Sstevel@tonic-gate iobp->ioc_error = 1314*0Sstevel@tonic-gate secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0 ? 1315*0Sstevel@tonic-gate EPERM : ttymux_abort_ioctl(mp); 1316*0Sstevel@tonic-gate DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK; 1317*0Sstevel@tonic-gate qreply(wq, mp); 1318*0Sstevel@tonic-gate break; 1319*0Sstevel@tonic-gate case TTYMUX_SETABORT: 1320*0Sstevel@tonic-gate if (secpolicy_sys_config(iobp->ioc_cr, B_FALSE) != 0) { 1321*0Sstevel@tonic-gate iobp->ioc_error = EPERM; 1322*0Sstevel@tonic-gate DB_TYPE(mp) = M_IOCNAK; 1323*0Sstevel@tonic-gate qreply(wq, mp); 1324*0Sstevel@tonic-gate break; 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate /*FALLTHROUGH*/ 1327*0Sstevel@tonic-gate case TTYMUX_GETABORT: 1328*0Sstevel@tonic-gate case TTYMUX_GETABORTSTR: 1329*0Sstevel@tonic-gate case TTYMUX_ASSOC: 1330*0Sstevel@tonic-gate case TTYMUX_DISASSOC: 1331*0Sstevel@tonic-gate case TTYMUX_SETCTL: 1332*0Sstevel@tonic-gate case TTYMUX_GETLINK: 1333*0Sstevel@tonic-gate case TTYMUX_CONSDEV: 1334*0Sstevel@tonic-gate case TTYMUX_GETCTL: 1335*0Sstevel@tonic-gate case TTYMUX_LIST: 1336*0Sstevel@tonic-gate (void) sm_ioctl_cmd(uqi, mp); 1337*0Sstevel@tonic-gate qreply(wq, mp); 1338*0Sstevel@tonic-gate break; 1339*0Sstevel@tonic-gate case I_LINK: 1340*0Sstevel@tonic-gate case I_PLINK: 1341*0Sstevel@tonic-gate case I_UNLINK: 1342*0Sstevel@tonic-gate case I_PUNLINK: 1343*0Sstevel@tonic-gate qwriter(wq, mp, sm_link_req, PERIM_OUTER); 1344*0Sstevel@tonic-gate break; 1345*0Sstevel@tonic-gate case TCSETSW: 1346*0Sstevel@tonic-gate case TCSETSF: 1347*0Sstevel@tonic-gate case TCSETAW: 1348*0Sstevel@tonic-gate case TCSETAF: 1349*0Sstevel@tonic-gate case TCSBRK: 1350*0Sstevel@tonic-gate if (wq->q_first) { 1351*0Sstevel@tonic-gate sm_dbg('A', ("sm_uwput: TCSET-> on srv q.\n")); 1352*0Sstevel@tonic-gate /* keep message order intact */ 1353*0Sstevel@tonic-gate (void) putq(wq, mp); 1354*0Sstevel@tonic-gate break; 1355*0Sstevel@tonic-gate } 1356*0Sstevel@tonic-gate /*FALLTHROUGH*/ 1357*0Sstevel@tonic-gate default: 1358*0Sstevel@tonic-gate (void) sm_default_uwioctl(wq, mp, putq); 1359*0Sstevel@tonic-gate break; 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate break; /* M_IOCTL */ 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate } /* end switch on message type */ 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate return (0); 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate /* 1370*0Sstevel@tonic-gate * sm_uwsrv - service function for an upper STREAM write. 1371*0Sstevel@tonic-gate * 'sm_uwsrv' takes a q parameter. The q parameter specifies the queue 1372*0Sstevel@tonic-gate * which is to be serviced. This function reads the messages which are on 1373*0Sstevel@tonic-gate * this service queue and passes them to the appropriate lower driver queue. 1374*0Sstevel@tonic-gate */ 1375*0Sstevel@tonic-gate static int 1376*0Sstevel@tonic-gate sm_uwsrv(queue_t *q) 1377*0Sstevel@tonic-gate { 1378*0Sstevel@tonic-gate mblk_t *mp; 1379*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)(q->q_ptr); 1380*0Sstevel@tonic-gate int msgtype; 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate ASSERT(q == SM_WQ(uqi)); 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate /* 1385*0Sstevel@tonic-gate * Empty the queue unless explicitly stopped. 1386*0Sstevel@tonic-gate */ 1387*0Sstevel@tonic-gate while (mp = getq(q)) { 1388*0Sstevel@tonic-gate msgtype = DB_TYPE(mp); 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate if (msgtype >= QPCTL && msgtype != M_IOCDATA) 1391*0Sstevel@tonic-gate if (sm_hp_uwput(q, mp)) { 1392*0Sstevel@tonic-gate sm_dbg('T', ("sm_uwsrv: flowcontrolled.\n")); 1393*0Sstevel@tonic-gate break; /* indicates that the is disabled */ 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate else 1396*0Sstevel@tonic-gate continue; 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate if (uqi->sm_flags & SM_STOPPED) { 1399*0Sstevel@tonic-gate (void) putbq(q, mp); 1400*0Sstevel@tonic-gate sm_dbg('T', ("sm_uwsrv: SM_STOPPED.\n")); 1401*0Sstevel@tonic-gate break; 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate /* 1405*0Sstevel@tonic-gate * Read any ttycommon data that may 1406*0Sstevel@tonic-gate * change (TS_SOFTCAR, CREAD, etc.). 1407*0Sstevel@tonic-gate */ 1408*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1409*0Sstevel@tonic-gate case M_IOCTL: 1410*0Sstevel@tonic-gate case M_IOCDATA: 1411*0Sstevel@tonic-gate if (sm_default_uwioctl(q, mp, putbq)) 1412*0Sstevel@tonic-gate return (0); 1413*0Sstevel@tonic-gate break; 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate default: 1416*0Sstevel@tonic-gate if (sm_putqs(q, mp, putbq)) 1417*0Sstevel@tonic-gate return (0); 1418*0Sstevel@tonic-gate } 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate return (0); 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate /* 1424*0Sstevel@tonic-gate * Lower write side service routine used for backenabling upstream 1425*0Sstevel@tonic-gate * flow control. 1426*0Sstevel@tonic-gate */ 1427*0Sstevel@tonic-gate static int 1428*0Sstevel@tonic-gate sm_lwsrv(queue_t *q) 1429*0Sstevel@tonic-gate { 1430*0Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 1431*0Sstevel@tonic-gate queue_t *uwq; 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate LOCK_UNIT(lqi); 1434*0Sstevel@tonic-gate if (lqi->sm_uqflags & SM_UQVALID) { 1435*0Sstevel@tonic-gate /* 1436*0Sstevel@tonic-gate * It's safe to lock uqi since lwsrv runs asynchronously 1437*0Sstevel@tonic-gate * with the upper write routines so this cannot be an 1438*0Sstevel@tonic-gate * upper half thread. While holding the lqi lock and 1439*0Sstevel@tonic-gate * if SM_UQVALID is set we are guaranteed that 1440*0Sstevel@tonic-gate * lqi->sm_uqi will be valid. 1441*0Sstevel@tonic-gate */ 1442*0Sstevel@tonic-gate sm_dbg('I', ("sm_lwsrv: re-enabling upper queue.\n")); 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate uwq = SM_WQ(lqi->sm_uqi); 1445*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1446*0Sstevel@tonic-gate qenable(uwq); 1447*0Sstevel@tonic-gate } else { 1448*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1449*0Sstevel@tonic-gate } 1450*0Sstevel@tonic-gate return (0); 1451*0Sstevel@tonic-gate } 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate /* 1454*0Sstevel@tonic-gate * Upper read queue ioctl response handler for messages 1455*0Sstevel@tonic-gate * passed from the lower half of the driver. 1456*0Sstevel@tonic-gate */ 1457*0Sstevel@tonic-gate static int 1458*0Sstevel@tonic-gate sm_uriocack(queue_t *rq, mblk_t *mp) 1459*0Sstevel@tonic-gate { 1460*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)rq->q_ptr; 1461*0Sstevel@tonic-gate int err, flag; 1462*0Sstevel@tonic-gate sm_iocdata_t *iodp; 1463*0Sstevel@tonic-gate struct sm_iocinfo info; 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate if ((err = sm_getiocinfo(mp, &info)) != 0) { 1466*0Sstevel@tonic-gate sm_dbg('I', ("Unknown ioctl response\n")); 1467*0Sstevel@tonic-gate return (err); 1468*0Sstevel@tonic-gate } 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate if (info.sm_id == uqi->sm_piocdata.sm_iocid) { 1471*0Sstevel@tonic-gate iodp = &uqi->sm_piocdata; 1472*0Sstevel@tonic-gate } else if (info.sm_id == uqi->sm_siocdata.sm_iocid) { 1473*0Sstevel@tonic-gate iodp = &uqi->sm_siocdata; 1474*0Sstevel@tonic-gate } else { 1475*0Sstevel@tonic-gate sm_log("Unexpected ioctl response\n"); 1476*0Sstevel@tonic-gate sm_dbg('I', ("Unexpected ioctl response (id %d)\n", 1477*0Sstevel@tonic-gate info.sm_id)); 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate /* 1480*0Sstevel@tonic-gate * If the response is sent up it will result in 1481*0Sstevel@tonic-gate * duplicate ioctl responses. The ioctl has probably been 1482*0Sstevel@tonic-gate * timed out by the stream head so dispose of the response 1483*0Sstevel@tonic-gate * (since it has arrived too late. 1484*0Sstevel@tonic-gate */ 1485*0Sstevel@tonic-gate goto out; 1486*0Sstevel@tonic-gate } 1487*0Sstevel@tonic-gate 1488*0Sstevel@tonic-gate flag = SM_COPYIN; 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1491*0Sstevel@tonic-gate case M_COPYOUT: 1492*0Sstevel@tonic-gate flag = SM_COPYOUT; 1493*0Sstevel@tonic-gate /*FALLTHRU*/ 1494*0Sstevel@tonic-gate case M_COPYIN: 1495*0Sstevel@tonic-gate if (iodp->sm_flags & flag) 1496*0Sstevel@tonic-gate goto out; 1497*0Sstevel@tonic-gate iodp->sm_flags |= flag; 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate break; 1500*0Sstevel@tonic-gate case M_IOCACK: 1501*0Sstevel@tonic-gate iodp->sm_ackcnt += 1; 1502*0Sstevel@tonic-gate iodp->sm_acnt += 1; 1503*0Sstevel@tonic-gate if (iodp->sm_policy == FIRSTACK) { 1504*0Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) 1505*0Sstevel@tonic-gate iodp->sm_iocid = 0; 1506*0Sstevel@tonic-gate if (iodp->sm_acnt == 1) 1507*0Sstevel@tonic-gate iodp->sm_acked = 1; 1508*0Sstevel@tonic-gate else 1509*0Sstevel@tonic-gate goto out; 1510*0Sstevel@tonic-gate } else { 1511*0Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) { 1512*0Sstevel@tonic-gate iodp->sm_iocid = 0; 1513*0Sstevel@tonic-gate iodp->sm_acked = 1; 1514*0Sstevel@tonic-gate } else 1515*0Sstevel@tonic-gate goto out; 1516*0Sstevel@tonic-gate } 1517*0Sstevel@tonic-gate break; 1518*0Sstevel@tonic-gate case M_IOCNAK: 1519*0Sstevel@tonic-gate iodp->sm_nakcnt += 1; 1520*0Sstevel@tonic-gate iodp->sm_acnt += 1; 1521*0Sstevel@tonic-gate if (iodp->sm_acnt == iodp->sm_nacks) { 1522*0Sstevel@tonic-gate iodp->sm_iocid = 0; 1523*0Sstevel@tonic-gate if (iodp->sm_acked == 0) { 1524*0Sstevel@tonic-gate iodp->sm_acked = 1; 1525*0Sstevel@tonic-gate break; 1526*0Sstevel@tonic-gate } 1527*0Sstevel@tonic-gate } 1528*0Sstevel@tonic-gate goto out; 1529*0Sstevel@tonic-gate default: 1530*0Sstevel@tonic-gate goto out; 1531*0Sstevel@tonic-gate } 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate /* 1534*0Sstevel@tonic-gate * Merge the tty settings each of the associated lower streams. 1535*0Sstevel@tonic-gate */ 1536*0Sstevel@tonic-gate if (info.sm_data) 1537*0Sstevel@tonic-gate (void) sm_update_ttyinfo(mp, uqi); 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate if (iodp == &uqi->sm_piocdata) { 1540*0Sstevel@tonic-gate if (iodp->sm_iocid == 0) { 1541*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_IOCPENDING; 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate } else { 1544*0Sstevel@tonic-gate sm_dbg('I', ("sm_uriocack: forwarding response for %d.\n", 1545*0Sstevel@tonic-gate info.sm_id)); 1546*0Sstevel@tonic-gate putnext(rq, mp); 1547*0Sstevel@tonic-gate return (0); 1548*0Sstevel@tonic-gate } 1549*0Sstevel@tonic-gate out: 1550*0Sstevel@tonic-gate sm_dbg('I', ("sm_uriocack: freeing response for %d.\n", info.sm_id)); 1551*0Sstevel@tonic-gate freemsg(mp); 1552*0Sstevel@tonic-gate return (0); 1553*0Sstevel@tonic-gate } 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate /* 1556*0Sstevel@tonic-gate * Transfer a message from the lower read side of the multiplexer onto 1557*0Sstevel@tonic-gate * the associated upper stream. 1558*0Sstevel@tonic-gate */ 1559*0Sstevel@tonic-gate static int 1560*0Sstevel@tonic-gate sm_ursendup(queue_t *q, mblk_t *mp) 1561*0Sstevel@tonic-gate { 1562*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate if (!canputnext(q) && DB_TYPE(mp) < QPCTL) { 1565*0Sstevel@tonic-gate sm_dbg('I', ("sm_ursendup: flow controlled.\n")); 1566*0Sstevel@tonic-gate return (1); 1567*0Sstevel@tonic-gate } 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1570*0Sstevel@tonic-gate case M_COPYIN: 1571*0Sstevel@tonic-gate case M_COPYOUT: 1572*0Sstevel@tonic-gate case M_IOCACK: 1573*0Sstevel@tonic-gate case M_IOCNAK: 1574*0Sstevel@tonic-gate (void) sm_uriocack(q, mp); 1575*0Sstevel@tonic-gate break; 1576*0Sstevel@tonic-gate case M_HANGUP: 1577*0Sstevel@tonic-gate if (sm_uwq_error(uqi)) { 1578*0Sstevel@tonic-gate /* there are no usable lower q's */ 1579*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 1580*0Sstevel@tonic-gate putnext(q, mp); 1581*0Sstevel@tonic-gate } else { 1582*0Sstevel@tonic-gate /* there are still usable q's - don't send up */ 1583*0Sstevel@tonic-gate freemsg(mp); 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate break; 1586*0Sstevel@tonic-gate case M_ERROR: 1587*0Sstevel@tonic-gate if (sm_uwq_error(uqi)) { 1588*0Sstevel@tonic-gate /* there are no usable lower q's */ 1589*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_CARON; 1590*0Sstevel@tonic-gate putnext(q, mp); 1591*0Sstevel@tonic-gate } else if (*mp->b_rptr == NOERROR) { 1592*0Sstevel@tonic-gate /* the error has cleared */ 1593*0Sstevel@tonic-gate uqi->sm_flags &= ~ERROR_MODE; 1594*0Sstevel@tonic-gate putnext(q, mp); 1595*0Sstevel@tonic-gate } else { 1596*0Sstevel@tonic-gate /* there are still usable q's - don't send up */ 1597*0Sstevel@tonic-gate freemsg(mp); 1598*0Sstevel@tonic-gate } 1599*0Sstevel@tonic-gate break; 1600*0Sstevel@tonic-gate case M_FLUSH: 1601*0Sstevel@tonic-gate flushq(q, FLUSHDATA); 1602*0Sstevel@tonic-gate putnext(q, mp); /* time to use FLUSHR_PEND flag */ 1603*0Sstevel@tonic-gate break; 1604*0Sstevel@tonic-gate case M_CTL: 1605*0Sstevel@tonic-gate /* wrong direction - must have come from sm_close */ 1606*0Sstevel@tonic-gate uqi->sm_flags |= SM_CLOSE; 1607*0Sstevel@tonic-gate sm_dbg('I', ("sm_ursrv: had SM_CLOSE.\n")); 1608*0Sstevel@tonic-gate freemsg(mp); 1609*0Sstevel@tonic-gate break; 1610*0Sstevel@tonic-gate case M_UNHANGUP: 1611*0Sstevel@tonic-gate /* just pass them all up - they're harmless */ 1612*0Sstevel@tonic-gate uqi->sm_flags |= SM_CARON; 1613*0Sstevel@tonic-gate /* FALLTHROUGH */ 1614*0Sstevel@tonic-gate default: 1615*0Sstevel@tonic-gate putnext(q, mp); 1616*0Sstevel@tonic-gate break; 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate return (0); 1620*0Sstevel@tonic-gate } 1621*0Sstevel@tonic-gate 1622*0Sstevel@tonic-gate /* 1623*0Sstevel@tonic-gate * sm_urput - put function for a lower STREAM read. 1624*0Sstevel@tonic-gate */ 1625*0Sstevel@tonic-gate static int 1626*0Sstevel@tonic-gate sm_urput(queue_t *q, mblk_t *mp) 1627*0Sstevel@tonic-gate { 1628*0Sstevel@tonic-gate if (sm_ursendup(q, mp) != 0) 1629*0Sstevel@tonic-gate (void) putq(q, mp); 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate return (0); 1632*0Sstevel@tonic-gate } 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate /* 1635*0Sstevel@tonic-gate * Upper read side service routine. 1636*0Sstevel@tonic-gate * Read side needs to be fast so only check for duplicate M_IOCTL acks. 1637*0Sstevel@tonic-gate */ 1638*0Sstevel@tonic-gate static int 1639*0Sstevel@tonic-gate sm_ursrv(queue_t *q) 1640*0Sstevel@tonic-gate { 1641*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)q->q_ptr; 1642*0Sstevel@tonic-gate mblk_t *mp; 1643*0Sstevel@tonic-gate int flags = uqi->sm_flags; 1644*0Sstevel@tonic-gate 1645*0Sstevel@tonic-gate while ((mp = getq(q))) { 1646*0Sstevel@tonic-gate if (sm_ursendup(q, mp) != 0) { 1647*0Sstevel@tonic-gate sm_dbg('I', ("sm_ursrv: flow controlled.\n")); 1648*0Sstevel@tonic-gate (void) putbq(q, mp); 1649*0Sstevel@tonic-gate uqi->sm_flags |= WANT_RENB; 1650*0Sstevel@tonic-gate break; 1651*0Sstevel@tonic-gate } 1652*0Sstevel@tonic-gate } 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate /* 1655*0Sstevel@tonic-gate * If the q service was called because it was no longer 1656*0Sstevel@tonic-gate * flow controled then enable each of the driver queues. 1657*0Sstevel@tonic-gate */ 1658*0Sstevel@tonic-gate if ((flags & WANT_RENB) && !(uqi->sm_flags & WANT_RENB)) { 1659*0Sstevel@tonic-gate sm_lqi_t *lqi; 1660*0Sstevel@tonic-gate queue_t *drq; /* read q of linked driver */ 1661*0Sstevel@tonic-gate 1662*0Sstevel@tonic-gate uqi->sm_flags &= ~WANT_RENB; 1663*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 1664*0Sstevel@tonic-gate drq = SM_RQ(lqi)->q_next; 1665*0Sstevel@tonic-gate if (drq && drq->q_first != 0) 1666*0Sstevel@tonic-gate qenable(drq); 1667*0Sstevel@tonic-gate } 1668*0Sstevel@tonic-gate } 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate return (0); 1671*0Sstevel@tonic-gate } 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate /* 1674*0Sstevel@tonic-gate * Check a message sent from a linked device for abort requests and 1675*0Sstevel@tonic-gate * for flow control. 1676*0Sstevel@tonic-gate */ 1677*0Sstevel@tonic-gate static int 1678*0Sstevel@tonic-gate sm_lrmsg_check(queue_t *q, mblk_t *mp) 1679*0Sstevel@tonic-gate { 1680*0Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1683*0Sstevel@tonic-gate case M_DATA: 1684*0Sstevel@tonic-gate LOCK_UNIT(lqi); 1685*0Sstevel@tonic-gate /* 1686*0Sstevel@tonic-gate * check for abort - only allow abort on I/O consoles 1687*0Sstevel@tonic-gate * known to OBP - 1688*0Sstevel@tonic-gate * fix it when we do polled io 1689*0Sstevel@tonic-gate */ 1690*0Sstevel@tonic-gate if ((lqi->sm_ioflag & (uint_t)FORINPUT) == 0) { 1691*0Sstevel@tonic-gate freemsg(mp); 1692*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1693*0Sstevel@tonic-gate return (1); 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_OBPCNDEV) && 1696*0Sstevel@tonic-gate lqi->sm_ctrla_abort_on && 1697*0Sstevel@tonic-gate abort_enable == KIOCABORTALTERNATE) { 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate uchar_t *rxc; 1700*0Sstevel@tonic-gate boolean_t aborted = B_FALSE; 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate for (rxc = mp->b_rptr; 1703*0Sstevel@tonic-gate rxc != mp->b_wptr; 1704*0Sstevel@tonic-gate rxc++) 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate if (*rxc == *lqi->sm_nachar) { 1707*0Sstevel@tonic-gate lqi->sm_nachar++; 1708*0Sstevel@tonic-gate if (*lqi->sm_nachar == '\0') { 1709*0Sstevel@tonic-gate abort_sequence_enter( 1710*0Sstevel@tonic-gate (char *)NULL); 1711*0Sstevel@tonic-gate lqi->sm_nachar = sm_ssp->sm_abs; 1712*0Sstevel@tonic-gate aborted = B_TRUE; 1713*0Sstevel@tonic-gate } 1714*0Sstevel@tonic-gate } else 1715*0Sstevel@tonic-gate lqi->sm_nachar = (*rxc == *sm_ssp-> 1716*0Sstevel@tonic-gate sm_abs) ? 1717*0Sstevel@tonic-gate sm_ssp-> 1718*0Sstevel@tonic-gate sm_abs + 1 : 1719*0Sstevel@tonic-gate sm_ssp->sm_abs; 1720*0Sstevel@tonic-gate 1721*0Sstevel@tonic-gate if (aborted) { 1722*0Sstevel@tonic-gate freemsg(mp); 1723*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1724*0Sstevel@tonic-gate return (1); 1725*0Sstevel@tonic-gate } 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1728*0Sstevel@tonic-gate break; 1729*0Sstevel@tonic-gate case M_BREAK: /* we'll eventually see this as a flush */ 1730*0Sstevel@tonic-gate LOCK_UNIT(lqi); 1731*0Sstevel@tonic-gate /* 1732*0Sstevel@tonic-gate * Only allow abort on OBP devices. When polled I/O is 1733*0Sstevel@tonic-gate * supported allow abort on any console device. 1734*0Sstevel@tonic-gate * Parity errors are reported upstream as breaks so 1735*0Sstevel@tonic-gate * ensure that there is no data in the message before 1736*0Sstevel@tonic-gate * deciding whether to abort. 1737*0Sstevel@tonic-gate */ 1738*0Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_OBPCNDEV) && /* console stream */ 1739*0Sstevel@tonic-gate (mp->b_wptr - mp->b_rptr == 0 && 1740*0Sstevel@tonic-gate msgdsize(mp) == 0)) { /* not due to parity */ 1741*0Sstevel@tonic-gate 1742*0Sstevel@tonic-gate if (lqi->sm_break_abort_on && 1743*0Sstevel@tonic-gate abort_enable != KIOCABORTALTERNATE) 1744*0Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate freemsg(mp); 1747*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1748*0Sstevel@tonic-gate return (1); 1749*0Sstevel@tonic-gate } else { 1750*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1751*0Sstevel@tonic-gate } 1752*0Sstevel@tonic-gate break; 1753*0Sstevel@tonic-gate default: 1754*0Sstevel@tonic-gate break; 1755*0Sstevel@tonic-gate } 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate if (DB_TYPE(mp) >= QPCTL) 1758*0Sstevel@tonic-gate return (0); 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate LOCK_UNIT(lqi); /* lock out the upper half */ 1761*0Sstevel@tonic-gate if ((lqi->sm_uqflags & SM_UQVALID) && SM_RQ(lqi->sm_uqi)) { 1762*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1763*0Sstevel@tonic-gate if (!canput(SM_RQ(lqi->sm_uqi))) { 1764*0Sstevel@tonic-gate sm_dbg('I', ("sm_lrmsg_check: flow controlled.\n")); 1765*0Sstevel@tonic-gate (void) putq(q, mp); 1766*0Sstevel@tonic-gate return (1); 1767*0Sstevel@tonic-gate } 1768*0Sstevel@tonic-gate } else { 1769*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1770*0Sstevel@tonic-gate } 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate return (0); 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate 1775*0Sstevel@tonic-gate /* 1776*0Sstevel@tonic-gate * sm_sendup - deliver a message to the upper read side of the multiplexer 1777*0Sstevel@tonic-gate */ 1778*0Sstevel@tonic-gate static int 1779*0Sstevel@tonic-gate sm_sendup(queue_t *q, mblk_t *mp) 1780*0Sstevel@tonic-gate { 1781*0Sstevel@tonic-gate sm_lqi_t *lqi = (sm_lqi_t *)q->q_ptr; 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate if (sm_ssp == NULL) { 1784*0Sstevel@tonic-gate freemsg(mp); 1785*0Sstevel@tonic-gate return (0); 1786*0Sstevel@tonic-gate } 1787*0Sstevel@tonic-gate 1788*0Sstevel@tonic-gate /* 1789*0Sstevel@tonic-gate * Check for CD status change messages from driver. 1790*0Sstevel@tonic-gate * (Remark: this is an se driver thread running at soft interupt 1791*0Sstevel@tonic-gate * priority and the waiters are in user context). 1792*0Sstevel@tonic-gate */ 1793*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 1794*0Sstevel@tonic-gate case M_DATA: 1795*0Sstevel@tonic-gate case M_BREAK: /* we'll eventually see this as a flush */ 1796*0Sstevel@tonic-gate break; 1797*0Sstevel@tonic-gate 1798*0Sstevel@tonic-gate /* high priority messages */ 1799*0Sstevel@tonic-gate case M_IOCACK: 1800*0Sstevel@tonic-gate case M_IOCNAK: 1801*0Sstevel@tonic-gate if ((lqi->sm_flags & SM_IOCPENDING) && lqi->sm_piocid == 1802*0Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_id) { 1803*0Sstevel@tonic-gate freemsg(mp); 1804*0Sstevel@tonic-gate lqi->sm_flags &= ~SM_IOCPENDING; 1805*0Sstevel@tonic-gate sm_issue_ioctl(lqi); 1806*0Sstevel@tonic-gate return (0); 1807*0Sstevel@tonic-gate } 1808*0Sstevel@tonic-gate break; 1809*0Sstevel@tonic-gate case M_UNHANGUP: 1810*0Sstevel@tonic-gate /* 1811*0Sstevel@tonic-gate * If the driver can send an M_UNHANGUP it must be able to 1812*0Sstevel@tonic-gate * accept messages from above (ie clear WERROR_MODE if set). 1813*0Sstevel@tonic-gate */ 1814*0Sstevel@tonic-gate sm_dbg('E', ("lrput: M_UNHANGUP\n")); 1815*0Sstevel@tonic-gate lqi->sm_mbits |= TIOCM_CD; 1816*0Sstevel@tonic-gate lqi->sm_flags &= ~(WERROR_MODE|HANGUP_MODE); 1817*0Sstevel@tonic-gate 1818*0Sstevel@tonic-gate break; 1819*0Sstevel@tonic-gate 1820*0Sstevel@tonic-gate case M_HANGUP: 1821*0Sstevel@tonic-gate sm_dbg('E', ("lrput: MHANGUP\n")); 1822*0Sstevel@tonic-gate lqi->sm_mbits &= ~TIOCM_CD; 1823*0Sstevel@tonic-gate lqi->sm_flags |= (WERROR_MODE|HANGUP_MODE); 1824*0Sstevel@tonic-gate break; 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate case M_ERROR: 1827*0Sstevel@tonic-gate 1828*0Sstevel@tonic-gate sm_dbg('E', ("lrput: MERROR\n")); 1829*0Sstevel@tonic-gate /* 1830*0Sstevel@tonic-gate * Tell the driver to flush rd/wr queue if its read/write error. 1831*0Sstevel@tonic-gate * if its a read/write error flush rq/wq (type in first bytes). 1832*0Sstevel@tonic-gate */ 1833*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) == 2) { 1834*0Sstevel@tonic-gate uchar_t rw = 0; 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate if (*mp->b_rptr == NOERROR) { 1837*0Sstevel@tonic-gate /* not in error anymore */ 1838*0Sstevel@tonic-gate lqi->sm_flags &= ~ERROR_MODE; 1839*0Sstevel@tonic-gate lqi->sm_flags |= WANT_CD; 1840*0Sstevel@tonic-gate } else { 1841*0Sstevel@tonic-gate if (*mp->b_rptr != 0) { 1842*0Sstevel@tonic-gate /* read error */ 1843*0Sstevel@tonic-gate rw |= FLUSHR; 1844*0Sstevel@tonic-gate lqi->sm_flags |= RERROR_MODE; 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate mp->b_rptr++; 1847*0Sstevel@tonic-gate if (*mp->b_rptr != 0) { 1848*0Sstevel@tonic-gate /* write error */ 1849*0Sstevel@tonic-gate rw |= FLUSHW; 1850*0Sstevel@tonic-gate lqi->sm_flags |= WERROR_MODE; 1851*0Sstevel@tonic-gate } 1852*0Sstevel@tonic-gate 1853*0Sstevel@tonic-gate mp->b_rptr--; 1854*0Sstevel@tonic-gate /* has next driver done qprocsoff */ 1855*0Sstevel@tonic-gate if (rw && OTHERQ(q)->q_next != NULL) { 1856*0Sstevel@tonic-gate (void) putnextctl1(OTHERQ(q), M_FLUSH, 1857*0Sstevel@tonic-gate rw); 1858*0Sstevel@tonic-gate } 1859*0Sstevel@tonic-gate } 1860*0Sstevel@tonic-gate } else if (*mp->b_rptr != 0 && OTHERQ(q)->q_next != NULL) { 1861*0Sstevel@tonic-gate sm_dbg('E', ("lrput: old style MERROR (?)\n")); 1862*0Sstevel@tonic-gate 1863*0Sstevel@tonic-gate lqi->sm_flags |= (RERROR_MODE | WERROR_MODE); 1864*0Sstevel@tonic-gate (void) putnextctl1(OTHERQ(q), M_FLUSH, FLUSHRW); 1865*0Sstevel@tonic-gate } 1866*0Sstevel@tonic-gate break; 1867*0Sstevel@tonic-gate 1868*0Sstevel@tonic-gate case M_PCSIG: 1869*0Sstevel@tonic-gate case M_SIG: 1870*0Sstevel@tonic-gate break; 1871*0Sstevel@tonic-gate case M_COPYOUT: 1872*0Sstevel@tonic-gate case M_COPYIN: 1873*0Sstevel@tonic-gate break; 1874*0Sstevel@tonic-gate case M_FLUSH: 1875*0Sstevel@tonic-gate /* flush the read queue and pass on up */ 1876*0Sstevel@tonic-gate flushq(q, FLUSHDATA); 1877*0Sstevel@tonic-gate break; 1878*0Sstevel@tonic-gate default: 1879*0Sstevel@tonic-gate break; 1880*0Sstevel@tonic-gate } 1881*0Sstevel@tonic-gate 1882*0Sstevel@tonic-gate LOCK_UNIT(lqi); /* lock out the upper half */ 1883*0Sstevel@tonic-gate if (lqi->sm_uqflags & SM_UQVALID && SM_RQ(lqi->sm_uqi)) { 1884*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1885*0Sstevel@tonic-gate (void) putq(SM_RQ(lqi->sm_uqi), mp); 1886*0Sstevel@tonic-gate return (0); 1887*0Sstevel@tonic-gate } else { 1888*0Sstevel@tonic-gate sm_dbg('I', ("sm_sendup: uq not valid\n")); 1889*0Sstevel@tonic-gate freemsg(mp); 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 1892*0Sstevel@tonic-gate 1893*0Sstevel@tonic-gate return (0); 1894*0Sstevel@tonic-gate } 1895*0Sstevel@tonic-gate 1896*0Sstevel@tonic-gate /* 1897*0Sstevel@tonic-gate * sm_lrput - put function for a lower STREAM read. 1898*0Sstevel@tonic-gate */ 1899*0Sstevel@tonic-gate static int 1900*0Sstevel@tonic-gate sm_lrput(queue_t *q, mblk_t *mp) 1901*0Sstevel@tonic-gate { 1902*0Sstevel@tonic-gate if (sm_lrmsg_check(q, mp) == 0) 1903*0Sstevel@tonic-gate (void) sm_sendup(q, mp); 1904*0Sstevel@tonic-gate return (0); 1905*0Sstevel@tonic-gate } 1906*0Sstevel@tonic-gate 1907*0Sstevel@tonic-gate /* 1908*0Sstevel@tonic-gate * sm_lrsrv - service function for the lower read STREAM. 1909*0Sstevel@tonic-gate */ 1910*0Sstevel@tonic-gate static int 1911*0Sstevel@tonic-gate sm_lrsrv(queue_t *q) 1912*0Sstevel@tonic-gate { 1913*0Sstevel@tonic-gate mblk_t *mp; 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gate sm_dbg('I', ("sm_lrsrv: not controlled.\n")); 1916*0Sstevel@tonic-gate while (mp = getq(q)) 1917*0Sstevel@tonic-gate (void) sm_sendup(q, mp); 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate return (0); 1920*0Sstevel@tonic-gate } 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate /* 1923*0Sstevel@tonic-gate * Check whether a thread is allowed to open the requested device. 1924*0Sstevel@tonic-gate */ 1925*0Sstevel@tonic-gate static int 1926*0Sstevel@tonic-gate sm_ok_to_open(sm_uqi_t *uqi, int protocol, cred_t *credp, int *abort_waiters) 1927*0Sstevel@tonic-gate { 1928*0Sstevel@tonic-gate int rval = 0; 1929*0Sstevel@tonic-gate int proto; 1930*0Sstevel@tonic-gate 1931*0Sstevel@tonic-gate *abort_waiters = 0; 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate switch (protocol) { 1934*0Sstevel@tonic-gate case ASYNC_DEVICE: /* Standard async protocol */ 1935*0Sstevel@tonic-gate if ((uqi->sm_protocol == NULL_PROTOCOL) || 1936*0Sstevel@tonic-gate (uqi->sm_protocol == ASYN_PROTOCOL)) { 1937*0Sstevel@tonic-gate /* 1938*0Sstevel@tonic-gate * Lock out other incompatible protocol requests. 1939*0Sstevel@tonic-gate */ 1940*0Sstevel@tonic-gate proto = ASYN_PROTOCOL; 1941*0Sstevel@tonic-gate rval = 0; 1942*0Sstevel@tonic-gate } else 1943*0Sstevel@tonic-gate rval = EBUSY; 1944*0Sstevel@tonic-gate break; 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate case OUTLINE: /* Outdial protocol */ 1947*0Sstevel@tonic-gate if ((uqi->sm_protocol == NULL_PROTOCOL) || 1948*0Sstevel@tonic-gate (uqi->sm_protocol == OUTD_PROTOCOL)) { 1949*0Sstevel@tonic-gate proto = OUTD_PROTOCOL; 1950*0Sstevel@tonic-gate rval = 0; 1951*0Sstevel@tonic-gate } else if (uqi->sm_protocol == ASYN_PROTOCOL) { 1952*0Sstevel@tonic-gate /* 1953*0Sstevel@tonic-gate * check for dialout request on a line that is already 1954*0Sstevel@tonic-gate * open for dial in: 1955*0Sstevel@tonic-gate * kick off any thread that is waiting to fully open 1956*0Sstevel@tonic-gate */ 1957*0Sstevel@tonic-gate if (uqi->sm_flags & FULLY_OPEN) 1958*0Sstevel@tonic-gate rval = EBUSY; 1959*0Sstevel@tonic-gate else { 1960*0Sstevel@tonic-gate proto = OUTD_PROTOCOL; 1961*0Sstevel@tonic-gate *abort_waiters = 1; 1962*0Sstevel@tonic-gate } 1963*0Sstevel@tonic-gate } else 1964*0Sstevel@tonic-gate rval = EBUSY; 1965*0Sstevel@tonic-gate break; 1966*0Sstevel@tonic-gate default: 1967*0Sstevel@tonic-gate rval = ENOTSUP; 1968*0Sstevel@tonic-gate } 1969*0Sstevel@tonic-gate 1970*0Sstevel@tonic-gate if (rval == 0 && 1971*0Sstevel@tonic-gate (uqi->sm_ttycommon->t_flags & TS_XCLUDE) && 1972*0Sstevel@tonic-gate secpolicy_excl_open(credp) != 0) { 1973*0Sstevel@tonic-gate 1974*0Sstevel@tonic-gate if (uqi->sm_flags & FULLY_OPEN) { 1975*0Sstevel@tonic-gate rval = EBUSY; /* exclusive device already open */ 1976*0Sstevel@tonic-gate } else { 1977*0Sstevel@tonic-gate /* NB TS_XCLUDE cant be set during open so NOTREACHED */ 1978*0Sstevel@tonic-gate /* force any waiters to yield TS_XCLUDE */ 1979*0Sstevel@tonic-gate *abort_waiters = 1; 1980*0Sstevel@tonic-gate } 1981*0Sstevel@tonic-gate } 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gate if (rval == 0) 1984*0Sstevel@tonic-gate uqi->sm_protocol = proto; 1985*0Sstevel@tonic-gate 1986*0Sstevel@tonic-gate sm_dbg('A', ("ok_to_open (0x%p, %d) proto=%d rval %d (wabort=%d)", 1987*0Sstevel@tonic-gate uqi, protocol, uqi->sm_protocol, rval, *abort_waiters)); 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate return (rval); 1990*0Sstevel@tonic-gate } 1991*0Sstevel@tonic-gate 1992*0Sstevel@tonic-gate /* wait for memory to become available whilst performing a qwait */ 1993*0Sstevel@tonic-gate /*ARGSUSED*/ 1994*0Sstevel@tonic-gate static void dummy_callback(void *arg) 1995*0Sstevel@tonic-gate {} 1996*0Sstevel@tonic-gate 1997*0Sstevel@tonic-gate /* ARGSUSED */ 1998*0Sstevel@tonic-gate static int 1999*0Sstevel@tonic-gate sm_dump_msg(queue_t *q, mblk_t *mp) 2000*0Sstevel@tonic-gate { 2001*0Sstevel@tonic-gate freemsg(mp); 2002*0Sstevel@tonic-gate return (0); 2003*0Sstevel@tonic-gate } 2004*0Sstevel@tonic-gate 2005*0Sstevel@tonic-gate /* 2006*0Sstevel@tonic-gate * Wait for a message to arrive - must be called with exclusive 2007*0Sstevel@tonic-gate * access at the outer perimiter. 2008*0Sstevel@tonic-gate */ 2009*0Sstevel@tonic-gate static int 2010*0Sstevel@tonic-gate sm_qwait_sig(sm_uqi_t *uqi, queue_t *q) 2011*0Sstevel@tonic-gate { 2012*0Sstevel@tonic-gate int err; 2013*0Sstevel@tonic-gate 2014*0Sstevel@tonic-gate sm_dbg('C', ("sm_qwait_sig: waiting.\n")); 2015*0Sstevel@tonic-gate 2016*0Sstevel@tonic-gate uqi->sm_waitq = q; 2017*0Sstevel@tonic-gate uqi->sm_nwaiters++; /* required by the close routine */ 2018*0Sstevel@tonic-gate err = qwait_sig(q); 2019*0Sstevel@tonic-gate if (--uqi->sm_nwaiters == 0) 2020*0Sstevel@tonic-gate uqi->sm_waitq = 0; 2021*0Sstevel@tonic-gate 2022*0Sstevel@tonic-gate if (err == 0) 2023*0Sstevel@tonic-gate err = EINTR; 2024*0Sstevel@tonic-gate else if (q->q_ptr == 0) /* can happen if there are multiple waiters */ 2025*0Sstevel@tonic-gate err = -1; 2026*0Sstevel@tonic-gate else if (uqi->sm_flags & SM_CLOSE) { 2027*0Sstevel@tonic-gate uqi->sm_flags &= ~SM_CLOSE; 2028*0Sstevel@tonic-gate err = 1; /* a different protocol has closed its stream */ 2029*0Sstevel@tonic-gate } 2030*0Sstevel@tonic-gate else 2031*0Sstevel@tonic-gate err = 0; /* was worth waiting for */ 2032*0Sstevel@tonic-gate 2033*0Sstevel@tonic-gate sm_dbg('C', ("sm_qwait_sig: rval %d\n", err)); 2034*0Sstevel@tonic-gate return (err); 2035*0Sstevel@tonic-gate } 2036*0Sstevel@tonic-gate 2037*0Sstevel@tonic-gate /* 2038*0Sstevel@tonic-gate * Defer the opening of one the drivers devices until the state of each 2039*0Sstevel@tonic-gate * associated lower stream is known. 2040*0Sstevel@tonic-gate */ 2041*0Sstevel@tonic-gate static int 2042*0Sstevel@tonic-gate sm_defer_open(sm_uqi_t *uqi, queue_t *q) 2043*0Sstevel@tonic-gate { 2044*0Sstevel@tonic-gate uint_t cmdflags = WANT_CDSTAT; 2045*0Sstevel@tonic-gate int err, nqs; 2046*0Sstevel@tonic-gate 2047*0Sstevel@tonic-gate while ((nqs = sm_good_qs(uqi)) == 0) { 2048*0Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: no good qs\n")); 2049*0Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 2050*0Sstevel@tonic-gate return (err); 2051*0Sstevel@tonic-gate } 2052*0Sstevel@tonic-gate 2053*0Sstevel@tonic-gate while ((uqi->sm_flags & SM_CARON) == 0) { 2054*0Sstevel@tonic-gate int iocmd; 2055*0Sstevel@tonic-gate mblk_t *pioc; 2056*0Sstevel@tonic-gate 2057*0Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: flags 0x%x cmdflags 0x%x\n", 2058*0Sstevel@tonic-gate uqi->sm_flags, cmdflags)); 2059*0Sstevel@tonic-gate if (cmdflags == 0) { 2060*0Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 2061*0Sstevel@tonic-gate return (err); 2062*0Sstevel@tonic-gate continue; /* waiting for an M_UNHANGUP */ 2063*0Sstevel@tonic-gate } else if (cmdflags & WANT_SC) { 2064*0Sstevel@tonic-gate cmdflags &= ~WANT_SC; 2065*0Sstevel@tonic-gate iocmd = TIOCGSOFTCAR; 2066*0Sstevel@tonic-gate } else if (cmdflags & WANT_CD) { 2067*0Sstevel@tonic-gate cmdflags &= ~WANT_CD; 2068*0Sstevel@tonic-gate iocmd = TIOCMGET; 2069*0Sstevel@tonic-gate } else if (cmdflags & WANT_CL) { 2070*0Sstevel@tonic-gate cmdflags &= ~WANT_CL; 2071*0Sstevel@tonic-gate iocmd = TCGETS; 2072*0Sstevel@tonic-gate } 2073*0Sstevel@tonic-gate 2074*0Sstevel@tonic-gate if (uqi->sm_piocdata.sm_iocid == 0) { 2075*0Sstevel@tonic-gate while ((pioc = mkiocb(iocmd)) == 0) { 2076*0Sstevel@tonic-gate bufcall_id_t id = 2077*0Sstevel@tonic-gate qbufcall(q, sizeof (struct iocblk), 2078*0Sstevel@tonic-gate BPRI_MED, dummy_callback, 0); 2079*0Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) { 2080*0Sstevel@tonic-gate /* wait for the bufcall */ 2081*0Sstevel@tonic-gate qunbufcall(q, id); 2082*0Sstevel@tonic-gate return (err); 2083*0Sstevel@tonic-gate } 2084*0Sstevel@tonic-gate qunbufcall(q, id); 2085*0Sstevel@tonic-gate } 2086*0Sstevel@tonic-gate 2087*0Sstevel@tonic-gate uqi->sm_flags |= SM_IOCPENDING; 2088*0Sstevel@tonic-gate 2089*0Sstevel@tonic-gate uqi->sm_piocdata.sm_iocid = 2090*0Sstevel@tonic-gate ((struct iocblk *)pioc->b_rptr)->ioc_id; 2091*0Sstevel@tonic-gate uqi->sm_piocdata.sm_acked = 0; 2092*0Sstevel@tonic-gate uqi->sm_piocdata.sm_nacks = nqs; 2093*0Sstevel@tonic-gate uqi->sm_piocdata.sm_acnt = 0; 2094*0Sstevel@tonic-gate uqi->sm_piocdata.sm_ackcnt = uqi-> 2095*0Sstevel@tonic-gate sm_piocdata.sm_nakcnt = 0; 2096*0Sstevel@tonic-gate uqi->sm_piocdata.sm_policy = uqi->sm_policy; 2097*0Sstevel@tonic-gate uqi->sm_piocdata.sm_flags = SM_INTERNALIOC; 2098*0Sstevel@tonic-gate if (sm_putqs(WR(q), pioc, sm_dump_msg) != 0) { 2099*0Sstevel@tonic-gate uqi->sm_piocdata.sm_iocid = 0; 2100*0Sstevel@tonic-gate sm_log("sm_defer_open: bad putqs\n"); 2101*0Sstevel@tonic-gate return (-1); 2102*0Sstevel@tonic-gate } 2103*0Sstevel@tonic-gate } 2104*0Sstevel@tonic-gate 2105*0Sstevel@tonic-gate sm_dbg('C', ("sm_defer_open: flags 0x%x\n", uqi->sm_flags)); 2106*0Sstevel@tonic-gate while ((uqi->sm_flags & SM_CARON) == 0 && 2107*0Sstevel@tonic-gate (uqi->sm_flags & SM_IOCPENDING) != 0) 2108*0Sstevel@tonic-gate if (err = sm_qwait_sig(uqi, q)) 2109*0Sstevel@tonic-gate return (err); 2110*0Sstevel@tonic-gate 2111*0Sstevel@tonic-gate sm_dbg('C', ("defer_open: uq flags 0x%x.\n", uqi->sm_flags)); 2112*0Sstevel@tonic-gate } 2113*0Sstevel@tonic-gate sm_dbg('C', ("defer_open: return 0.\n")); 2114*0Sstevel@tonic-gate return (0); 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate 2117*0Sstevel@tonic-gate static int 2118*0Sstevel@tonic-gate sm_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 2119*0Sstevel@tonic-gate { 2120*0Sstevel@tonic-gate int ftstat; 2121*0Sstevel@tonic-gate int unit; 2122*0Sstevel@tonic-gate int protocol; 2123*0Sstevel@tonic-gate sm_uqi_t *uqi; 2124*0Sstevel@tonic-gate int abort_waiters; 2125*0Sstevel@tonic-gate 2126*0Sstevel@tonic-gate if (sm_ssp == NULL) 2127*0Sstevel@tonic-gate return (ENXIO); 2128*0Sstevel@tonic-gate /* 2129*0Sstevel@tonic-gate * sflag = 0 => streams device. 2130*0Sstevel@tonic-gate */ 2131*0Sstevel@tonic-gate if (sflag != 0 || DEV_TO_UNIT(*devp) >= NLUNITS) { 2132*0Sstevel@tonic-gate sm_dbg('C', ("open: sflag=%d or bad dev_t.\n", sflag)); 2133*0Sstevel@tonic-gate return (ENXIO); 2134*0Sstevel@tonic-gate } 2135*0Sstevel@tonic-gate 2136*0Sstevel@tonic-gate unit = DEV_TO_UNIT(*devp); 2137*0Sstevel@tonic-gate protocol = DEV_TO_PROTOBITS(*devp); 2138*0Sstevel@tonic-gate 2139*0Sstevel@tonic-gate uqi = get_uqi(sm_ssp, unit); 2140*0Sstevel@tonic-gate 2141*0Sstevel@tonic-gate sm_dbg('C', ("open(0x%p, %d, 0x%x) :- unit=%d, proto=%d, uqi=0x%p\n", 2142*0Sstevel@tonic-gate rq, *devp, flag, unit, protocol, uqi)); 2143*0Sstevel@tonic-gate 2144*0Sstevel@tonic-gate if (uqi == 0) 2145*0Sstevel@tonic-gate return (ENXIO); 2146*0Sstevel@tonic-gate 2147*0Sstevel@tonic-gate if (sm_refuse_opens && unit > smctlunit && uqi->sm_nlqs == 0) 2148*0Sstevel@tonic-gate return (ENXIO); 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate if (uqi->sm_flags & EXCL_OPEN && (flag & FEXCL)) { 2151*0Sstevel@tonic-gate return (EBUSY); /* device in use */ 2152*0Sstevel@tonic-gate } 2153*0Sstevel@tonic-gate 2154*0Sstevel@tonic-gate if ((flag & FEXCL)) { 2155*0Sstevel@tonic-gate if (secpolicy_excl_open(credp) != 0) 2156*0Sstevel@tonic-gate return (EPERM); 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) || uqi->sm_nwaiters > 0) 2159*0Sstevel@tonic-gate return (EBUSY); /* device in use */ 2160*0Sstevel@tonic-gate 2161*0Sstevel@tonic-gate uqi->sm_flags |= EXCL_OPEN; 2162*0Sstevel@tonic-gate } 2163*0Sstevel@tonic-gate 2164*0Sstevel@tonic-gate if (uqi->sm_protocol == NULL_PROTOCOL) { 2165*0Sstevel@tonic-gate struct termios *termiosp; 2166*0Sstevel@tonic-gate int len; 2167*0Sstevel@tonic-gate 2168*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 2169*0Sstevel@tonic-gate DDI_PROP_NOTPROM, "ttymodes", (caddr_t)&termiosp, &len) 2170*0Sstevel@tonic-gate == DDI_PROP_SUCCESS && 2171*0Sstevel@tonic-gate (len == sizeof (struct termios))) { 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate sm_dbg('C', ("open: c_cflag=0x%x\n", 2174*0Sstevel@tonic-gate termiosp->c_cflag)); 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate uqi->sm_ttycommon->t_iflag = termiosp->c_iflag; 2177*0Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = termiosp->c_cflag; 2178*0Sstevel@tonic-gate uqi->sm_ttycommon->t_stopc = termiosp->c_cc[VSTOP]; 2179*0Sstevel@tonic-gate uqi->sm_ttycommon->t_startc = termiosp->c_cc[VSTART]; 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate /* 2182*0Sstevel@tonic-gate * IGNBRK,BRKINT,INPCK,IXON,IXANY,IXOFF - drivers 2183*0Sstevel@tonic-gate * PARMRK,IGNPAR,ISTRIP - how to report parity 2184*0Sstevel@tonic-gate * INLCR,IGNCR,ICRNL,IUCLC - ldterm (sophisticated I/O) 2185*0Sstevel@tonic-gate * IXON, IXANY, IXOFF - flow control input 2186*0Sstevel@tonic-gate * CBAUD,CSIZE,CS5-8,CSTOPB,PARENB,PARODD,HUPCL, 2187*0Sstevel@tonic-gate * RCV1EN,XMT1EN,LOBLK,XCLUDE,CRTSXOFF,CRTSCTS, 2188*0Sstevel@tonic-gate * CIBAUD,PAREXT,CBAUDEXT,CIBAUDEXT,CREAD,CLOCAL 2189*0Sstevel@tonic-gate */ 2190*0Sstevel@tonic-gate 2191*0Sstevel@tonic-gate kmem_free(termiosp, len); 2192*0Sstevel@tonic-gate } 2193*0Sstevel@tonic-gate else 2194*0Sstevel@tonic-gate bzero((caddr_t)uqi->sm_ttycommon, 2195*0Sstevel@tonic-gate sizeof (uqi->sm_ttycommon)); 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate if (*devp == rconsdev) { 2198*0Sstevel@tonic-gate uqi->sm_cmask = sm_cmask; 2199*0Sstevel@tonic-gate uqi->sm_ttycommon->t_flags |= TS_SOFTCAR; 2200*0Sstevel@tonic-gate } else { 2201*0Sstevel@tonic-gate uqi->sm_ttycommon->t_flags &= ~TS_SOFTCAR; 2202*0Sstevel@tonic-gate } 2203*0Sstevel@tonic-gate 2204*0Sstevel@tonic-gate /* 2205*0Sstevel@tonic-gate * Clear the default CLOCAL and TS_SOFTCAR flags since 2206*0Sstevel@tonic-gate * they must correspond to the settings on the real devices. 2207*0Sstevel@tonic-gate */ 2208*0Sstevel@tonic-gate 2209*0Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag &= ~(uqi->sm_cmask|CLOCAL); 2210*0Sstevel@tonic-gate uqi->sm_mbits = 0; 2211*0Sstevel@tonic-gate uqi->sm_policy = FIRSTACK; 2212*0Sstevel@tonic-gate if (unit == 0 && sm_ssp->sm_ms == 0) 2213*0Sstevel@tonic-gate sm_ssp->sm_ms = (sm_mux_state_t *) 2214*0Sstevel@tonic-gate space_fetch(TTYMUXPTR); 2215*0Sstevel@tonic-gate if (sm_ssp->sm_ms) { 2216*0Sstevel@tonic-gate if (sm_ssp->sm_ms->sm_cons_stdin.sm_dev == *devp || 2217*0Sstevel@tonic-gate sm_ssp->sm_ms->sm_cons_stdout.sm_dev == *devp) 2218*0Sstevel@tonic-gate sm_ssp->sm_lconsole = uqi; 2219*0Sstevel@tonic-gate } 2220*0Sstevel@tonic-gate } 2221*0Sstevel@tonic-gate 2222*0Sstevel@tonic-gate /* 2223*0Sstevel@tonic-gate * Does this thread need to wait? 2224*0Sstevel@tonic-gate */ 2225*0Sstevel@tonic-gate 2226*0Sstevel@tonic-gate sm_dbg('C', ("sm_open: %d %d 0x%p 0x%x\n", 2227*0Sstevel@tonic-gate !(flag & (FNDELAY|FNONBLOCK)), !(protocol == OUTLINE), uqi->sm_lqs, 2228*0Sstevel@tonic-gate uqi->sm_flags)); 2229*0Sstevel@tonic-gate 2230*0Sstevel@tonic-gate tryopen: 2231*0Sstevel@tonic-gate 2232*0Sstevel@tonic-gate abort_waiters = 0; 2233*0Sstevel@tonic-gate if (ftstat = sm_ok_to_open(uqi, protocol, credp, &abort_waiters)) { 2234*0Sstevel@tonic-gate sm_dbg('C', ("open failed stat=%d.\n", ftstat)); 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0 && uqi->sm_nwaiters == 0) 2237*0Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 2238*0Sstevel@tonic-gate if (flag & FEXCL) 2239*0Sstevel@tonic-gate uqi->sm_flags &= ~EXCL_OPEN; 2240*0Sstevel@tonic-gate return (ftstat); 2241*0Sstevel@tonic-gate } 2242*0Sstevel@tonic-gate 2243*0Sstevel@tonic-gate if (abort_waiters) { 2244*0Sstevel@tonic-gate uqi->sm_dev = *devp; 2245*0Sstevel@tonic-gate /* different device wants to use the unit */ 2246*0Sstevel@tonic-gate SM_RQ(uqi) = rq; 2247*0Sstevel@tonic-gate SM_WQ(uqi) = WR(rq); 2248*0Sstevel@tonic-gate } 2249*0Sstevel@tonic-gate if (rq->q_ptr == 0) { 2250*0Sstevel@tonic-gate sm_lqi_t *lqi; 2251*0Sstevel@tonic-gate 2252*0Sstevel@tonic-gate uqi->sm_dev = *devp; 2253*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = uqi; 2254*0Sstevel@tonic-gate SM_RQ(uqi) = rq; 2255*0Sstevel@tonic-gate SM_WQ(uqi) = WR(rq); 2256*0Sstevel@tonic-gate qprocson(rq); 2257*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 2258*0Sstevel@tonic-gate LOCK_UNIT(lqi); 2259*0Sstevel@tonic-gate lqi->sm_uqflags |= SM_UQVALID; 2260*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate sm_dbg('C', ("sm_open: SM_UQVALID set on lqs.\n")); 2264*0Sstevel@tonic-gate } 2265*0Sstevel@tonic-gate 2266*0Sstevel@tonic-gate if (*devp != rconsdev && BLOCKING(uqi, protocol, flag)) { 2267*0Sstevel@tonic-gate 2268*0Sstevel@tonic-gate uqi->sm_flags |= WANT_CDSTAT; 2269*0Sstevel@tonic-gate 2270*0Sstevel@tonic-gate do { 2271*0Sstevel@tonic-gate /* 2272*0Sstevel@tonic-gate * Wait for notifications of changes in the CLOCAL 2273*0Sstevel@tonic-gate * and TS_SOFTCAR flags and a TIOCM_CD flag of a 2274*0Sstevel@tonic-gate * TIOCMGET request (come in on the write side queue). 2275*0Sstevel@tonic-gate */ 2276*0Sstevel@tonic-gate 2277*0Sstevel@tonic-gate if ((ftstat = sm_defer_open(uqi, rq)) != EINTR) { 2278*0Sstevel@tonic-gate if (ftstat) { 2279*0Sstevel@tonic-gate goto tryopen; 2280*0Sstevel@tonic-gate } else { 2281*0Sstevel@tonic-gate continue; 2282*0Sstevel@tonic-gate } 2283*0Sstevel@tonic-gate } 2284*0Sstevel@tonic-gate 2285*0Sstevel@tonic-gate if (uqi->sm_nwaiters == 0) { /* clean up */ 2286*0Sstevel@tonic-gate /* 2287*0Sstevel@tonic-gate * only opens on an asynchronous 2288*0Sstevel@tonic-gate * protocols reach here so checking 2289*0Sstevel@tonic-gate * nwaiters == 0 is sufficient to 2290*0Sstevel@tonic-gate * ensure that no other thread 2291*0Sstevel@tonic-gate * is waiting on this logical unit 2292*0Sstevel@tonic-gate */ 2293*0Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0) { 2294*0Sstevel@tonic-gate 2295*0Sstevel@tonic-gate sm_lqi_t *lqi; 2296*0Sstevel@tonic-gate 2297*0Sstevel@tonic-gate uqi->sm_dev = NODEV; 2298*0Sstevel@tonic-gate sm_dbg('C', ("sm_open FULLY_OPEN=0\n")); 2299*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; 2300*0Sstevel@tonic-gate lqi = lqi->sm_nlqi) { 2301*0Sstevel@tonic-gate LOCK_UNIT(lqi); 2302*0Sstevel@tonic-gate lqi->sm_uqflags &= ~SM_UQVALID; 2303*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 2304*0Sstevel@tonic-gate } 2305*0Sstevel@tonic-gate 2306*0Sstevel@tonic-gate qprocsoff(rq); 2307*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = 0; 2308*0Sstevel@tonic-gate SM_RQ(uqi) = 0; 2309*0Sstevel@tonic-gate SM_WQ(uqi) = 0; 2310*0Sstevel@tonic-gate } 2311*0Sstevel@tonic-gate } 2312*0Sstevel@tonic-gate if ((uqi->sm_flags & FULLY_OPEN) == 0 && 2313*0Sstevel@tonic-gate uqi->sm_nwaiters == 0) 2314*0Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 2315*0Sstevel@tonic-gate if (flag & FEXCL) 2316*0Sstevel@tonic-gate uqi->sm_flags &= ~EXCL_OPEN; 2317*0Sstevel@tonic-gate sm_dbg('C', ("sm_open: done (ret %d).\n", ftstat)); 2318*0Sstevel@tonic-gate return (ftstat); 2319*0Sstevel@tonic-gate } while (BLOCKING(uqi, protocol, flag)); 2320*0Sstevel@tonic-gate } 2321*0Sstevel@tonic-gate 2322*0Sstevel@tonic-gate uqi->sm_flags |= FULLY_OPEN; 2323*0Sstevel@tonic-gate 2324*0Sstevel@tonic-gate sm_dbg('C', ("sm_open done (ret %d).\n", ftstat)); 2325*0Sstevel@tonic-gate return (ftstat); 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate /* 2329*0Sstevel@tonic-gate * Multiplexer device close routine. 2330*0Sstevel@tonic-gate */ 2331*0Sstevel@tonic-gate /*ARGSUSED*/ 2332*0Sstevel@tonic-gate static int 2333*0Sstevel@tonic-gate sm_close(queue_t *rq, int flag, cred_t *credp) 2334*0Sstevel@tonic-gate { 2335*0Sstevel@tonic-gate sm_uqi_t *uqi = (sm_uqi_t *)rq->q_ptr; 2336*0Sstevel@tonic-gate sm_lqi_t *lqi; 2337*0Sstevel@tonic-gate 2338*0Sstevel@tonic-gate if (sm_ssp == NULL) 2339*0Sstevel@tonic-gate return (ENXIO); 2340*0Sstevel@tonic-gate 2341*0Sstevel@tonic-gate if (uqi == NULL) { 2342*0Sstevel@tonic-gate sm_dbg('C', ("close: WARN:- q 0x%p already closed.\n", rq)); 2343*0Sstevel@tonic-gate return (ENXIO); 2344*0Sstevel@tonic-gate } 2345*0Sstevel@tonic-gate 2346*0Sstevel@tonic-gate sm_dbg('C', ("close: uqi=0x%p unit=%d q=0x%p)\n", uqi, uqi->sm_lunit, 2347*0Sstevel@tonic-gate rq)); 2348*0Sstevel@tonic-gate 2349*0Sstevel@tonic-gate if (SM_RQ(uqi) != rq) 2350*0Sstevel@tonic-gate sm_dbg('C', ("sm_close: rq != current uqi queue\n")); 2351*0Sstevel@tonic-gate 2352*0Sstevel@tonic-gate if (uqi->sm_ttybid) { 2353*0Sstevel@tonic-gate qunbufcall(SM_RQ(uqi), uqi->sm_ttybid); 2354*0Sstevel@tonic-gate uqi->sm_ttybid = 0; 2355*0Sstevel@tonic-gate } 2356*0Sstevel@tonic-gate 2357*0Sstevel@tonic-gate /* 2358*0Sstevel@tonic-gate * Tell all the linked queues that the upper queue has gone 2359*0Sstevel@tonic-gate * Note close will never get called on a stream while there is a 2360*0Sstevel@tonic-gate * thread blocked trying to open the same stream. 2361*0Sstevel@tonic-gate * If there is a blocked open on a different stream but on 2362*0Sstevel@tonic-gate * the same logical unit it will reset the lower queue flags. 2363*0Sstevel@tonic-gate */ 2364*0Sstevel@tonic-gate for (lqi = uqi->sm_lqs; lqi != 0; lqi = lqi->sm_nlqi) { 2365*0Sstevel@tonic-gate LOCK_UNIT(lqi); 2366*0Sstevel@tonic-gate lqi->sm_uqflags &= ~SM_UQVALID; 2367*0Sstevel@tonic-gate UNLOCK_UNIT(lqi); 2368*0Sstevel@tonic-gate } 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate /* 2371*0Sstevel@tonic-gate * Turn off the STREAMs queue processing for this queue. 2372*0Sstevel@tonic-gate */ 2373*0Sstevel@tonic-gate qprocsoff(rq); 2374*0Sstevel@tonic-gate 2375*0Sstevel@tonic-gate /* 2376*0Sstevel@tonic-gate * Similarly we will never get here if there is thread trying to 2377*0Sstevel@tonic-gate * open ths stream. 2378*0Sstevel@tonic-gate */ 2379*0Sstevel@tonic-gate LOCK_UNIT(uqi); 2380*0Sstevel@tonic-gate if (uqi->sm_waitq == 0) 2381*0Sstevel@tonic-gate uqi->sm_flags = (uqi->sm_flags & SM_OBPCNDEV) ? SM_OBPCNDEV : 2382*0Sstevel@tonic-gate 0U; 2383*0Sstevel@tonic-gate 2384*0Sstevel@tonic-gate uqi->sm_dev = NODEV; 2385*0Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 2386*0Sstevel@tonic-gate ttycommon_close(uqi->sm_ttycommon); 2387*0Sstevel@tonic-gate /* it just frees any pending ioctl */ 2388*0Sstevel@tonic-gate 2389*0Sstevel@tonic-gate uqi->sm_ttycommon->t_cflag = 0; 2390*0Sstevel@tonic-gate uqi->sm_ttycommon->t_flags = 0; 2391*0Sstevel@tonic-gate 2392*0Sstevel@tonic-gate /* 2393*0Sstevel@tonic-gate * Reset the queue pointers to NULL. 2394*0Sstevel@tonic-gate * If a thread is qwaiting in the open routine it will recheck 2395*0Sstevel@tonic-gate * the q_ptr. 2396*0Sstevel@tonic-gate */ 2397*0Sstevel@tonic-gate rq->q_ptr = NULL; 2398*0Sstevel@tonic-gate WR(rq)->q_ptr = NULL; 2399*0Sstevel@tonic-gate UNLOCK_UNIT(uqi); 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate if (sm_ssp->sm_lconsole == uqi) { 2402*0Sstevel@tonic-gate /* this will never be the outdial device closing */ 2403*0Sstevel@tonic-gate sm_ssp->sm_lconsole = 0; 2404*0Sstevel@tonic-gate } 2405*0Sstevel@tonic-gate /* 2406*0Sstevel@tonic-gate * If there is another thread waiting for this close then unblock 2407*0Sstevel@tonic-gate * the thread by putting a message on its read queue. 2408*0Sstevel@tonic-gate */ 2409*0Sstevel@tonic-gate if (uqi->sm_waitq) { 2410*0Sstevel@tonic-gate sm_dbg('C', ("close(0x%p): doing putctl on 0x%p\n", 2411*0Sstevel@tonic-gate rq, uqi->sm_waitq)); 2412*0Sstevel@tonic-gate if (rq == uqi->sm_waitq) 2413*0Sstevel@tonic-gate sm_log("close: waitq and closeq are same q\n"); 2414*0Sstevel@tonic-gate (void) putctl(uqi->sm_waitq, M_CTL); 2415*0Sstevel@tonic-gate } 2416*0Sstevel@tonic-gate 2417*0Sstevel@tonic-gate uqi->sm_flags &= ~(EXCL_OPEN | FULLY_OPEN); 2418*0Sstevel@tonic-gate sm_dbg('C', ("close: returning ok.\n")); 2419*0Sstevel@tonic-gate return (0); 2420*0Sstevel@tonic-gate } 2421*0Sstevel@tonic-gate 2422*0Sstevel@tonic-gate /* 2423*0Sstevel@tonic-gate * Initialise the software abort sequence for use when one of the 2424*0Sstevel@tonic-gate * driver's nodes provides the system console. 2425*0Sstevel@tonic-gate */ 2426*0Sstevel@tonic-gate static void 2427*0Sstevel@tonic-gate sm_set_abort() 2428*0Sstevel@tonic-gate { 2429*0Sstevel@tonic-gate char ds[3] = { '\r', '~', CNTRL('b') }; 2430*0Sstevel@tonic-gate char as[SM_MAX_ABSLEN]; 2431*0Sstevel@tonic-gate int len = SM_MAX_ABSLEN; 2432*0Sstevel@tonic-gate 2433*0Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, sm_ssp->sm_dip, PROP_LEN_AND_VAL_BUF, 0, 2434*0Sstevel@tonic-gate "abort-str", as, &len) != DDI_PROP_SUCCESS || 2435*0Sstevel@tonic-gate (len = strlen(as)) < SM_MIN_ABSLEN) { 2436*0Sstevel@tonic-gate (void) strcpy(as, ds); 2437*0Sstevel@tonic-gate len = strlen(as); 2438*0Sstevel@tonic-gate } else { 2439*0Sstevel@tonic-gate char *s; 2440*0Sstevel@tonic-gate int i; 2441*0Sstevel@tonic-gate 2442*0Sstevel@tonic-gate for (s = as, i = 0; i < len-1; i++, s++) { 2443*0Sstevel@tonic-gate if (as[i] == '^' && as[i+1] >= 'a' && as[i+1] <= 'z') { 2444*0Sstevel@tonic-gate *s = as[i+1] - 'a' + 1; 2445*0Sstevel@tonic-gate i++; 2446*0Sstevel@tonic-gate } else { 2447*0Sstevel@tonic-gate *s = as[i]; 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate } 2450*0Sstevel@tonic-gate *s++ = as[i]; 2451*0Sstevel@tonic-gate *s = '\0'; 2452*0Sstevel@tonic-gate len = strlen(as); 2453*0Sstevel@tonic-gate } 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate if (len < SM_MIN_ABSLEN) 2456*0Sstevel@tonic-gate (void) strcpy(sm_ssp->sm_abs, ds); 2457*0Sstevel@tonic-gate else 2458*0Sstevel@tonic-gate (void) strcpy(sm_ssp->sm_abs, as); 2459*0Sstevel@tonic-gate } 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate /* 2462*0Sstevel@tonic-gate * 2463*0Sstevel@tonic-gate * sm_attach - initialisation routine per driver instance. 2464*0Sstevel@tonic-gate */ 2465*0Sstevel@tonic-gate static int 2466*0Sstevel@tonic-gate sm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2467*0Sstevel@tonic-gate { 2468*0Sstevel@tonic-gate int unit; 2469*0Sstevel@tonic-gate char name[32]; 2470*0Sstevel@tonic-gate sm_uqi_t *uqi; 2471*0Sstevel@tonic-gate sm_lqi_t *lqip; 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate /* 2474*0Sstevel@tonic-gate * Is this an attach? 2475*0Sstevel@tonic-gate */ 2476*0Sstevel@tonic-gate if (cmd != DDI_ATTACH) { 2477*0Sstevel@tonic-gate return (DDI_FAILURE); 2478*0Sstevel@tonic-gate } 2479*0Sstevel@tonic-gate 2480*0Sstevel@tonic-gate /* 2481*0Sstevel@tonic-gate * Validate the instance number (sm is a single instance driver). 2482*0Sstevel@tonic-gate */ 2483*0Sstevel@tonic-gate if (sm_ssp) { /* only one instance allowed */ 2484*0Sstevel@tonic-gate return (DDI_FAILURE); 2485*0Sstevel@tonic-gate } 2486*0Sstevel@tonic-gate 2487*0Sstevel@tonic-gate sm_instance = ddi_get_instance(dip); 2488*0Sstevel@tonic-gate 2489*0Sstevel@tonic-gate /* 2490*0Sstevel@tonic-gate * Create the default minor node which will become the console. 2491*0Sstevel@tonic-gate * (create it with three different names).: 2492*0Sstevel@tonic-gate * con which appears in the /dev filesystem; 2493*0Sstevel@tonic-gate * input which matches the prom /multiplexer:input node; 2494*0Sstevel@tonic-gate * output which matches the prom /multiplexer:input node 2495*0Sstevel@tonic-gate * Create a minor node for control operations. 2496*0Sstevel@tonic-gate */ 2497*0Sstevel@tonic-gate if (ddi_create_minor_node(dip, "con", S_IFCHR, 0, 2498*0Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 2499*0Sstevel@tonic-gate ddi_create_minor_node(dip, "input", S_IFCHR, 0, 2500*0Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 2501*0Sstevel@tonic-gate ddi_create_minor_node(dip, "output", S_IFCHR, 0, 2502*0Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS || 2503*0Sstevel@tonic-gate ddi_create_minor_node(dip, "ctl", S_IFCHR, 1, 2504*0Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS) { 2505*0Sstevel@tonic-gate 2506*0Sstevel@tonic-gate cmn_err(CE_WARN, "sm_attach: create minors failed.\n"); 2507*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2508*0Sstevel@tonic-gate return (DDI_FAILURE); 2509*0Sstevel@tonic-gate } 2510*0Sstevel@tonic-gate 2511*0Sstevel@tonic-gate smctlunit = 1; 2512*0Sstevel@tonic-gate 2513*0Sstevel@tonic-gate /* 2514*0Sstevel@tonic-gate * Allocate private state for this instance. 2515*0Sstevel@tonic-gate */ 2516*0Sstevel@tonic-gate sm_ssp = (sm_ss_t *)kmem_zalloc(sizeof (sm_ss_t), KM_SLEEP); 2517*0Sstevel@tonic-gate 2518*0Sstevel@tonic-gate /* 2519*0Sstevel@tonic-gate * Initialise per instance data. 2520*0Sstevel@tonic-gate */ 2521*0Sstevel@tonic-gate sm_ssp->sm_dip = dip; 2522*0Sstevel@tonic-gate 2523*0Sstevel@tonic-gate /* 2524*0Sstevel@tonic-gate * Get required debug level. 2525*0Sstevel@tonic-gate */ 2526*0Sstevel@tonic-gate sm_ssp->sm_trflag = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2527*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-trlv", sm_default_trflag); 2528*0Sstevel@tonic-gate 2529*0Sstevel@tonic-gate sm_max_units = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2530*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-max-units", sm_max_units); 2531*0Sstevel@tonic-gate sm_minor_cnt = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2532*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-minor-cnt", 0); 2533*0Sstevel@tonic-gate 2534*0Sstevel@tonic-gate sm_refuse_opens = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2535*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-refuse-opens", sm_refuse_opens); 2536*0Sstevel@tonic-gate 2537*0Sstevel@tonic-gate sm_ssp->sm_ctrla_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2538*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-ctrla-abort-on", 1); 2539*0Sstevel@tonic-gate sm_ssp->sm_break_abort_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 2540*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "sm-break-abort-on", 0); 2541*0Sstevel@tonic-gate 2542*0Sstevel@tonic-gate sm_set_abort(); 2543*0Sstevel@tonic-gate 2544*0Sstevel@tonic-gate sm_ssp->sm_lqs = (sm_lqi_t *)kmem_zalloc(sizeof (sm_lqi_t) * MAX_LQS, 2545*0Sstevel@tonic-gate KM_SLEEP); 2546*0Sstevel@tonic-gate sm_ssp->sm_uqs = (sm_uqi_t *)kmem_zalloc(sizeof (sm_uqi_t) * NLUNITS, 2547*0Sstevel@tonic-gate KM_SLEEP); 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate for (unit = 2; unit < NLUNITS && unit < sm_minor_cnt + 2; unit++) { 2550*0Sstevel@tonic-gate 2551*0Sstevel@tonic-gate if (snprintf(name, sizeof (name), "sm%c", 'a' + unit-2) > 2552*0Sstevel@tonic-gate sizeof (name)) { 2553*0Sstevel@tonic-gate cmn_err(CE_WARN, 2554*0Sstevel@tonic-gate "sm_attach: create device for unit %d failed.\n", 2555*0Sstevel@tonic-gate unit); 2556*0Sstevel@tonic-gate } else if (ddi_create_minor_node(dip, name, S_IFCHR, 2557*0Sstevel@tonic-gate unit, DDI_NT_SERIAL, NULL) != DDI_SUCCESS) { 2558*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2559*0Sstevel@tonic-gate return (DDI_FAILURE); 2560*0Sstevel@tonic-gate } 2561*0Sstevel@tonic-gate 2562*0Sstevel@tonic-gate if (snprintf(name, sizeof (name), "sm%c,cu", 'a' + unit-2) > 2563*0Sstevel@tonic-gate sizeof (name)) { 2564*0Sstevel@tonic-gate cmn_err(CE_WARN, 2565*0Sstevel@tonic-gate "sm_attach: create cu device for unit %d failed.\n", 2566*0Sstevel@tonic-gate unit); 2567*0Sstevel@tonic-gate continue; 2568*0Sstevel@tonic-gate } else if (ddi_create_minor_node(dip, name, S_IFCHR, 2569*0Sstevel@tonic-gate unit|OUTLINE, DDI_NT_SERIAL_DO, NULL) != DDI_SUCCESS) { 2570*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2571*0Sstevel@tonic-gate return (DDI_FAILURE); 2572*0Sstevel@tonic-gate } 2573*0Sstevel@tonic-gate } 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 2576*0Sstevel@tonic-gate 2577*0Sstevel@tonic-gate uqi = get_uqi(sm_ssp, unit); 2578*0Sstevel@tonic-gate uqi->sm_lqs = 0; 2579*0Sstevel@tonic-gate uqi->sm_dev = NODEV; 2580*0Sstevel@tonic-gate uqi->sm_nlqs = 0; 2581*0Sstevel@tonic-gate uqi->sm_lunit = unit; 2582*0Sstevel@tonic-gate uqi->sm_protocol = NULL_PROTOCOL; 2583*0Sstevel@tonic-gate mutex_init(uqi->sm_umutex, NULL, MUTEX_DRIVER, NULL); 2584*0Sstevel@tonic-gate cv_init(uqi->sm_ucv, NULL, CV_DRIVER, NULL); 2585*0Sstevel@tonic-gate mutex_init(&uqi->sm_ttycommon->t_excl, NULL, 2586*0Sstevel@tonic-gate MUTEX_DRIVER, NULL); 2587*0Sstevel@tonic-gate } 2588*0Sstevel@tonic-gate 2589*0Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 2590*0Sstevel@tonic-gate lqip = get_lqi(sm_ssp, unit); 2591*0Sstevel@tonic-gate lqip->sm_unit = unit; 2592*0Sstevel@tonic-gate lqip->sm_hadkadbchar = 0; 2593*0Sstevel@tonic-gate lqip->sm_nachar = sm_ssp->sm_abs; 2594*0Sstevel@tonic-gate lqip->sm_ioflag = FORIO; 2595*0Sstevel@tonic-gate lqip->sm_ctrla_abort_on = sm_ssp->sm_ctrla_abort_on; 2596*0Sstevel@tonic-gate lqip->sm_break_abort_on = sm_ssp->sm_break_abort_on; 2597*0Sstevel@tonic-gate mutex_init(lqip->sm_umutex, NULL, MUTEX_DRIVER, NULL); 2598*0Sstevel@tonic-gate cv_init(lqip->sm_ucv, NULL, CV_DRIVER, NULL); 2599*0Sstevel@tonic-gate mutex_init(&lqip->sm_ttycommon->t_excl, NULL, 2600*0Sstevel@tonic-gate MUTEX_DRIVER, NULL); 2601*0Sstevel@tonic-gate } 2602*0Sstevel@tonic-gate 2603*0Sstevel@tonic-gate return (DDI_SUCCESS); 2604*0Sstevel@tonic-gate } 2605*0Sstevel@tonic-gate 2606*0Sstevel@tonic-gate /* 2607*0Sstevel@tonic-gate * 2608*0Sstevel@tonic-gate * sm_detach - detach routine per driver instance. 2609*0Sstevel@tonic-gate */ 2610*0Sstevel@tonic-gate static int 2611*0Sstevel@tonic-gate sm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2612*0Sstevel@tonic-gate { 2613*0Sstevel@tonic-gate sm_uqi_t *lu; 2614*0Sstevel@tonic-gate sm_lqi_t *pu; 2615*0Sstevel@tonic-gate int unit; 2616*0Sstevel@tonic-gate 2617*0Sstevel@tonic-gate /* 2618*0Sstevel@tonic-gate * Is this a detach request for instance 0 (single instance driver). 2619*0Sstevel@tonic-gate */ 2620*0Sstevel@tonic-gate if (cmd != DDI_DETACH) 2621*0Sstevel@tonic-gate return (DDI_FAILURE); 2622*0Sstevel@tonic-gate 2623*0Sstevel@tonic-gate if (sm_ssp == NULL) 2624*0Sstevel@tonic-gate return (DDI_FAILURE); 2625*0Sstevel@tonic-gate 2626*0Sstevel@tonic-gate sm_dbg('V', ("detach ...")); 2627*0Sstevel@tonic-gate 2628*0Sstevel@tonic-gate 2629*0Sstevel@tonic-gate /* 2630*0Sstevel@tonic-gate * Check that all the upper and lower queues are closed. 2631*0Sstevel@tonic-gate */ 2632*0Sstevel@tonic-gate 2633*0Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 2634*0Sstevel@tonic-gate lu = &sm_ssp->sm_uqs[unit]; 2635*0Sstevel@tonic-gate if (lu && lu->sm_protocol != NULL_PROTOCOL) { 2636*0Sstevel@tonic-gate sm_dbg('V', ("detach: upper unit still open.\n")); 2637*0Sstevel@tonic-gate return (DDI_FAILURE); 2638*0Sstevel@tonic-gate } 2639*0Sstevel@tonic-gate } 2640*0Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 2641*0Sstevel@tonic-gate pu = &sm_ssp->sm_lqs[unit]; 2642*0Sstevel@tonic-gate if (pu && pu->sm_linkid != 0) { 2643*0Sstevel@tonic-gate sm_dbg('V', ("detach: lower unit still linked (%d)\n", 2644*0Sstevel@tonic-gate pu->sm_linkid)); 2645*0Sstevel@tonic-gate return (DDI_FAILURE); 2646*0Sstevel@tonic-gate } 2647*0Sstevel@tonic-gate } 2648*0Sstevel@tonic-gate 2649*0Sstevel@tonic-gate for (unit = 0; unit < NLUNITS; unit++) { 2650*0Sstevel@tonic-gate lu = &sm_ssp->sm_uqs[unit]; 2651*0Sstevel@tonic-gate mutex_destroy(lu->sm_umutex); 2652*0Sstevel@tonic-gate cv_destroy(lu->sm_ucv); 2653*0Sstevel@tonic-gate mutex_destroy(&lu->sm_ttycommon->t_excl); 2654*0Sstevel@tonic-gate } 2655*0Sstevel@tonic-gate for (unit = 0; unit < MAX_LQS; unit++) { 2656*0Sstevel@tonic-gate pu = &sm_ssp->sm_lqs[unit]; 2657*0Sstevel@tonic-gate mutex_destroy(pu->sm_umutex); 2658*0Sstevel@tonic-gate cv_destroy(pu->sm_ucv); 2659*0Sstevel@tonic-gate mutex_destroy(&pu->sm_ttycommon->t_excl); 2660*0Sstevel@tonic-gate } 2661*0Sstevel@tonic-gate 2662*0Sstevel@tonic-gate /* 2663*0Sstevel@tonic-gate * Tidy up per instance state. 2664*0Sstevel@tonic-gate */ 2665*0Sstevel@tonic-gate kmem_free(sm_ssp->sm_lqs, sizeof (sm_lqi_t) * MAX_LQS); 2666*0Sstevel@tonic-gate kmem_free(sm_ssp->sm_uqs, sizeof (sm_uqi_t) * NLUNITS); 2667*0Sstevel@tonic-gate kmem_free(sm_ssp, sizeof (sm_ss_t)); 2668*0Sstevel@tonic-gate 2669*0Sstevel@tonic-gate sm_ssp = 0; 2670*0Sstevel@tonic-gate 2671*0Sstevel@tonic-gate /* 2672*0Sstevel@tonic-gate * Remove all of the devices created in attach. 2673*0Sstevel@tonic-gate */ 2674*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2675*0Sstevel@tonic-gate 2676*0Sstevel@tonic-gate return (DDI_SUCCESS); 2677*0Sstevel@tonic-gate } 2678*0Sstevel@tonic-gate 2679*0Sstevel@tonic-gate /* 2680*0Sstevel@tonic-gate * SECTION 2681*0Sstevel@tonic-gate * Driver interface to the OS. 2682*0Sstevel@tonic-gate */ 2683*0Sstevel@tonic-gate 2684*0Sstevel@tonic-gate /* 2685*0Sstevel@tonic-gate * The driver is responsible for managing the mapping between the file system 2686*0Sstevel@tonic-gate * device types (major/minor pairs) and the corresponding instance of the driver 2687*0Sstevel@tonic-gate * or device information pointer (dip). 2688*0Sstevel@tonic-gate * sm_info - return the instance or dip corresponding to the dev_t. 2689*0Sstevel@tonic-gate */ 2690*0Sstevel@tonic-gate /*ARGSUSED*/ 2691*0Sstevel@tonic-gate static int 2692*0Sstevel@tonic-gate sm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2693*0Sstevel@tonic-gate { 2694*0Sstevel@tonic-gate int res = DDI_SUCCESS; 2695*0Sstevel@tonic-gate 2696*0Sstevel@tonic-gate switch (infocmd) { 2697*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2698*0Sstevel@tonic-gate if (sm_ssp == NULL) 2699*0Sstevel@tonic-gate res = DDI_FAILURE; 2700*0Sstevel@tonic-gate else 2701*0Sstevel@tonic-gate *result = (void *)sm_ssp->sm_dip; 2702*0Sstevel@tonic-gate break; 2703*0Sstevel@tonic-gate 2704*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2705*0Sstevel@tonic-gate *result = (void*)0; /* single instance driver */ 2706*0Sstevel@tonic-gate break; 2707*0Sstevel@tonic-gate 2708*0Sstevel@tonic-gate default: 2709*0Sstevel@tonic-gate res = DDI_FAILURE; 2710*0Sstevel@tonic-gate break; 2711*0Sstevel@tonic-gate } 2712*0Sstevel@tonic-gate 2713*0Sstevel@tonic-gate return (res); 2714*0Sstevel@tonic-gate } 2715*0Sstevel@tonic-gate 2716*0Sstevel@tonic-gate /* 2717*0Sstevel@tonic-gate * End of driver implementation 2718*0Sstevel@tonic-gate */ 2719*0Sstevel@tonic-gate 2720*0Sstevel@tonic-gate /* 2721*0Sstevel@tonic-gate * Loadable module interface to the kernel 2722*0Sstevel@tonic-gate */ 2723*0Sstevel@tonic-gate 2724*0Sstevel@tonic-gate /* 2725*0Sstevel@tonic-gate * Firstly the Streams specific interface 2726*0Sstevel@tonic-gate */ 2727*0Sstevel@tonic-gate 2728*0Sstevel@tonic-gate /* 2729*0Sstevel@tonic-gate * Solaris driver/STREAM initialisation structures. 2730*0Sstevel@tonic-gate */ 2731*0Sstevel@tonic-gate static struct module_info uinfo = 2732*0Sstevel@tonic-gate { 2733*0Sstevel@tonic-gate SM_MOD_ID, 2734*0Sstevel@tonic-gate TTYMUX_DRVNAME, 2735*0Sstevel@tonic-gate 0, /* min packet size */ 2736*0Sstevel@tonic-gate INFPSZ, /* max packet size */ 2737*0Sstevel@tonic-gate 2048, /* high water mark */ 2738*0Sstevel@tonic-gate 256, /* low water mark */ 2739*0Sstevel@tonic-gate }; 2740*0Sstevel@tonic-gate 2741*0Sstevel@tonic-gate /* 2742*0Sstevel@tonic-gate * Use zero water marks becuase the lower queues are used only for flow control. 2743*0Sstevel@tonic-gate */ 2744*0Sstevel@tonic-gate static struct module_info linfo = 2745*0Sstevel@tonic-gate { 2746*0Sstevel@tonic-gate SM_MOD_ID, 2747*0Sstevel@tonic-gate TTYMUX_DRVNAME, 2748*0Sstevel@tonic-gate 0, /* min packet size */ 2749*0Sstevel@tonic-gate INFPSZ, /* max packet size */ 2750*0Sstevel@tonic-gate 0, /* high water mark */ 2751*0Sstevel@tonic-gate 0 /* low water mark */ 2752*0Sstevel@tonic-gate }; 2753*0Sstevel@tonic-gate 2754*0Sstevel@tonic-gate 2755*0Sstevel@tonic-gate /* 2756*0Sstevel@tonic-gate * Solaris upper read STREAM initialisation structure. 2757*0Sstevel@tonic-gate */ 2758*0Sstevel@tonic-gate static struct qinit urinit = 2759*0Sstevel@tonic-gate { 2760*0Sstevel@tonic-gate sm_urput, /* put */ 2761*0Sstevel@tonic-gate sm_ursrv, /* service */ 2762*0Sstevel@tonic-gate sm_open, /* open */ 2763*0Sstevel@tonic-gate sm_close, /* close */ 2764*0Sstevel@tonic-gate NULL, /* admin */ 2765*0Sstevel@tonic-gate &uinfo, /* module info */ 2766*0Sstevel@tonic-gate NULL /* stats */ 2767*0Sstevel@tonic-gate }; 2768*0Sstevel@tonic-gate 2769*0Sstevel@tonic-gate /* 2770*0Sstevel@tonic-gate * Solaris upper write STREAM initialisation structure. 2771*0Sstevel@tonic-gate */ 2772*0Sstevel@tonic-gate static struct qinit uwinit = 2773*0Sstevel@tonic-gate { 2774*0Sstevel@tonic-gate sm_uwput, 2775*0Sstevel@tonic-gate sm_uwsrv, 2776*0Sstevel@tonic-gate NULL, 2777*0Sstevel@tonic-gate NULL, 2778*0Sstevel@tonic-gate NULL, 2779*0Sstevel@tonic-gate &uinfo, 2780*0Sstevel@tonic-gate NULL 2781*0Sstevel@tonic-gate }; 2782*0Sstevel@tonic-gate 2783*0Sstevel@tonic-gate /* 2784*0Sstevel@tonic-gate * Solaris lower read STREAM initialisation structure. 2785*0Sstevel@tonic-gate */ 2786*0Sstevel@tonic-gate static struct qinit lrinit = 2787*0Sstevel@tonic-gate { 2788*0Sstevel@tonic-gate sm_lrput, 2789*0Sstevel@tonic-gate sm_lrsrv, 2790*0Sstevel@tonic-gate NULL, 2791*0Sstevel@tonic-gate NULL, NULL, 2792*0Sstevel@tonic-gate &linfo, 2793*0Sstevel@tonic-gate NULL 2794*0Sstevel@tonic-gate }; 2795*0Sstevel@tonic-gate 2796*0Sstevel@tonic-gate /* 2797*0Sstevel@tonic-gate * Solaris lower write STREAM initialisation structure. 2798*0Sstevel@tonic-gate */ 2799*0Sstevel@tonic-gate static struct qinit lwinit = 2800*0Sstevel@tonic-gate { 2801*0Sstevel@tonic-gate putq, 2802*0Sstevel@tonic-gate sm_lwsrv, 2803*0Sstevel@tonic-gate NULL, 2804*0Sstevel@tonic-gate NULL, 2805*0Sstevel@tonic-gate NULL, 2806*0Sstevel@tonic-gate &linfo, 2807*0Sstevel@tonic-gate NULL 2808*0Sstevel@tonic-gate }; 2809*0Sstevel@tonic-gate 2810*0Sstevel@tonic-gate /* 2811*0Sstevel@tonic-gate * Multiplexing STREAM structure. 2812*0Sstevel@tonic-gate */ 2813*0Sstevel@tonic-gate struct streamtab sm_streamtab = 2814*0Sstevel@tonic-gate { 2815*0Sstevel@tonic-gate &urinit, 2816*0Sstevel@tonic-gate &uwinit, 2817*0Sstevel@tonic-gate &lrinit, 2818*0Sstevel@tonic-gate &lwinit 2819*0Sstevel@tonic-gate }; 2820*0Sstevel@tonic-gate 2821*0Sstevel@tonic-gate /* 2822*0Sstevel@tonic-gate * Driver operations structure (struct cb_ops) and 2823*0Sstevel@tonic-gate * driver dynamic loading functions (struct dev_ops). 2824*0Sstevel@tonic-gate */ 2825*0Sstevel@tonic-gate 2826*0Sstevel@tonic-gate /* 2827*0Sstevel@tonic-gate * Fold the Stream interface to the kernel into the driver interface 2828*0Sstevel@tonic-gate * to the OS. 2829*0Sstevel@tonic-gate */ 2830*0Sstevel@tonic-gate 2831*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(sm_ops, \ 2832*0Sstevel@tonic-gate nulldev, nulldev, \ 2833*0Sstevel@tonic-gate sm_attach, sm_detach, nodev, \ 2834*0Sstevel@tonic-gate sm_info, (D_NEW | D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL | D_MP), 2835*0Sstevel@tonic-gate &sm_streamtab); 2836*0Sstevel@tonic-gate 2837*0Sstevel@tonic-gate /* 2838*0Sstevel@tonic-gate * Driver module information. 2839*0Sstevel@tonic-gate */ 2840*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2841*0Sstevel@tonic-gate static struct modldrv modldrv = 2842*0Sstevel@tonic-gate { 2843*0Sstevel@tonic-gate &mod_driverops, 2844*0Sstevel@tonic-gate "serial mux driver %I%", 2845*0Sstevel@tonic-gate &sm_ops 2846*0Sstevel@tonic-gate }; 2847*0Sstevel@tonic-gate 2848*0Sstevel@tonic-gate static struct modlinkage modlinkage = 2849*0Sstevel@tonic-gate { 2850*0Sstevel@tonic-gate MODREV_1, 2851*0Sstevel@tonic-gate &modldrv, 2852*0Sstevel@tonic-gate NULL 2853*0Sstevel@tonic-gate }; 2854*0Sstevel@tonic-gate 2855*0Sstevel@tonic-gate /* 2856*0Sstevel@tonic-gate * Define the body of our interface to the OS. 2857*0Sstevel@tonic-gate */ 2858*0Sstevel@tonic-gate 2859*0Sstevel@tonic-gate /* 2860*0Sstevel@tonic-gate * '_init' is called by Solaris to initialise any driver 2861*0Sstevel@tonic-gate * specific state and to install the driver. 2862*0Sstevel@tonic-gate */ 2863*0Sstevel@tonic-gate int 2864*0Sstevel@tonic-gate _init(void) 2865*0Sstevel@tonic-gate { 2866*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 2867*0Sstevel@tonic-gate } 2868*0Sstevel@tonic-gate 2869*0Sstevel@tonic-gate /* 2870*0Sstevel@tonic-gate * _info - return this drivers interface to the kernel. 2871*0Sstevel@tonic-gate */ 2872*0Sstevel@tonic-gate int 2873*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 2874*0Sstevel@tonic-gate { 2875*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2876*0Sstevel@tonic-gate } 2877*0Sstevel@tonic-gate 2878*0Sstevel@tonic-gate /* 2879*0Sstevel@tonic-gate * _fini - the OS is finished with the services provided by the driver. 2880*0Sstevel@tonic-gate * remove ourself and then remove any footprint that remains. 2881*0Sstevel@tonic-gate */ 2882*0Sstevel@tonic-gate int 2883*0Sstevel@tonic-gate _fini(void) 2884*0Sstevel@tonic-gate { 2885*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 2886*0Sstevel@tonic-gate } 2887