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