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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * DESCRIPTION
30 *
31 * ttymux_ioctl - Handler for ttymux specific ioctl calls.
32 *
33 */
34
35 #include <sys/types.h>
36 #include <sys/strsubr.h>
37 #include <sys/strsun.h>
38 #include <sys/errno.h>
39 #include <sys/stat.h>
40 #include <sys/kmem.h>
41 #include <sys/ddi.h>
42 #include <sys/termio.h>
43 #include <sys/mkdev.h>
44 #include <sys/sunddi.h>
45 #include <sys/esunddi.h>
46 #include <sys/consdev.h>
47 #include <sys/promif.h>
48
49 #include <sys/ttymux.h>
50 #include "ttymux_impl.h"
51
52 /*
53 * Extern declarations
54 */
55 extern mblk_t *mkiocb(uint_t);
56 extern int nulldev();
57 extern uintptr_t space_fetch(char *key);
58 extern void prom_interpret(char *, uintptr_t, uintptr_t, uintptr_t,
59 uintptr_t, uintptr_t);
60
61 /*
62 * Imported ttymux routines
63 */
64 extern void sm_debug(char *, ...);
65 extern void sm_log(char *, ...);
66 extern sm_lqi_t *get_lqi_byid(int);
67 extern sm_lqi_t *get_lqi_bydevt(dev_t);
68 extern int sm_associate(int, sm_lqi_t *, ulong_t, uint_t, char *);
69 extern int sm_disassociate(int, sm_lqi_t *, ulong_t);
70
71 /*
72 * Exported ttymux routines
73 */
74 int ttymux_abort_ioctl(mblk_t *);
75 int ttymux_device_init(sm_lqi_t *);
76 int ttymux_device_fini(sm_lqi_t *);
77 int sm_ioctl_cmd(sm_uqi_t *, mblk_t *);
78
79 /*
80 * Imported ttymux variables
81 */
82 extern sm_ss_t *sm_ssp;
83
84 static int
mblk2assoc(mblk_t * mp,ttymux_assoc_t * assoc)85 mblk2assoc(mblk_t *mp, ttymux_assoc_t *assoc)
86 {
87 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
88
89 sm_dbg('M', ("mblk2assoc:\n"));
90 if (mp->b_cont == NULL)
91 return (EINVAL);
92
93 #ifdef _SYSCALL32_IMPL
94 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
95 ttymux_assoc32_t *assoc32;
96
97 sm_dbg('I', ("mblk2assoc: b_cont 0x%p count %d (sz %d)\n",
98 mp->b_cont, iobp->ioc_count, sizeof (*assoc32)));
99
100 if (iobp->ioc_count < sizeof (ttymux_assoc32_t))
101 return (EINVAL);
102
103 assoc32 = (ttymux_assoc32_t *)mp->b_cont->b_rptr;
104 assoc->ttymux_udev = expldev(assoc32->ttymux32_udev);
105 assoc->ttymux_ldev = expldev(assoc32->ttymux32_ldev);
106 assoc->ttymux_linkid = assoc32->ttymux32_linkid;
107 assoc->ttymux_tag = assoc32->ttymux32_tag;
108 assoc->ttymux_ioflag = assoc32->ttymux32_ioflag;
109 (void) strncpy(assoc->ttymux_path, assoc32->ttymux32_path,
110 MAXPATHLEN);
111
112 } else
113 #endif
114 if (iobp->ioc_count < sizeof (*assoc)) {
115 return (EINVAL);
116 } else {
117 *assoc = *(ttymux_assoc_t *)mp->b_cont->b_rptr;
118 }
119 sm_dbg('M', ("mblk2assoc (%d): dev %d:%d not found\n",
120 assoc->ttymux_linkid, getmajor(assoc->ttymux_ldev),
121 getminor(assoc->ttymux_ldev)));
122 return (0);
123 }
124
125 /*
126 * Given a device path return an OBP alias for it if it exists.
127 */
128 static char *
val2alias(pnode_t node,char * path)129 val2alias(pnode_t node, char *path)
130 {
131 char *buf1;
132 char *buf2;
133 char *propname, *propval;
134 int proplen;
135
136 if (node == OBP_BADNODE)
137 return (NULL);
138
139 sm_dbg('A', ("Looking for an alias for: %s (len %d)\n",
140 path, strlen(path)));
141
142 /*
143 * Ask for first property by passing a NULL string
144 */
145 buf1 = kmem_alloc(OBP_MAXPROPNAME, KM_SLEEP);
146 buf2 = kmem_zalloc(OBP_MAXPROPNAME, KM_SLEEP);
147 buf1[0] = '\0';
148
149 while (propname = (char *)prom_nextprop(node, buf1, buf2)) {
150 if (strlen(propname) == 0)
151 break; /* end of prop list */
152
153 (void) strcpy(buf1, propname);
154
155 proplen = prom_getproplen(node, propname);
156 if (proplen == 0)
157 continue;
158 propval = kmem_zalloc(proplen + 1, KM_SLEEP);
159 (void) prom_getprop(node, propname, propval);
160
161 if (strcmp(propval, path) == 0) {
162 kmem_free(propval, proplen + 1);
163 kmem_free(buf1, OBP_MAXPROPNAME);
164 sm_dbg('A', ("Alias is : %s\n", buf2));
165 return (buf2);
166 }
167
168 kmem_free(propval, proplen + 1);
169 bzero(buf2, OBP_MAXPROPNAME);
170 }
171
172 kmem_free(buf1, OBP_MAXPROPNAME);
173 kmem_free(buf2, OBP_MAXPROPNAME);
174
175 return (NULL);
176 }
177
178 /*
179 * Tell OBP that this device is now usable
180 */
181 static void
enable_device(sm_mux_state_t * ms,sm_console_t * cn)182 enable_device(sm_mux_state_t *ms, sm_console_t *cn)
183 {
184 char *enb_str = "\" enable-device\" rot $call-method";
185
186 if (!cn->sm_obp_con)
187 return;
188
189 sm_dbg('A', ("ttymux: enabling %d:%d\n",
190 getmajor(cn->sm_dev), getminor(cn->sm_dev)));
191
192 if (cn->sm_i_ihdl != 0)
193 prom_interpret(enb_str, (caddr32_t)ms->sm_cons_stdin.sm_i_ihdl,
194 (caddr32_t)cn->sm_i_ihdl, 0, 0, 0);
195
196 if (cn->sm_o_ihdl != 0 && cn->sm_o_ihdl != cn->sm_i_ihdl)
197 prom_interpret(enb_str, (caddr32_t)ms->sm_cons_stdout.sm_o_ihdl,
198 (caddr32_t)cn->sm_o_ihdl, 0, 0, 0);
199 }
200
201 /*
202 * Tell OBP that this device is no longer usable
203 */
204 static void
disable_device(sm_mux_state_t * ms,sm_console_t * cn)205 disable_device(sm_mux_state_t *ms, sm_console_t *cn)
206 {
207 char *dis_str = "\" disable-device\" rot $call-method";
208
209 if (!cn->sm_obp_con)
210 return;
211
212 sm_dbg('A', ("ttymux: disabling %d:%d\n",
213 getmajor(cn->sm_dev), getminor(cn->sm_dev)));
214
215 if (cn->sm_i_ihdl != 0)
216 prom_interpret(dis_str, (caddr32_t)ms->sm_cons_stdin.sm_i_ihdl,
217 (caddr32_t)cn->sm_i_ihdl, 0, 0, 0);
218 if (cn->sm_o_ihdl != 0 && cn->sm_o_ihdl != cn->sm_i_ihdl)
219 prom_interpret(dis_str, (caddr32_t)ms->sm_cons_stdout.sm_o_ihdl,
220 (caddr32_t)cn->sm_o_ihdl, 0, 0, 0);
221 }
222
223 static void
device_init_impl(sm_mux_state_t * ms,sm_console_t * cn,sm_lqi_t * plqi)224 device_init_impl(sm_mux_state_t *ms, sm_console_t *cn, sm_lqi_t *plqi)
225 {
226 uint_t flags = 0;
227 dev_info_t *ldip;
228
229 sm_dbg('I', ("device_init_impl:\n"));
230
231 if (plqi == NULL || cn == NULL)
232 return;
233
234 flags = (uint_t)cn->sm_mode;
235 sm_dbg('I', ("device_init_impl: flgs %d con %d\n", flags,
236 cn->sm_obp_con));
237 if (ldip = e_ddi_hold_devi_by_dev(cn->sm_dev, 0)) {
238
239 /*
240 * Indicate to the linked device that it is
241 * providing a multiplexed console.
242 */
243 if (flags & (uint_t)FORINPUT)
244 (void) e_ddi_prop_create(cn->sm_dev, ldip,
245 DDI_PROP_CANSLEEP, "obp-input-console", 0, 0);
246 if (flags & (uint_t)FOROUTPUT)
247 (void) e_ddi_prop_create(cn->sm_dev, ldip,
248 DDI_PROP_CANSLEEP, "obp-output-console", 0, 0);
249
250 ddi_release_devi(ldip);
251 }
252
253 if (flags) {
254 plqi->sm_ioflag = flags;
255 if (cn->sm_obp_con)
256 plqi->sm_uqflags |= SM_OBPCNDEV;
257 plqi->sm_ctrla_abort_on = sm_ssp->sm_ctrla_abort_on;
258 plqi->sm_break_abort_on = sm_ssp->sm_break_abort_on;
259 }
260
261 /*
262 * Tell OBP that its ok to use this console
263 */
264 enable_device(ms, cn);
265 }
266
267 static void
device_fini_impl(sm_mux_state_t * ms,sm_console_t * cn,sm_lqi_t * plqi)268 device_fini_impl(sm_mux_state_t *ms, sm_console_t *cn, sm_lqi_t *plqi)
269 {
270 dev_info_t *ldip;
271
272 if (plqi == NULL || cn == NULL)
273 return;
274 /*
275 * Indicate to the linked device that it is no longer
276 * providing a multiplexed console.
277 */
278 if (ldip = e_ddi_hold_devi_by_dev(plqi->sm_dev, 0)) {
279 if (plqi->sm_ioflag & (uint_t)FORINPUT)
280 (void) e_ddi_prop_remove(plqi->sm_dev,
281 ldip, "obp-input-console");
282 if (plqi->sm_ioflag & (uint_t)FOROUTPUT)
283 (void) e_ddi_prop_remove(plqi->sm_dev,
284 ldip, "obp-output-console");
285
286 ddi_release_devi(ldip);
287 }
288 plqi->sm_ioflag = 0;
289 plqi->sm_uqflags &= ~SM_OBPCNDEV;
290 disable_device(ms, cn);
291 }
292
293 static int
read_prop(pnode_t node,char * propname,char ** propval)294 read_prop(pnode_t node, char *propname, char **propval)
295 {
296 int proplen = prom_getproplen(node, propname);
297
298 if (proplen < 0)
299 return (proplen);
300 *propval = kmem_zalloc(proplen + 1, KM_SLEEP);
301 if (proplen > 0)
302 (void) prom_getprop(node, propname, *propval);
303 else
304 *propval = 0;
305
306 return (proplen);
307 }
308
309 /*
310 * Parse a list of tokens
311 */
312 static char *
sm_strtok_r(char * p,char * sep,char ** lasts)313 sm_strtok_r(char *p, char *sep, char **lasts)
314 {
315 char *e, *tok = NULL;
316
317 if (p == 0 || *p == 0)
318 return (NULL);
319
320 e = p + strlen(p);
321
322 do {
323 if (strchr(sep, *p) != NULL) {
324 if (tok != NULL) {
325 *p = 0;
326 *lasts = p + 1;
327 return (tok);
328 }
329 } else if (tok == NULL) {
330 tok = p;
331 }
332 } while (++p < e);
333
334 *lasts = NULL;
335 if (tok != NULL)
336 return (tok);
337 return (NULL);
338 }
339
340 /*
341 * Add or remove an alias from a property list of aliases:
342 * path: an OBP device path
343 * pname: property name containing a space separated list of aliases
344 * append: if true include the alias for path in the property list
345 * otherwise remove the alias from the list.
346 */
347 static int
upd_config(boolean_t append,char * pname,char * path)348 upd_config(boolean_t append, char *pname, char *path)
349 {
350 pnode_t onode, anode;
351 size_t plen; /* length of property name */
352 char *pval; /* value of property */
353 char *tok, *lasts;
354 char *aliases[TTYMUX_MAX_LINKS];
355 size_t i, cnt, len;
356 boolean_t found;
357 char *nval, *alias = NULL;
358
359 if ((anode = prom_alias_node()) == OBP_BADNODE ||
360 (onode = prom_optionsnode()) == OBP_BADNODE) {
361 sm_dbg('I', ("upd_config: no alias or options node.\n"));
362 return (1);
363 }
364
365 if ((plen = read_prop(onode, pname, &pval)) < 0)
366 return (1);
367
368 sm_dbg('I', ("upd_config: %s=%s (%s)\n", pname, pval, path));
369 found = B_FALSE;
370 for (len = 0, cnt = 0, tok = sm_strtok_r(pval, " \t", &lasts);
371 tok != NULL && cnt < TTYMUX_MAX_LINKS;
372 tok = sm_strtok_r(lasts, " \t", &lasts)) {
373 char *aval;
374 size_t alen;
375
376 if ((alen = read_prop(anode, tok, &aval)) < 0)
377 continue;
378
379 /* does this alias match the requested path */
380 if (strcmp(aval, path) == 0 ||
381 (strstr(path, aval) != NULL &&
382 strchr(aval, ':') == NULL && strchr(path, ':') != NULL &&
383 strcmp(strchr(path, ':'), ":a") == 0)) {
384 if (!found && append) {
385 kmem_free(aval, alen + 1);
386 goto out;
387 }
388 found = B_TRUE;
389 } else {
390 aliases[cnt++] = tok;
391 len += strlen(tok) + 1;
392 }
393 kmem_free(aval, alen + 1);
394 }
395
396 sm_dbg('I', ("%d aliases\n", cnt));
397 if (append) {
398 if (cnt + 1 == TTYMUX_MAX_LINKS)
399 goto out;
400
401 if ((alias = val2alias(anode, path)) == NULL) {
402 char *mnode = strstr(path, ":a");
403
404 if (mnode != 0) {
405 *mnode = '\0';
406 alias = val2alias(anode, path);
407 *mnode = ':';
408 }
409 }
410 if (alias == NULL) {
411 sm_dbg('I', ("No alias for %s\n", path));
412 goto out;
413 }
414 aliases[cnt++] = alias;
415 len += strlen(alias) + 1;
416 } else if (!found) {
417 goto out;
418 }
419
420 sm_dbg('I', ("%d aliases (len %d)\n", cnt, len));
421 if (len == 0)
422 goto out;
423 ASSERT(len > 1 && cnt > 0);
424
425 nval = kmem_zalloc(len, KM_SLEEP);
426 for (i = 0; ; ) {
427 ASSERT(strlen(nval) + strlen(aliases[i]) + 1 <= len);
428 sm_dbg('I', ("alias %s\n", aliases[i]));
429 (void) strcat(nval, aliases[i]);
430 if (++i == cnt)
431 break;
432 (void) strcat(nval, " ");
433 }
434
435 sm_dbg('I', ("setprop: %s=%s (%d)\n", pname, nval, len));
436
437 (void) prom_setprop(onode, pname, nval, len);
438
439 kmem_free(nval, len);
440
441 if (alias != NULL)
442 kmem_free(alias, OBP_MAXPROPNAME);
443 out:
444 sm_dbg('I', ("upd_config: returning.\n"));
445 kmem_free(pval, plen + 1);
446 return (0);
447 }
448
449 /*
450 *
451 */
452 static int
update_config(sm_mux_state_t * ms,char * path,io_mode_t mode,int cmd)453 update_config(sm_mux_state_t *ms, char *path, io_mode_t mode, int cmd)
454 {
455 sm_dbg('I', ("update_config: path %s io %d\n", path ? path : "", mode));
456 if (path == 0 || *path == 0) {
457 sm_dbg('I', ("update_config: EINVAL - no path\n"));
458 return (1);
459 }
460 if (prom_is_openprom() == 0)
461 return (0);
462
463 if ((mode & FORINPUT) && ms->sm_ialias != NULL)
464 (void) upd_config((cmd == TTYMUX_ASSOC), ms->sm_ialias, path);
465 if ((mode & FOROUTPUT) && ms->sm_oalias != NULL)
466 (void) upd_config((cmd == TTYMUX_ASSOC), ms->sm_oalias, path);
467 return (0);
468 }
469
470 /*
471 * Convert a dev_t to a device path
472 */
473 static char *
sm_di_path(dev_t dev)474 sm_di_path(dev_t dev)
475 {
476 char *p, *path;
477
478 if (dev == NODEV)
479 return (NULL);
480
481 p = kmem_zalloc(MAXPATHLEN + 1, KM_SLEEP);
482 if (ddi_dev_pathname(dev, S_IFCHR, p) == DDI_SUCCESS) {
483 path = kmem_alloc(strlen(p) + 1, KM_SLEEP);
484 (void) strcpy(path, p);
485 }
486 kmem_free(p, MAXPATHLEN + 1);
487
488 return (path);
489 }
490
491 static int
console_cmd(int cmd,ttymux_assoc_t * assoc)492 console_cmd(int cmd, ttymux_assoc_t *assoc)
493 {
494 sm_mux_state_t *ms;
495 sm_console_t *cn;
496 uint_t j;
497
498 sm_dbg('I', ("console_cmd ENTER: %s\n", cmd == TTYMUX_DISASSOC ?
499 "TTYMUX_DISASSOC" : "TTYMUX_ASSOC"));
500
501 if (assoc->ttymux_ldev == NODEV && *assoc->ttymux_path != '/') {
502 sm_lqi_t *lqi = get_lqi_byid(assoc->ttymux_linkid);
503 if (lqi == 0 || lqi->sm_dev == NODEV) {
504 sm_dbg('I', ("console_cmd: no id link %d cmd %d\n",
505 assoc->ttymux_linkid, cmd));
506 return (EINVAL);
507 }
508 assoc->ttymux_ldev = lqi->sm_dev;
509 }
510
511 sm_dbg('I', ("console_cmd: path %s\n", assoc->ttymux_path));
512
513 if ((ms = (sm_mux_state_t *)space_fetch(TTYMUXPTR)) == 0) {
514 sm_dbg('I', ("console_cmd: No muxstate\n"));
515 return (0);
516 }
517
518 mutex_enter(&ms->sm_cons_mutex);
519
520 for (cn = ms->sm_cons_links, j = 0;
521 j < ms->sm_cons_cnt; cn++, j++) {
522 if (assoc->ttymux_ldev != NODEV && assoc->ttymux_ldev ==
523 cn->sm_dev) {
524 break;
525 } else if (cn->sm_path != NULL &&
526 strncmp(cn->sm_path, assoc->ttymux_path, MAXPATHLEN) == 0) {
527 break;
528 }
529 }
530
531 assoc->ttymux_path[MAXPATHLEN - 1] = 0;
532 if (cmd == TTYMUX_DISASSOC) {
533 if (j == ms->sm_cons_cnt) {
534 mutex_exit(&ms->sm_cons_mutex);
535 return (0);
536 }
537
538 /*
539 * Disable the console in OBP and then delete this console
540 * this console - note that this also deletes OBP
541 * information - i.e. once it is disassociated it cannot
542 * be reused as an OBP console - roll on polled I/O!
543 */
544 sm_dbg('I', ("console_cmd: cleaning up\n"));
545 device_fini_impl(ms, cn, get_lqi_bydevt(assoc->ttymux_ldev));
546
547 if (cn->sm_path == NULL) {
548 if (assoc->ttymux_ldev != NODEV)
549 cn->sm_path = sm_di_path(assoc->ttymux_ldev);
550 else
551 (void) update_config(ms, assoc->ttymux_path,
552 assoc->ttymux_ioflag, cmd);
553 }
554 if (cn->sm_path) {
555 (void) update_config(ms, cn->sm_path, cn->sm_mode, cmd);
556 kmem_free(cn->sm_path, strlen(cn->sm_path) + 1);
557 cn->sm_path = NULL;
558 }
559 ms->sm_cons_cnt -= 1;
560 if (ms->sm_cons_cnt > 0)
561 *cn = ms->sm_cons_links[ms->sm_cons_cnt];
562
563 sm_dbg('I', ("console_cmd: console %d removed (cnt %d)\n",
564 j, ms->sm_cons_cnt));
565
566 } else if (cmd == TTYMUX_ASSOC) {
567
568 if (j == ms->sm_cons_cnt) {
569
570 if (j == TTYMUX_MAX_LINKS) {
571 mutex_exit(&ms->sm_cons_mutex);
572 return (ENOMEM);
573 }
574
575 ms->sm_cons_cnt += 1;
576
577 bzero((caddr_t)cn, sizeof (*cn));
578 cn->sm_dev = assoc->ttymux_ldev;
579 cn->sm_muxid = assoc->ttymux_linkid;
580 cn->sm_mode = assoc->ttymux_ioflag;
581 device_init_impl(ms, cn,
582 get_lqi_bydevt(assoc->ttymux_ldev));
583 } else {
584 cn->sm_dev = assoc->ttymux_ldev;
585 cn->sm_muxid = assoc->ttymux_linkid;
586 cn->sm_mode = assoc->ttymux_ioflag;
587 }
588
589 if (assoc->ttymux_ldev != NODEV) {
590 cn->sm_path = sm_di_path(assoc->ttymux_ldev);
591 } else {
592 cn->sm_path = kmem_alloc(strlen(assoc->ttymux_path) + 1,
593 KM_SLEEP);
594 (void) strcpy(cn->sm_path, assoc->ttymux_path);
595 }
596 if (cn->sm_path != NULL)
597 (void) update_config(ms, cn->sm_path, cn->sm_mode, cmd);
598 else
599 sm_dbg('I', ("console_cmd: ASSOC No path info"));
600 }
601 mutex_exit(&ms->sm_cons_mutex);
602 sm_dbg('I', ("console_cmd EXIT: %s\n", cmd == TTYMUX_DISASSOC ?
603 "TTYMUX_DISASSOC" : "TTYMUX_ASSOC"));
604 return (0);
605 }
606
607 static int
get_unconfigured_consoles(sm_mux_state_t * ms,ttymux_assoc_t * a)608 get_unconfigured_consoles(sm_mux_state_t *ms, ttymux_assoc_t *a)
609 {
610 sm_console_t *cn;
611 int j, cnt;
612
613 if (ms == 0)
614 return (0);
615
616 mutex_enter(&ms->sm_cons_mutex);
617 for (cn = ms->sm_cons_links, cnt = j = 0; j < ms->sm_cons_cnt;
618 cn++, j++) {
619 if (cn->sm_path && get_lqi_bydevt(cn->sm_dev) == NULL) {
620 a->ttymux_linkid = cn->sm_muxid;
621 a->ttymux_tag = (uint_t)0;
622 a->ttymux_ioflag = cn->sm_mode;
623 a->ttymux_udev = cn->sm_mode & FORINPUT ?
624 ms->sm_cons_stdin.sm_dev :
625 ms->sm_cons_stdout.sm_dev;
626 a->ttymux_ldev = NODEV;
627 (void) strncpy(a->ttymux_path, cn->sm_path, MAXPATHLEN);
628 cnt++;
629 a++;
630 }
631 }
632 mutex_exit(&ms->sm_cons_mutex);
633 return (cnt);
634 }
635
636 #ifdef _SYSCALL32_IMPL
637 /*
638 * Look for any consoles that are not currently plumbed under the multiplexer.
639 */
640 static int
get_unconfigured_consoles32(sm_mux_state_t * ms,ttymux_assoc32_t * a)641 get_unconfigured_consoles32(sm_mux_state_t *ms, ttymux_assoc32_t *a)
642 {
643 sm_console_t *cn;
644 int j, cnt;
645
646 if (ms == 0)
647 return (0);
648
649 mutex_enter(&ms->sm_cons_mutex);
650 for (cn = ms->sm_cons_links, cnt = j = 0; j < ms->sm_cons_cnt;
651 cn++, j++) {
652 sm_dbg('I', ("get_unconfigured_consoles: check %s (%d:%d)",
653 cn->sm_path ? cn->sm_path : "NULL",
654 getmajor(cn->sm_dev), getminor(cn->sm_dev)));
655 if (cn->sm_path && get_lqi_bydevt(cn->sm_dev) == NULL) {
656 a->ttymux32_linkid = 0;
657 a->ttymux32_tag = (uint32_t)0;
658 a->ttymux32_ioflag = (uint32_t)cn->sm_mode;
659 a->ttymux32_ldev = NODEV32;
660 (void) cmpldev(&a->ttymux32_udev, cn->sm_mode &
661 FORINPUT ? ms->sm_cons_stdin.sm_dev :
662 ms->sm_cons_stdout.sm_dev);
663
664 (void) strncpy(a->ttymux32_path, cn->sm_path,
665 MAXPATHLEN);
666 cnt++;
667 a++;
668 }
669 }
670 mutex_exit(&ms->sm_cons_mutex);
671 return (cnt);
672 }
673 #endif
674
675 static int
count_unconfigured_consoles(sm_mux_state_t * ms)676 count_unconfigured_consoles(sm_mux_state_t *ms)
677 {
678 sm_console_t *cn;
679 int j, cnt;
680
681 if (ms == 0)
682 return (0);
683
684 mutex_enter(&ms->sm_cons_mutex);
685 for (cn = ms->sm_cons_links, cnt = j = 0; j < ms->sm_cons_cnt;
686 cn++, j++) {
687 sm_dbg('I', ("cnt_unconfigured_consoles: check %s (%d:%d)",
688 cn->sm_path ? cn->sm_path : "NULL",
689 getmajor(cn->sm_dev), getminor(cn->sm_dev)));
690 if (cn->sm_path && get_lqi_bydevt(cn->sm_dev) == NULL)
691 cnt++;
692 }
693 mutex_exit(&ms->sm_cons_mutex);
694 return (cnt);
695 }
696
697 /*
698 * Exported interfaces
699 */
700
701 /*
702 * A console device is no longer associated.
703 */
704 int
ttymux_device_fini(sm_lqi_t * plqi)705 ttymux_device_fini(sm_lqi_t *plqi)
706 {
707 int j;
708 sm_mux_state_t *ms;
709
710 ms = (sm_mux_state_t *)space_fetch(TTYMUXPTR);
711
712 if (plqi == NULL || ms == NULL)
713 return (0);
714
715 mutex_enter(&ms->sm_cons_mutex);
716
717 for (j = 0; j < ms->sm_cons_cnt; j++) {
718
719 if (ms->sm_cons_links[j].sm_dev == plqi->sm_dev) {
720
721 device_fini_impl(ms, &ms->sm_cons_links[j], plqi);
722
723 mutex_exit(&ms->sm_cons_mutex);
724 return (0);
725 }
726 }
727 mutex_exit(&ms->sm_cons_mutex);
728
729 return (1);
730 }
731
732 /*
733 * A console device is being introduced.
734 */
735 int
ttymux_device_init(sm_lqi_t * plqi)736 ttymux_device_init(sm_lqi_t *plqi)
737 {
738 int j;
739 sm_mux_state_t *ms;
740
741 ms = (sm_mux_state_t *)space_fetch(TTYMUXPTR);
742
743 if (ms == NULL)
744 return (0);
745
746 mutex_enter(&ms->sm_cons_mutex);
747
748 for (j = 0; j < ms->sm_cons_cnt; j++) {
749
750 if (ms->sm_cons_links[j].sm_dev == plqi->sm_dev) {
751
752 device_init_impl(ms, &ms->sm_cons_links[j], plqi);
753
754 mutex_exit(&ms->sm_cons_mutex);
755 return (0);
756 }
757 }
758 mutex_exit(&ms->sm_cons_mutex);
759 return (1);
760 }
761
762 /*
763 * Process a TTYMUX_ASSOCIATE or TTYMUX_DISASSOCIATE ioctl.
764 */
765 static int
ttymux_link_ioctl(mblk_t * mp)766 ttymux_link_ioctl(mblk_t *mp)
767 {
768 ttymux_assoc_t assoc;
769 int err;
770 sm_lqi_t *lqi;
771 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
772 dev_t cidev, codev;
773
774 sm_dbg('I', ("ttymux_link_ioctl:\n"));
775 if ((err = mblk2assoc(mp, &assoc)) != 0)
776 return (err);
777
778 sm_dbg('I', ("uminor is %d\n", getminor(assoc.ttymux_udev)));
779
780 if (assoc.ttymux_udev == NODEV)
781 return (EINVAL);
782
783 err = 0;
784
785 if ((lqi = get_lqi_bydevt(assoc.ttymux_ldev)) == NULL) {
786 if (assoc.ttymux_linkid < 0)
787 err = EINVAL;
788 else if ((lqi = get_lqi_byid(assoc.ttymux_linkid)) == 0)
789 err = ENOLINK;
790 }
791
792 if (sm_ssp->sm_ms) {
793 mutex_enter(&sm_ssp->sm_ms->sm_cons_mutex);
794 cidev = sm_ssp->sm_ms->sm_cons_stdin.sm_dev;
795 codev = sm_ssp->sm_ms->sm_cons_stdout.sm_dev;
796 mutex_exit(&sm_ssp->sm_ms->sm_cons_mutex);
797 } else {
798 cidev = codev = NODEV;
799 }
800
801 if (err != 0) {
802 if (assoc.ttymux_udev != cidev && assoc.ttymux_udev != codev)
803 return (err);
804 (void) console_cmd(iobp->ioc_cmd, &assoc);
805 return (0);
806 } else if (assoc.ttymux_udev == cidev || assoc.ttymux_udev == codev) {
807 (void) console_cmd(iobp->ioc_cmd, &assoc);
808 }
809
810 if (iobp->ioc_cmd == TTYMUX_ASSOC)
811 return (sm_associate(sm_dev2unit(assoc.ttymux_udev),
812 lqi, assoc.ttymux_tag, assoc.ttymux_ioflag,
813 assoc.ttymux_path));
814 else if (iobp->ioc_cmd == TTYMUX_DISASSOC)
815 return (sm_disassociate(sm_dev2unit(assoc.ttymux_udev),
816 lqi, assoc.ttymux_tag));
817
818 return (0);
819 }
820
821 /*
822 * Process a TTYMUX_GETLINK ioctl.
823 */
824 int
ttymux_query_link_ioctl(mblk_t * mp)825 ttymux_query_link_ioctl(mblk_t *mp)
826 {
827 sm_lqi_t *lqi;
828
829 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
830
831 sm_dbg('I', ("ttymux_query_link_ioctl:\n"));
832
833 if (mp->b_cont == NULL)
834 return (EINVAL);
835
836 #ifdef _SYSCALL32_IMPL
837 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
838 ttymux_assoc32_t *assoc32;
839 ttymux_assoc_t assoc;
840
841 if (mblk2assoc(mp, &assoc) != 0)
842 return (EINVAL);
843
844 if ((lqi = get_lqi_bydevt(assoc.ttymux_ldev)) == NULL &&
845 (lqi = get_lqi_byid(assoc.ttymux_linkid)) == NULL) {
846 sm_dbg('M', ("Query Link (%d): dev %d:%d not found\n",
847 assoc.ttymux_linkid,
848 getmajor(assoc.ttymux_ldev),
849 getminor(assoc.ttymux_ldev)));
850 return (ENOLINK);
851 }
852 assoc32 = (ttymux_assoc32_t *)mp->b_cont->b_rptr;
853 LQI2ASSOC32(assoc32, lqi);
854 } else
855 #endif
856 {
857 ttymux_assoc_t *assoc;
858
859 if (iobp->ioc_count < sizeof (ttymux_assoc_t))
860 return (EINVAL);
861
862 assoc = (ttymux_assoc_t *)mp->b_cont->b_rptr;
863 if ((lqi = get_lqi_bydevt(assoc->ttymux_ldev)) == NULL &&
864 (lqi = get_lqi_byid(assoc->ttymux_linkid)) == NULL) {
865 return (ENOLINK);
866 }
867 LQI2ASSOC(assoc, lqi);
868 }
869 return (0);
870 }
871
872 /*
873 * Response to receiving an M_IOCDATA message for the TTYMUX_LIST ioctl.
874 */
875 static int
sm_iocresp(mblk_t * mp)876 sm_iocresp(mblk_t *mp)
877 {
878 struct copyresp *csp = (struct copyresp *)mp->b_rptr;
879 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
880 mblk_t *pmp;
881
882 sm_dbg('M', ("(M_IOCDATA: cmd %d)\n", csp->cp_cmd));
883
884 if (csp->cp_cmd != TTYMUX_LIST) {
885 sm_dbg('M', ("(M_IOCDATA: unknown cmd)\n"));
886 DB_TYPE(mp) = M_IOCNAK;
887 return (EINVAL);
888 }
889 if (csp->cp_rval) {
890 if (csp->cp_private)
891 freemsg((mblk_t *)csp->cp_private);
892
893 sm_dbg('M', ("M_IOCDATA: result is %d\n", csp->cp_rval));
894 DB_TYPE(mp) = M_IOCNAK;
895 iobp->ioc_error = (int)(uintptr_t)csp->cp_rval;
896 iobp->ioc_rval = 0;
897 return (iobp->ioc_error);
898 }
899
900 pmp = (mblk_t *)csp->cp_private;
901
902 #ifdef _SYSCALL32_IMPL
903 if ((csp->cp_flag & IOC_MODELS) != IOC_NATIVE) {
904 iobp->ioc_count = sizeof (ttymux_assocs32_t);
905 iobp->ioc_rval = pmp == NULL ? 0 :
906 ((ttymux_assocs32_t *)pmp->b_rptr)->ttymux32_nlinks;
907 } else
908 #endif
909 {
910 iobp->ioc_count = sizeof (ttymux_assocs_t);
911 iobp->ioc_rval = pmp == NULL ? 0 :
912 ((ttymux_assocs_t *)pmp->b_rptr)->ttymux_nlinks;
913
914 }
915
916 DB_TYPE(mp) = (pmp) ? M_IOCACK : M_IOCNAK;
917 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
918
919 if (mp->b_cont)
920 freemsg(unlinkb(mp));
921 if (pmp)
922 linkb(mp, pmp);
923 else
924 iobp->ioc_count = 0;
925
926 iobp->ioc_error = 0;
927
928 sm_dbg('M', ("(M_IOCDATA: rval %d cnt %d private 0x%p)\n",
929 iobp->ioc_rval, iobp->ioc_count, pmp));
930 return (0);
931 }
932
933 /*
934 * Process a TTYMUX_LIST ioctl.
935 */
936 int
ttymux_query_links_ioctl(mblk_t * mp)937 ttymux_query_links_ioctl(mblk_t *mp)
938 {
939 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
940 struct copyreq *cqp;
941 int unit;
942 sm_lqi_t *lqi;
943 mblk_t *nmp;
944 int cnt;
945 void *asl;
946 void *uaddr;
947 size_t sz;
948
949 if (DB_TYPE(mp) == M_IOCDATA) {
950 return (sm_iocresp(mp));
951 }
952 /*
953 * Is this a query for the number of linked devices?
954 */
955 if (iobp->ioc_count == 0) {
956
957 for (unit = 0, iobp->ioc_rval = 0;
958 unit < MAX_LQS && (lqi = get_lqi(sm_ssp, unit));
959 unit++)
960 if (lqi->sm_linkid != 0)
961 iobp->ioc_rval += 1;
962
963 iobp->ioc_rval += count_unconfigured_consoles(sm_ssp->sm_ms);
964 DB_TYPE(mp) = M_IOCACK;
965 iobp->ioc_error = 0;
966
967 return (0);
968 }
969
970 if (mp->b_cont == NULL) {
971 sm_dbg('Y', ("TTYMUX_LIST: b_cont is NULL\n"));
972 DB_TYPE(mp) = M_IOCNAK;
973 iobp->ioc_error = EINVAL;
974 return (EINVAL);
975 }
976
977 asl = mp->b_cont->b_rptr;
978
979 #ifdef _SYSCALL32_IMPL
980 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
981 cnt = ((ttymux_assocs32_t *)asl)->ttymux32_nlinks;
982 sz = cnt * sizeof (ttymux_assoc32_t);
983 uaddr = (void *)(uintptr_t)
984 ((ttymux_assocs32_t *)asl)->ttymux32_assocs;
985 } else
986 #endif
987 {
988 cnt = ((ttymux_assocs_t *)asl)->ttymux_nlinks;
989 sz = cnt * sizeof (ttymux_assoc_t);
990 uaddr = (void *)((ttymux_assocs_t *)asl)->ttymux_assocs;
991 }
992 if ((nmp = sm_allocb(sz, BPRI_MED)) == NULL) {
993 DB_TYPE(mp) = M_IOCNAK;
994 iobp->ioc_error = EINVAL;
995 return (EAGAIN);
996 }
997
998 sm_dbg('Y', ("TTYMUX_LIST: cnt %d sz %d uaddr 0x%p\n", cnt, sz, uaddr));
999
1000 iobp->ioc_rval = 0;
1001
1002 #ifdef _SYSCALL32_IMPL
1003 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
1004 ttymux_assoc32_t *assoc;
1005
1006 sm_dbg('Y', ("!Native: %d structures\n", cnt));
1007 assoc = (ttymux_assoc32_t *)nmp->b_rptr;
1008
1009 for (unit = 0;
1010 unit < MAX_LQS && (lqi = get_lqi(sm_ssp, unit));
1011 unit++) {
1012 if (lqi->sm_linkid != 0) {
1013 if (cnt-- == 0)
1014 break;
1015 LQI2ASSOC32(assoc, lqi);
1016 assoc++;
1017 iobp->ioc_rval += 1;
1018 }
1019 }
1020 if (cnt > 0) {
1021 /* see if there are unconfigured consoles */
1022 iobp->ioc_rval +=
1023 get_unconfigured_consoles32(sm_ssp->sm_ms, assoc);
1024 sm_dbg('I', ("%d unconfigured consoles\n",
1025 iobp->ioc_rval));
1026 } else {
1027 sm_dbg('I', ("no more space in user addr\n"));
1028 }
1029 ((ttymux_assocs32_t *)asl)->ttymux32_nlinks = iobp->ioc_rval;
1030 } else
1031 #endif
1032 {
1033 ttymux_assoc_t *assoc;
1034
1035 sm_dbg('Y', ("!Native: %d structures\n", cnt));
1036 assoc = (ttymux_assoc_t *)nmp->b_wptr;
1037
1038 for (unit = 0;
1039 unit < MAX_LQS && (lqi = get_lqi(sm_ssp, unit));
1040 unit++) {
1041 if (lqi->sm_linkid != 0) {
1042 if (cnt-- == 0)
1043 break;
1044 LQI2ASSOC(assoc, lqi);
1045 assoc++;
1046 iobp->ioc_rval += 1;
1047 }
1048 }
1049 if (cnt > 0) {
1050 /* see if there are unconfigured consoles */
1051 iobp->ioc_rval +=
1052 get_unconfigured_consoles(sm_ssp->sm_ms, assoc);
1053 sm_dbg('I', ("%d unconfigured consoles\n",
1054 iobp->ioc_rval));
1055 } else {
1056 sm_dbg('I', ("no more space in user addr\n"));
1057 }
1058 ((ttymux_assocs_t *)asl)->ttymux_nlinks = iobp->ioc_rval;
1059 }
1060
1061 cqp = (struct copyreq *)mp->b_rptr;
1062 cqp->cq_addr = uaddr;
1063 cqp->cq_size = sz;
1064 cqp->cq_flag = 0;
1065 cqp->cq_private = mp->b_cont;
1066 mp->b_cont = nmp;
1067 nmp->b_wptr = nmp->b_rptr + sz;
1068
1069 DB_TYPE(mp) = M_COPYOUT;
1070 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
1071
1072 return (0);
1073 }
1074
1075 /*
1076 * Process a TTYMUX_CONSDEV ioctl.
1077 */
1078 static int
ttymux_console_ioctl(mblk_t * mp)1079 ttymux_console_ioctl(mblk_t *mp)
1080 {
1081 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
1082 int err = EINVAL;
1083
1084 sm_dbg('I', ("ttymux_console_ioctl:\n"));
1085 #ifdef _SYSCALL32_IMPL
1086 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
1087 if (mp->b_cont && iobp->ioc_count >= sizeof (dev32_t)) {
1088 dev32_t dev;
1089
1090 (void) cmpldev(&dev, rconsdev);
1091
1092 *(dev32_t *)mp->b_cont->b_rptr = dev;
1093 mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof (dev);
1094 iobp->ioc_count = sizeof (dev);
1095 err = 0;
1096 } else {
1097 sm_dbg('I', ("TTYMUX_CONSDEV: b_cont 0x%p count %d\n",
1098 mp->b_cont, iobp->ioc_count));
1099 }
1100 } else
1101 #endif
1102 if (mp->b_cont && iobp->ioc_count >= sizeof (dev_t)) {
1103 *(dev_t *)mp->b_cont->b_rptr = rconsdev;
1104 mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof (rconsdev);
1105 iobp->ioc_count = sizeof (rconsdev);
1106 err = 0;
1107 }
1108 return (err);
1109 }
1110
1111 /*
1112 * Process a ioctl relating to aborting on the console.
1113 */
1114 int
ttymux_abort_ioctl(mblk_t * mp)1115 ttymux_abort_ioctl(mblk_t *mp)
1116 {
1117 struct iocblk *iobp;
1118 int cmd, err = 0;
1119 sm_lqi_t *lqi;
1120 ttymux_abort_t *abreq;
1121 #ifdef _SYSCALL32_IMPL
1122 struct ttymux_abort32 {
1123 dev32_t ldev;
1124 enum ttymux_break_type method;
1125 uint32_t enable;
1126 } *abreq32;
1127 #endif
1128 dev_t ldev;
1129 enum ttymux_break_type method;
1130 uint_t enable;
1131
1132 iobp = (struct iocblk *)mp->b_rptr;
1133 cmd = iobp->ioc_cmd;
1134
1135 iobp->ioc_error = 0;
1136 iobp->ioc_rval = 0;
1137 sm_dbg('I', ("ttymux_abort_ioctl:\n"));
1138 switch (cmd) {
1139 case CONSSETABORTENABLE:
1140 lqi = (sm_ssp->sm_lconsole) ? sm_ssp->sm_lconsole->sm_lqs : 0;
1141 enable = (*(intptr_t *)mp->b_cont->b_rptr) ? 1 : 0;
1142 sm_ssp->sm_ctrla_abort_on = sm_ssp->sm_break_abort_on = enable;
1143 for (; lqi != 0; lqi = lqi->sm_nlqi) {
1144 lqi->sm_ctrla_abort_on = enable;
1145 lqi->sm_break_abort_on = enable;
1146 }
1147 break;
1148 case CONSGETABORTENABLE:
1149 if (mp->b_cont == 0 || iobp->ioc_count < sizeof (intptr_t)) {
1150 iobp->ioc_error = EINVAL;
1151 iobp->ioc_rval = -1;
1152 } else {
1153 *(intptr_t *)mp->b_cont->b_rptr =
1154 (sm_ssp->sm_ctrla_abort_on ||
1155 sm_ssp->sm_break_abort_on);
1156 mp->b_cont->b_wptr =
1157 mp->b_cont->b_rptr + sizeof (intptr_t);
1158 iobp->ioc_count = sizeof (intptr_t);
1159 }
1160 break;
1161 case TTYMUX_GETABORTSTR:
1162
1163 if (iobp->ioc_count < strlen(sm_ssp->sm_abs) + 1 ||
1164 mp->b_cont == 0 ||
1165 mp->b_cont->b_cont) {
1166 iobp->ioc_error = EINVAL;
1167 iobp->ioc_rval = -1;
1168 } else {
1169 (void) strcpy((char *)mp->b_cont->b_rptr,
1170 sm_ssp->sm_abs);
1171 iobp->ioc_count = strlen(sm_ssp->sm_abs) + 1;
1172 mp->b_cont->b_wptr =
1173 mp->b_cont->b_rptr + iobp->ioc_count;
1174 }
1175 break;
1176 case TTYMUX_GETABORT:
1177 case TTYMUX_SETABORT:
1178
1179 lqi = 0;
1180 #ifdef _SYSCALL32_IMPL
1181 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
1182 if (iobp->ioc_count < sizeof (*abreq32) ||
1183 mp->b_cont == 0) {
1184 err = EINVAL;
1185 } else {
1186 abreq32 = (struct ttymux_abort32 *)
1187 mp->b_cont->b_rptr;
1188 ldev = expldev(abreq32->ldev);
1189 method = abreq32->method;
1190 enable = (uint_t)abreq32->enable;
1191 iobp->ioc_count = sizeof (*abreq32);
1192 }
1193 } else
1194 #endif
1195 if (iobp->ioc_count < sizeof (*abreq) ||
1196 mp->b_cont == 0) {
1197 err = EINVAL;
1198 } else {
1199 abreq = (ttymux_abort_t *)mp->b_cont->b_rptr;
1200 ldev = abreq->ttymux_ldev;
1201 method = abreq->ttymux_method;
1202 enable = abreq->ttymux_enable;
1203 iobp->ioc_count = sizeof (*abreq);
1204 }
1205
1206 if (err != 0) {
1207 iobp->ioc_rval = -1;
1208 return ((iobp->ioc_error = err));
1209 }
1210
1211 sm_dbg('Y', ("ttymux_abort_ioctl: type %d how %d ldev %d:%d\n",
1212 method, enable, getmajor(ldev), getminor(ldev)));
1213
1214 lqi = get_lqi_bydevt(ldev);
1215 if (ldev != NODEV && lqi == 0) {
1216 err = ENOLINK;
1217 } else if (cmd == TTYMUX_GETABORT && lqi == 0) {
1218 err = ENODEV;
1219 } else if (cmd == TTYMUX_GETABORT) {
1220 if (lqi->sm_break_abort_on == 0 &&
1221 lqi->sm_ctrla_abort_on == 0) {
1222 method = SOFTHARD_BREAK;
1223 enable = 0;
1224 } else {
1225 enable = 1;
1226 if (lqi->sm_break_abort_on == 0)
1227 method = SOFTWARE_BREAK;
1228 else if (lqi->sm_ctrla_abort_on == 0)
1229 method = HARDWARE_BREAK;
1230 else
1231 method = SOFTHARD_BREAK;
1232 }
1233
1234 #ifdef _SYSCALL32_IMPL
1235 if ((iobp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
1236 abreq32->method = method;
1237 abreq32->enable = (uint32_t)enable;
1238 } else
1239 #endif
1240 {
1241 abreq->ttymux_method = method;
1242 abreq->ttymux_enable = enable;
1243 }
1244 } else {
1245 iobp->ioc_count = 0;
1246 sm_dbg('I', ("lqi is 0x%p\n", lqi));
1247 if (lqi == 0) {
1248 if (method == HARDWARE_BREAK)
1249 sm_ssp->sm_break_abort_on = enable;
1250 else if (method == SOFTWARE_BREAK)
1251 sm_ssp->sm_ctrla_abort_on = enable;
1252 else if (method == SOFTHARD_BREAK) {
1253 sm_ssp->sm_break_abort_on = enable;
1254 sm_ssp->sm_ctrla_abort_on = enable;
1255 } else {
1256 sm_dbg('I', ("%d - invalid\n", method));
1257 iobp->ioc_rval = -1;
1258 return ((iobp->ioc_error = EINVAL));
1259 }
1260
1261 if (sm_ssp->sm_lconsole) {
1262 sm_dbg('I', ("lconsole 0x%p (0x%p)\n",
1263 sm_ssp->sm_lconsole,
1264 sm_ssp->sm_lconsole->sm_lqs));
1265 } else {
1266 sm_dbg('I', ("lconsole is null\n"));
1267 }
1268
1269 lqi = (sm_ssp->sm_lconsole) ?
1270 sm_ssp->sm_lconsole->sm_lqs : 0;
1271 }
1272 while (lqi) {
1273 if (method == HARDWARE_BREAK)
1274 lqi->sm_break_abort_on = enable;
1275 else if (method == SOFTWARE_BREAK)
1276 lqi->sm_ctrla_abort_on = enable;
1277 else if (method == SOFTHARD_BREAK) {
1278 lqi->sm_break_abort_on = enable;
1279 lqi->sm_ctrla_abort_on = enable;
1280 } else {
1281 sm_dbg('I', ("%d: invalid\n", method));
1282 iobp->ioc_rval = -1;
1283 return ((iobp->ioc_error = EINVAL));
1284 }
1285
1286 lqi = (ldev == NODEV) ? lqi->sm_nlqi : 0;
1287 }
1288 }
1289 iobp->ioc_rval = err ? -1 : 0;
1290 iobp->ioc_error = err;
1291 break;
1292 default:
1293 iobp->ioc_rval = -1;
1294 iobp->ioc_error = EINVAL;
1295 }
1296 return (iobp->ioc_error);
1297 }
1298
1299 /*
1300 * Process ioctls specific to the ttymux driver.
1301 */
1302 /*ARGSUSED*/
1303 int
sm_ioctl_cmd(sm_uqi_t * uqi,mblk_t * mp)1304 sm_ioctl_cmd(sm_uqi_t *uqi, mblk_t *mp)
1305 {
1306 struct iocblk *iobp = (struct iocblk *)mp->b_rptr;
1307
1308 iobp->ioc_rval = 0;
1309
1310 /*
1311 * This routine does not support transparent ioctls
1312 */
1313 if (iobp->ioc_count == TRANSPARENT) {
1314 sm_dbg('Y', ("sm_ioctl_cmd: unsupported ioctl\n"));
1315 iobp->ioc_error = ENOTSUP;
1316 DB_TYPE(mp) = M_IOCNAK;
1317 if (mp->b_cont)
1318 freemsg(unlinkb(mp));
1319 return (ENOTSUP);
1320 }
1321
1322 switch (iobp->ioc_cmd) {
1323 case TTYMUX_CONSDEV:
1324 iobp->ioc_error = ttymux_console_ioctl(mp);
1325 break;
1326 case TTYMUX_ASSOC:
1327 case TTYMUX_DISASSOC:
1328 iobp->ioc_error = ttymux_link_ioctl(mp);
1329 break;
1330 case TTYMUX_GETLINK:
1331 iobp->ioc_error = ttymux_query_link_ioctl(mp);
1332 break;
1333 case TTYMUX_LIST:
1334 return (ttymux_query_links_ioctl(mp));
1335 case TTYMUX_SETCTL:
1336 case TTYMUX_GETCTL:
1337 iobp->ioc_error = ENOTSUP;
1338 break;
1339 case TTYMUX_GETABORTSTR:
1340 case TTYMUX_SETABORT:
1341 case TTYMUX_GETABORT:
1342 iobp->ioc_error = ttymux_abort_ioctl(mp);
1343 break;
1344 default:
1345 iobp->ioc_error = EINVAL;
1346 break;
1347 }
1348
1349 DB_TYPE(mp) = iobp->ioc_error ? M_IOCNAK : M_IOCACK;
1350
1351 if ((iobp->ioc_error || iobp->ioc_count == 0) && mp->b_cont)
1352 freemsg(unlinkb(mp));
1353
1354 sm_dbg('I', ("TTYMUX IOCTL: err %d rval %d count %d\n",
1355 iobp->ioc_error, iobp->ioc_rval, iobp->ioc_count));
1356
1357 return (iobp->ioc_error);
1358 }
1359