Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/xen/io/xencons.c
+++ new/usr/src/uts/common/xen/io/xencons.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
23 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
24 24 /* All Rights Reserved */
25 25
26 26 /*
27 27 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
28 28 * Use is subject to license terms.
29 29 */
30 30
31 31
32 32 /*
33 33 *
34 34 * Copyright (c) 2004 Christian Limpach.
35 35 * All rights reserved.
36 36 *
37 37 * Redistribution and use in source and binary forms, with or without
38 38 * modification, are permitted provided that the following conditions
39 39 * are met:
40 40 * 1. Redistributions of source code must retain the above copyright
41 41 * notice, this list of conditions and the following disclaimer.
42 42 * 2. Redistributions in binary form must reproduce the above copyright
43 43 * notice, this list of conditions and the following disclaimer in the
44 44 * documentation and/or other materials provided with the distribution.
45 45 * 3. This section intentionally left blank.
46 46 * 4. The name of the author may not be used to endorse or promote products
47 47 * derived from this software without specific prior written permission.
48 48 *
49 49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
50 50 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51 51 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52 52 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
53 53 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
54 54 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55 55 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56 56 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57 57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
58 58 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 59 */
60 60 /*
61 61 * Section 3 of the above license was updated in response to bug 6379571.
62 62 */
63 63
64 64 /*
65 65 * Hypervisor virtual console driver
66 66 */
67 67
68 68 #include <sys/param.h>
69 69 #include <sys/types.h>
70 70 #include <sys/signal.h>
71 71 #include <sys/stream.h>
72 72 #include <sys/termio.h>
73 73 #include <sys/errno.h>
74 74 #include <sys/file.h>
75 75 #include <sys/cmn_err.h>
76 76 #include <sys/stropts.h>
77 77 #include <sys/strsubr.h>
78 78 #include <sys/strtty.h>
79 79 #include <sys/debug.h>
80 80 #include <sys/kbio.h>
81 81 #include <sys/cred.h>
82 82 #include <sys/stat.h>
83 83 #include <sys/consdev.h>
84 84 #include <sys/mkdev.h>
85 85 #include <sys/kmem.h>
86 86 #include <sys/cred.h>
87 87 #include <sys/strsun.h>
88 88 #ifdef DEBUG
89 89 #include <sys/promif.h>
90 90 #endif
91 91 #include <sys/modctl.h>
92 92 #include <sys/ddi.h>
93 93 #include <sys/sunddi.h>
94 94 #include <sys/sunndi.h>
95 95 #include <sys/policy.h>
96 96 #include <sys/atomic.h>
97 97 #include <sys/psm.h>
98 98 #include <xen/public/io/console.h>
99 99
100 100 #include "xencons.h"
101 101
102 102 #include <sys/hypervisor.h>
103 103 #include <sys/evtchn_impl.h>
104 104 #include <xen/sys/xenbus_impl.h>
105 105 #include <xen/sys/xendev.h>
106 106
107 107 #ifdef DEBUG
108 108 #define XENCONS_DEBUG_INIT 0x0001 /* msgs during driver initialization. */
109 109 #define XENCONS_DEBUG_INPUT 0x0002 /* characters received during int. */
110 110 #define XENCONS_DEBUG_EOT 0x0004 /* msgs when wait for xmit to finish. */
111 111 #define XENCONS_DEBUG_CLOSE 0x0008 /* msgs when driver open/close called */
112 112 #define XENCONS_DEBUG_PROCS 0x0020 /* each proc name as it is entered. */
113 113 #define XENCONS_DEBUG_OUT 0x0100 /* msgs about output events. */
114 114 #define XENCONS_DEBUG_BUSY 0x0200 /* msgs when xmit is enabled/disabled */
115 115 #define XENCONS_DEBUG_MODEM 0x0400 /* msgs about modem status & control. */
116 116 #define XENCONS_DEBUG_MODM2 0x0800 /* msgs about modem status & control. */
117 117 #define XENCONS_DEBUG_IOCTL 0x1000 /* Output msgs about ioctl messages. */
118 118 #define XENCONS_DEBUG_CHIP 0x2000 /* msgs about chip identification. */
119 119 #define XENCONS_DEBUG_SFLOW 0x4000 /* msgs when S/W flowcontrol active */
120 120 #define XENCONS_DEBUG(x) (debug & (x))
121 121 static int debug = 0;
122 122 #else
123 123 #define XENCONS_DEBUG(x) B_FALSE
124 124 #endif
125 125
126 126 #define XENCONS_WBUFSIZE 4096
127 127
128 128 static boolean_t abort_charseq_recognize(uchar_t);
129 129
130 130 /* The async interrupt entry points */
131 131 static void xcasync_ioctl(struct asyncline *, queue_t *, mblk_t *);
132 132 static void xcasync_reioctl(void *);
133 133 static void xcasync_start(struct asyncline *);
134 134 static void xenconsputchar(cons_polledio_arg_t, uchar_t);
135 135 static int xenconsgetchar(cons_polledio_arg_t);
136 136 static boolean_t xenconsischar(cons_polledio_arg_t);
137 137
138 138 static uint_t xenconsintr(caddr_t);
139 139 static uint_t xenconsintr_priv(caddr_t);
140 140 /*PRINTFLIKE2*/
141 141 static void xenconserror(int, const char *, ...) __KPRINTFLIKE(2);
142 142 static void xencons_soft_state_free(struct xencons *);
143 143 static boolean_t
144 144 xcasync_flowcontrol_sw_input(struct xencons *, async_flowc_action, int);
145 145 static void
146 146 xcasync_flowcontrol_sw_output(struct xencons *, async_flowc_action);
147 147
148 148 void *xencons_soft_state;
149 149 char *xencons_wbuf;
150 150 struct xencons *xencons_console;
151 151
152 152 static void
153 153 xenconssetup_avintr(struct xencons *xcp, int attach)
154 154 {
155 155 /*
156 156 * On xen, CPU 0 always exists and can't be taken offline,
157 157 * so binding this thread to it should always succeed.
158 158 */
159 159 mutex_enter(&cpu_lock);
160 160 thread_affinity_set(curthread, 0);
161 161 mutex_exit(&cpu_lock);
162 162
163 163 if (attach) {
164 164 /* Setup our interrupt binding. */
165 165 (void) add_avintr(NULL, IPL_CONS, (avfunc)xenconsintr_priv,
166 166 "xencons", xcp->console_irq, (caddr_t)xcp, NULL, NULL,
167 167 xcp->dip);
168 168 } else {
169 169 /*
170 170 * Cleanup interrupt configuration. Note that the framework
171 171 * _should_ ensure that when rem_avintr() returns the interrupt
172 172 * service routine is not currently executing and that it won't
173 173 * be invoked again.
174 174 */
175 175 (void) rem_avintr(NULL, IPL_CONS, (avfunc)xenconsintr_priv,
176 176 xcp->console_irq);
177 177 }
178 178
179 179 /* Notify our caller that we're done. */
180 180 mutex_enter(&xcp->excl);
181 181 cv_signal(&xcp->excl_cv);
182 182 mutex_exit(&xcp->excl);
183 183
184 184 /* Clear our binding to CPU 0 */
185 185 thread_affinity_clear(curthread);
186 186
187 187 }
188 188
189 189 static void
190 190 xenconssetup_add_avintr(struct xencons *xcp)
191 191 {
192 192 xenconssetup_avintr(xcp, B_TRUE);
193 193 }
194 194
195 195 static void
196 196 xenconssetup_rem_avintr(struct xencons *xcp)
197 197 {
198 198 xenconssetup_avintr(xcp, B_FALSE);
199 199 }
200 200
201 201 static int
202 202 xenconsdetach(dev_info_t *devi, ddi_detach_cmd_t cmd)
203 203 {
204 204 int instance;
205 205 struct xencons *xcp;
206 206
207 207 if (cmd != DDI_DETACH && cmd != DDI_SUSPEND)
208 208 return (DDI_FAILURE);
209 209
210 210 if (cmd == DDI_SUSPEND) {
211 211 ddi_remove_intr(devi, 0, NULL);
212 212 return (DDI_SUCCESS);
213 213 }
214 214
215 215 /*
216 216 * We should never try to detach the console driver on a domU
217 217 * because it should always be held open
218 218 */
219 219 ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
220 220 if (!DOMAIN_IS_INITDOMAIN(xen_info))
221 221 return (DDI_FAILURE);
222 222
223 223 instance = ddi_get_instance(devi); /* find out which unit */
224 224
225 225 xcp = ddi_get_soft_state(xencons_soft_state, instance);
226 226 if (xcp == NULL)
227 227 return (DDI_FAILURE);
228 228
229 229 /*
230 230 * Cleanup our interrupt bindings. For more info on why we
231 231 * do this in a seperate thread, see the comments for when we
232 232 * setup the interrupt bindings.
233 233 */
234 234 xencons_console = NULL;
235 235 mutex_enter(&xcp->excl);
236 236 (void) taskq_dispatch(system_taskq,
237 237 (void (*)(void *))xenconssetup_rem_avintr, xcp, TQ_SLEEP);
238 238 cv_wait(&xcp->excl_cv, &xcp->excl);
239 239 mutex_exit(&xcp->excl);
240 240
241 241 /* remove all minor device node(s) for this device */
242 242 ddi_remove_minor_node(devi, NULL);
243 243
244 244 /* free up state */
245 245 xencons_soft_state_free(xcp);
246 246 kmem_free(xencons_wbuf, XENCONS_WBUFSIZE);
247 247
248 248 DEBUGNOTE1(XENCONS_DEBUG_INIT, "xencons%d: shutdown complete",
249 249 instance);
250 250 return (DDI_SUCCESS);
251 251 }
252 252
253 253 static void
254 254 xenconssetup(struct xencons *xcp)
255 255 {
256 256 xcp->ifp = (volatile struct xencons_interface *)HYPERVISOR_console_page;
257 257
258 258 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
259 259 xencons_wbuf = kmem_alloc(XENCONS_WBUFSIZE, KM_SLEEP);
260 260
261 261 /*
262 262 * Activate the xen console virq. Note that xen requires
263 263 * that VIRQs be bound to CPU 0 when first created.
264 264 */
265 265 xcp->console_irq = ec_bind_virq_to_irq(VIRQ_CONSOLE, 0);
266 266
267 267 /*
268 268 * Ok. This is kinda ugly. We want to register an
269 269 * interrupt handler for the xen console virq, but
270 270 * virq's are xen sepcific and currently the DDI doesn't
271 271 * support binding to them. So instead we need to use
272 272 * add_avintr(). So to make things more complicated,
273 273 * we already had to bind the xen console VIRQ to CPU 0,
274 274 * and add_avintr() needs to be invoked on the same CPU
275 275 * where the VIRQ is bound, in this case on CPU 0. We
276 276 * could just temporarily bind ourselves to CPU 0, but
277 277 * we don't want to do that since this attach thread
278 278 * could have been invoked in a user thread context,
279 279 * in which case this thread could already have some
280 280 * pre-existing cpu binding. So to avoid changing our
281 281 * cpu binding we're going to use a taskq thread that
282 282 * will bind to CPU 0 and register our interrupts
283 283 * handler for us.
284 284 */
285 285 mutex_enter(&xcp->excl);
286 286 (void) taskq_dispatch(system_taskq,
287 287 (void (*)(void *))xenconssetup_add_avintr, xcp, TQ_SLEEP);
288 288 cv_wait(&xcp->excl_cv, &xcp->excl);
289 289 mutex_exit(&xcp->excl);
290 290 } else {
291 291 (void) xvdi_alloc_evtchn(xcp->dip);
292 292 xcp->evtchn = xvdi_get_evtchn(xcp->dip);
293 293 (void) ddi_add_intr(xcp->dip, 0, NULL, NULL, xenconsintr,
294 294 (caddr_t)xcp);
295 295 }
296 296 }
297 297
298 298 static int
299 299 xenconsattach(dev_info_t *devi, ddi_attach_cmd_t cmd)
300 300 {
301 301 int instance = ddi_get_instance(devi);
302 302 struct xencons *xcp;
303 303 int ret;
304 304
305 305 /* There can be only one. */
306 306 if (instance != 0)
307 307 return (DDI_FAILURE);
308 308
309 309 switch (cmd) {
310 310 case DDI_RESUME:
311 311 xcp = xencons_console;
312 312 xenconssetup(xcp);
313 313 return (DDI_SUCCESS);
314 314 case DDI_ATTACH:
315 315 break;
316 316 default:
317 317 return (DDI_FAILURE);
318 318 }
319 319
320 320 ret = ddi_soft_state_zalloc(xencons_soft_state, instance);
321 321 if (ret != DDI_SUCCESS)
322 322 return (DDI_FAILURE);
323 323 xcp = ddi_get_soft_state(xencons_soft_state, instance);
324 324 ASSERT(xcp != NULL); /* can't fail - we only just allocated it */
325 325
326 326 /*
327 327 * Set up the other components of the xencons structure for this port.
328 328 */
329 329 xcp->unit = instance;
330 330 xcp->dip = devi;
331 331
332 332 /* Fill in the polled I/O structure. */
333 333 xcp->polledio.cons_polledio_version = CONSPOLLEDIO_V0;
334 334 xcp->polledio.cons_polledio_argument = (cons_polledio_arg_t)xcp;
335 335 xcp->polledio.cons_polledio_putchar = xenconsputchar;
336 336 xcp->polledio.cons_polledio_getchar = xenconsgetchar;
337 337 xcp->polledio.cons_polledio_ischar = xenconsischar;
338 338 xcp->polledio.cons_polledio_enter = NULL;
339 339 xcp->polledio.cons_polledio_exit = NULL;
340 340
341 341 /*
342 342 * Initializes the asyncline structure which has TTY protocol-private
343 343 * data before enabling interrupts.
344 344 */
345 345 xcp->priv = kmem_zalloc(sizeof (struct asyncline), KM_SLEEP);
346 346 xcp->priv->async_common = xcp;
347 347 cv_init(&xcp->priv->async_flags_cv, NULL, CV_DRIVER, NULL);
348 348
349 349 /* Initialize mutexes before accessing the interface. */
350 350 mutex_init(&xcp->excl, NULL, MUTEX_DRIVER, NULL);
351 351 cv_init(&xcp->excl_cv, NULL, CV_DEFAULT, NULL);
352 352
353 353 /* create minor device node for this device */
354 354 ret = ddi_create_minor_node(devi, "xencons", S_IFCHR, instance,
355 355 DDI_NT_SERIAL, NULL);
356 356 if (ret != DDI_SUCCESS) {
357 357 ddi_remove_minor_node(devi, NULL);
358 358 xencons_soft_state_free(xcp);
359 359 return (DDI_FAILURE);
360 360 }
361 361
362 362 ddi_report_dev(devi);
363 363 xencons_console = xcp;
364 364 xenconssetup(xcp);
365 365 DEBUGCONT1(XENCONS_DEBUG_INIT, "xencons%dattach: done\n", instance);
366 366 return (DDI_SUCCESS);
367 367 }
368 368
369 369 /*ARGSUSED*/
370 370 static int
371 371 xenconsinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
372 372 void **result)
373 373 {
374 374 dev_t dev = (dev_t)arg;
375 375 int instance, error;
376 376 struct xencons *xcp;
377 377
378 378 instance = getminor(dev);
379 379 xcp = ddi_get_soft_state(xencons_soft_state, instance);
380 380 if (xcp == NULL)
381 381 return (DDI_FAILURE);
382 382
383 383 switch (infocmd) {
384 384 case DDI_INFO_DEVT2DEVINFO:
385 385 if (xcp->dip == NULL)
386 386 error = DDI_FAILURE;
387 387 else {
388 388 *result = (void *) xcp->dip;
389 389 error = DDI_SUCCESS;
390 390 }
391 391 break;
392 392 case DDI_INFO_DEVT2INSTANCE:
393 393 *result = (void *)(intptr_t)instance;
394 394 error = DDI_SUCCESS;
395 395 break;
396 396 default:
397 397 error = DDI_FAILURE;
398 398 }
399 399 return (error);
400 400 }
401 401
402 402 /* xencons_soft_state_free - local wrapper for ddi_soft_state_free(9F) */
403 403
404 404 static void
405 405 xencons_soft_state_free(struct xencons *xcp)
406 406 {
407 407 mutex_destroy(&xcp->excl);
408 408 cv_destroy(&xcp->excl_cv);
409 409 kmem_free(xcp->priv, sizeof (struct asyncline));
410 410 ddi_soft_state_free(xencons_soft_state, xcp->unit);
411 411 }
412 412
413 413 /*ARGSUSED*/
414 414 static int
415 415 xenconsopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
416 416 {
417 417 struct xencons *xcp;
418 418 struct asyncline *async;
419 419 int unit;
420 420
421 421 unit = getminor(*dev);
422 422 DEBUGCONT1(XENCONS_DEBUG_CLOSE, "xencons%dopen\n", unit);
423 423 xcp = ddi_get_soft_state(xencons_soft_state, unit);
424 424 if (xcp == NULL)
425 425 return (ENXIO); /* unit not configured */
426 426 async = xcp->priv;
427 427 mutex_enter(&xcp->excl);
428 428
429 429 again:
430 430
431 431 if ((async->async_flags & ASYNC_ISOPEN) == 0) {
432 432 async->async_ttycommon.t_iflag = 0;
433 433 async->async_ttycommon.t_iocpending = NULL;
434 434 async->async_ttycommon.t_size.ws_row = 0;
435 435 async->async_ttycommon.t_size.ws_col = 0;
436 436 async->async_ttycommon.t_size.ws_xpixel = 0;
437 437 async->async_ttycommon.t_size.ws_ypixel = 0;
438 438 async->async_dev = *dev;
439 439 async->async_wbufcid = 0;
440 440
441 441 async->async_startc = CSTART;
442 442 async->async_stopc = CSTOP;
443 443 } else if ((async->async_ttycommon.t_flags & TS_XCLUDE) &&
444 444 secpolicy_excl_open(cr) != 0) {
445 445 mutex_exit(&xcp->excl);
446 446 return (EBUSY);
447 447 }
448 448
449 449 async->async_ttycommon.t_flags |= TS_SOFTCAR;
450 450
451 451 async->async_ttycommon.t_readq = rq;
452 452 async->async_ttycommon.t_writeq = WR(rq);
453 453 rq->q_ptr = WR(rq)->q_ptr = (caddr_t)async;
454 454 mutex_exit(&xcp->excl);
455 455 /*
456 456 * Caution here -- qprocson sets the pointers that are used by canput
457 457 * called by xencons_rxint. ASYNC_ISOPEN must *not* be set until those
458 458 * pointers are valid.
459 459 */
460 460 qprocson(rq);
461 461 async->async_flags |= ASYNC_ISOPEN;
462 462 DEBUGCONT1(XENCONS_DEBUG_INIT, "asy%dopen: done\n", unit);
463 463 return (0);
464 464 }
465 465
466 466
467 467 /*
468 468 * Close routine.
469 469 */
470 470 /*ARGSUSED*/
471 471 static int
472 472 xenconsclose(queue_t *q, int flag, cred_t *credp)
473 473 {
474 474 struct asyncline *async;
475 475 struct xencons *xcp;
476 476 #ifdef DEBUG
477 477 int instance;
478 478 #endif
479 479
480 480 async = (struct asyncline *)q->q_ptr;
481 481 ASSERT(async != NULL);
482 482 xcp = async->async_common;
483 483 #ifdef DEBUG
484 484 instance = xcp->unit;
485 485 DEBUGCONT1(XENCONS_DEBUG_CLOSE, "xencons%dclose\n", instance);
486 486 #endif
487 487
488 488 mutex_enter(&xcp->excl);
489 489 async->async_flags |= ASYNC_CLOSING;
490 490
491 491 async->async_ocnt = 0;
492 492 if (async->async_xmitblk != NULL)
493 493 freeb(async->async_xmitblk);
494 494 async->async_xmitblk = NULL;
495 495
496 496 out:
497 497 ttycommon_close(&async->async_ttycommon);
498 498
499 499 /*
500 500 * Cancel outstanding "bufcall" request.
501 501 */
502 502 if (async->async_wbufcid != 0) {
503 503 unbufcall(async->async_wbufcid);
504 504 async->async_wbufcid = 0;
505 505 }
506 506
507 507 /* Note that qprocsoff can't be done until after interrupts are off */
508 508 qprocsoff(q);
509 509 q->q_ptr = WR(q)->q_ptr = NULL;
510 510 async->async_ttycommon.t_readq = NULL;
511 511 async->async_ttycommon.t_writeq = NULL;
512 512
513 513 /*
514 514 * Clear out device state, except persistant device property flags.
515 515 */
516 516 async->async_flags = 0;
517 517 cv_broadcast(&async->async_flags_cv);
518 518 mutex_exit(&xcp->excl);
519 519
520 520 DEBUGCONT1(XENCONS_DEBUG_CLOSE, "xencons%dclose: done\n", instance);
521 521 return (0);
522 522 }
523 523
524 524 #define INBUF_IX(ix, ifp) (DOMAIN_IS_INITDOMAIN(xen_info) ? \
525 525 (ix) : MASK_XENCONS_IDX((ix), (ifp)->in))
526 526
527 527 /*
528 528 * Handle a xen console rx interrupt.
529 529 */
530 530 /*ARGSUSED*/
531 531 static void
532 532 xencons_rxint(struct xencons *xcp)
533 533 {
534 534 struct asyncline *async;
535 535 short cc;
536 536 mblk_t *bp;
537 537 queue_t *q;
538 538 uchar_t c, buf[16];
539 539 uchar_t *cp;
540 540 tty_common_t *tp;
541 541 int instance;
542 542 volatile struct xencons_interface *ifp;
543 543 XENCONS_RING_IDX cons, prod;
544 544
545 545 DEBUGCONT0(XENCONS_DEBUG_PROCS, "xencons_rxint\n");
546 546
547 547 loop:
548 548 mutex_enter(&xcp->excl);
549 549
550 550 /* sanity check if we should bail */
551 551 if (xencons_console == NULL) {
552 552 mutex_exit(&xcp->excl);
553 553 goto out;
554 554 }
555 555
556 556 async = xcp->priv;
557 557 instance = xcp->unit;
558 558 ifp = xcp->ifp;
559 559 tp = &async->async_ttycommon;
560 560 q = tp->t_readq;
561 561
562 562 if (async->async_flags & ASYNC_OUT_FLW_RESUME) {
563 563 xcasync_start(async);
564 564 async->async_flags &= ~ASYNC_OUT_FLW_RESUME;
565 565 }
566 566
567 567 /*
568 568 * If data is available, send it up the stream if there's
569 569 * somebody listening.
570 570 */
571 571 if (!(async->async_flags & ASYNC_ISOPEN)) {
572 572 mutex_exit(&xcp->excl);
573 573 goto out;
574 574 }
575 575 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
576 576 cc = HYPERVISOR_console_io(CONSOLEIO_read, 16, (char *)buf);
577 577 cp = buf;
578 578 cons = 0;
579 579 } else {
580 580 cons = ifp->in_cons;
581 581 prod = ifp->in_prod;
582 582
583 583 cc = prod - cons;
584 584 cp = (uchar_t *)ifp->in;
585 585 }
586 586 if (cc <= 0) {
587 587 mutex_exit(&xcp->excl);
588 588 goto out;
589 589 }
590 590
591 591 /*
592 592 * Check for character break sequence.
593 593 *
594 594 * Note that normally asy drivers only check for a character sequence
595 595 * if abort_enable == KIOCABORTALTERNATE and otherwise use a break
596 596 * sensed on the line to do an abort_sequence_enter. Since the
597 597 * hypervisor does not use a real chip for the console we default to
598 598 * using the alternate sequence.
599 599 */
600 600 if ((abort_enable == KIOCABORTENABLE) && (xcp->flags & ASY_CONSOLE)) {
601 601 XENCONS_RING_IDX i;
602 602
603 603 for (i = 0; i < cc; i++) {
604 604 c = cp[INBUF_IX(cons + i, ifp)];
605 605 if (abort_charseq_recognize(c)) {
606 606 /*
607 607 * Eat abort seg, it's not a valid debugger
608 608 * command.
609 609 */
610 610 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
611 611 membar_producer();
612 612 ifp->in_cons = cons + i;
613 613 } else {
614 614 cons += i;
615 615 }
616 616 abort_sequence_enter((char *)NULL);
617 617 /*
618 618 * Back from debugger, resume normal processing
619 619 */
620 620 mutex_exit(&xcp->excl);
621 621 goto loop;
622 622 }
623 623 }
624 624 }
625 625
626 626 if (!canput(q)) {
627 627 if (!(async->async_inflow_source & IN_FLOW_STREAMS)) {
628 628 (void) xcasync_flowcontrol_sw_input(xcp, FLOW_STOP,
629 629 IN_FLOW_STREAMS);
630 630 }
631 631 mutex_exit(&xcp->excl);
632 632 goto out;
633 633 }
634 634 if (async->async_inflow_source & IN_FLOW_STREAMS) {
635 635 (void) xcasync_flowcontrol_sw_input(xcp, FLOW_START,
636 636 IN_FLOW_STREAMS);
637 637 }
638 638 DEBUGCONT2(XENCONS_DEBUG_INPUT,
639 639 "xencons%d_rxint: %d char(s) in queue.\n", instance, cc);
640 640 if (!(bp = allocb(cc, BPRI_MED))) {
641 641 mutex_exit(&xcp->excl);
642 642 ttycommon_qfull(&async->async_ttycommon, q);
643 643 goto out;
644 644 }
645 645 do {
646 646 c = cp[INBUF_IX(cons++, ifp)];
647 647 /*
648 648 * We handle XON/XOFF char if IXON is set,
649 649 * but if received char is _POSIX_VDISABLE,
650 650 * we left it to the up level module.
651 651 */
652 652 if (tp->t_iflag & IXON) {
653 653 if ((c == async->async_stopc) &&
654 654 (c != _POSIX_VDISABLE)) {
655 655 xcasync_flowcontrol_sw_output(xcp, FLOW_STOP);
656 656 continue;
657 657 } else if ((c == async->async_startc) &&
658 658 (c != _POSIX_VDISABLE)) {
659 659 xcasync_flowcontrol_sw_output(xcp, FLOW_START);
660 660 continue;
661 661 }
662 662 if ((tp->t_iflag & IXANY) &&
663 663 (async->async_flags & ASYNC_SW_OUT_FLW)) {
664 664 xcasync_flowcontrol_sw_output(xcp, FLOW_START);
665 665 }
666 666 }
667 667 *bp->b_wptr++ = c;
668 668 } while (--cc);
669 669 membar_producer();
670 670 if (!DOMAIN_IS_INITDOMAIN(xen_info))
671 671 ifp->in_cons = cons;
672 672 mutex_exit(&xcp->excl);
673 673 if (bp->b_wptr > bp->b_rptr) {
674 674 if (!canput(q)) {
675 675 xenconserror(CE_NOTE, "xencons%d: local queue full",
676 676 instance);
677 677 freemsg(bp);
678 678 } else
679 679 (void) putq(q, bp);
680 680 } else
681 681 freemsg(bp);
682 682 if (DOMAIN_IS_INITDOMAIN(xen_info))
683 683 goto loop;
684 684 out:
685 685 DEBUGCONT1(XENCONS_DEBUG_PROCS, "xencons%d_rxint: done\n", instance);
686 686 if (!DOMAIN_IS_INITDOMAIN(xen_info))
687 687 ec_notify_via_evtchn(xcp->evtchn);
688 688 }
689 689
690 690
691 691 /*
692 692 * Handle a xen console tx interrupt.
693 693 */
694 694 /*ARGSUSED*/
695 695 static void
696 696 xencons_txint(struct xencons *xcp)
697 697 {
698 698 struct asyncline *async;
699 699
700 700 DEBUGCONT0(XENCONS_DEBUG_PROCS, "xencons_txint\n");
701 701
702 702 /*
703 703 * prevent recursive entry
704 704 */
705 705 if (mutex_owner(&xcp->excl) == curthread) {
706 706 goto out;
707 707 }
708 708
709 709 mutex_enter(&xcp->excl);
710 710 if (xencons_console == NULL) {
711 711 mutex_exit(&xcp->excl);
712 712 goto out;
713 713 }
714 714
715 715 /* make sure the device is open */
716 716 async = xcp->priv;
717 717 if ((async->async_flags & ASYNC_ISOPEN) != 0)
718 718 xcasync_start(async);
719 719
720 720 mutex_exit(&xcp->excl);
721 721 out:
722 722 DEBUGCONT0(XENCONS_DEBUG_PROCS, "xencons_txint: done\n");
723 723 }
724 724
725 725
726 726 /*
727 727 * Get an event when input ring becomes not empty or output ring becomes not
728 728 * full.
729 729 */
730 730 static uint_t
731 731 xenconsintr(caddr_t arg)
732 732 {
733 733 struct xencons *xcp = (struct xencons *)arg;
734 734 volatile struct xencons_interface *ifp = xcp->ifp;
735 735
736 736 if (ifp->in_prod != ifp->in_cons)
737 737 xencons_rxint(xcp);
738 738 if (ifp->out_prod - ifp->out_cons < sizeof (ifp->out))
739 739 xencons_txint(xcp);
740 740 return (DDI_INTR_CLAIMED);
741 741 }
742 742
743 743 /*
744 744 * Console interrupt routine for priviliged domains
745 745 */
746 746 static uint_t
747 747 xenconsintr_priv(caddr_t arg)
748 748 {
749 749 struct xencons *xcp = (struct xencons *)arg;
750 750
751 751 xencons_rxint(xcp);
752 752 xencons_txint(xcp);
753 753 return (DDI_INTR_CLAIMED);
754 754 }
755 755
756 756 /*
757 757 * Start output on a line, unless it's busy, frozen, or otherwise.
758 758 */
759 759 /*ARGSUSED*/
760 760 static void
761 761 xcasync_start(struct asyncline *async)
762 762 {
763 763 struct xencons *xcp = async->async_common;
764 764 int cc;
765 765 queue_t *q;
766 766 mblk_t *bp;
767 767 int len, space, blen;
768 768 mblk_t *nbp;
769 769
770 770 #ifdef DEBUG
771 771 int instance = xcp->unit;
772 772
773 773 DEBUGCONT1(XENCONS_DEBUG_PROCS, "async%d_nstart\n", instance);
774 774 #endif
775 775 ASSERT(mutex_owned(&xcp->excl));
776 776
777 777 /*
778 778 * Check only pended sw input flow control.
779 779 */
780 780 domore:
781 781 (void) xcasync_flowcontrol_sw_input(xcp, FLOW_CHECK, IN_FLOW_NULL);
782 782
783 783 if ((q = async->async_ttycommon.t_writeq) == NULL) {
784 784 return; /* not attached to a stream */
785 785 }
786 786
787 787 for (;;) {
788 788 if ((bp = getq(q)) == NULL)
789 789 return; /* no data to transmit */
790 790
791 791 /*
792 792 * We have a message block to work on.
793 793 * Check whether it's a break, a delay, or an ioctl (the latter
794 794 * occurs if the ioctl in question was waiting for the output
795 795 * to drain). If it's one of those, process it immediately.
796 796 */
797 797 switch (bp->b_datap->db_type) {
798 798
799 799 case M_IOCTL:
800 800 /*
801 801 * This ioctl was waiting for the output ahead of
802 802 * it to drain; obviously, it has. Do it, and
803 803 * then grab the next message after it.
804 804 */
805 805 mutex_exit(&xcp->excl);
806 806 xcasync_ioctl(async, q, bp);
807 807 mutex_enter(&xcp->excl);
808 808 continue;
809 809 }
810 810
811 811 while (bp != NULL && (cc = bp->b_wptr - bp->b_rptr) == 0) {
812 812 nbp = bp->b_cont;
813 813 freeb(bp);
814 814 bp = nbp;
815 815 }
816 816 if (bp != NULL)
817 817 break;
818 818 }
819 819
820 820 /*
821 821 * We have data to transmit. If output is stopped, put
822 822 * it back and try again later.
823 823 */
824 824 if (async->async_flags & (ASYNC_SW_OUT_FLW | ASYNC_STOPPED)) {
825 825 (void) putbq(q, bp);
826 826 return;
827 827 }
828 828
829 829
830 830 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
831 831 len = 0;
832 832 space = XENCONS_WBUFSIZE;
833 833 while (bp != NULL && space) {
834 834 blen = bp->b_wptr - bp->b_rptr;
835 835 cc = min(blen, space);
836 836 bcopy(bp->b_rptr, &xencons_wbuf[len], cc);
837 837 bp->b_rptr += cc;
838 838 if (cc == blen) {
839 839 nbp = bp->b_cont;
840 840 freeb(bp);
841 841 bp = nbp;
842 842 }
843 843 space -= cc;
844 844 len += cc;
845 845 }
846 846 mutex_exit(&xcp->excl);
847 847 (void) HYPERVISOR_console_io(CONSOLEIO_write, len,
848 848 xencons_wbuf);
849 849 mutex_enter(&xcp->excl);
850 850 if (bp != NULL)
851 851 (void) putbq(q, bp); /* not done with this msg yet */
852 852 /*
853 853 * There are no completion interrupts when using the
854 854 * HYPERVISOR_console_io call to write console data
855 855 * so we loop here till we have sent all the data to the
856 856 * hypervisor.
857 857 */
858 858 goto domore;
859 859 } else {
860 860 volatile struct xencons_interface *ifp = xcp->ifp;
861 861 XENCONS_RING_IDX cons, prod;
862 862
863 863 cons = ifp->out_cons;
864 864 prod = ifp->out_prod;
865 865 membar_enter();
866 866 while (bp != NULL && ((prod - cons) < sizeof (ifp->out))) {
867 867 ifp->out[MASK_XENCONS_IDX(prod++, ifp->out)] =
868 868 *bp->b_rptr++;
869 869 if (bp->b_rptr == bp->b_wptr) {
870 870 nbp = bp->b_cont;
871 871 freeb(bp);
872 872 bp = nbp;
873 873 }
874 874 }
875 875 membar_producer();
876 876 ifp->out_prod = prod;
877 877 ec_notify_via_evtchn(xcp->evtchn);
878 878 if (bp != NULL)
879 879 (void) putbq(q, bp); /* not done with this msg yet */
880 880 }
881 881 }
882 882
883 883
884 884 /*
885 885 * Process an "ioctl" message sent down to us.
886 886 * Note that we don't need to get any locks until we are ready to access
887 887 * the hardware. Nothing we access until then is going to be altered
888 888 * outside of the STREAMS framework, so we should be safe.
889 889 */
890 890 static void
891 891 xcasync_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)
892 892 {
893 893 struct xencons *xcp = async->async_common;
894 894 tty_common_t *tp = &async->async_ttycommon;
895 895 struct iocblk *iocp;
896 896 unsigned datasize;
897 897 int error = 0;
898 898
899 899 #ifdef DEBUG
900 900 int instance = xcp->unit;
901 901
902 902 DEBUGCONT1(XENCONS_DEBUG_PROCS, "async%d_ioctl\n", instance);
903 903 #endif
904 904
905 905 if (tp->t_iocpending != NULL) {
906 906 /*
907 907 * We were holding an "ioctl" response pending the
908 908 * availability of an "mblk" to hold data to be passed up;
909 909 * another "ioctl" came through, which means that "ioctl"
910 910 * must have timed out or been aborted.
911 911 */
912 912 freemsg(async->async_ttycommon.t_iocpending);
913 913 async->async_ttycommon.t_iocpending = NULL;
914 914 }
915 915
916 916 iocp = (struct iocblk *)mp->b_rptr;
917 917
918 918 /*
919 919 * For TIOCMGET and the PPS ioctls, do NOT call ttycommon_ioctl()
920 920 * because this function frees up the message block (mp->b_cont) that
921 921 * contains the user location where we pass back the results.
922 922 *
923 923 * Similarly, CONSOPENPOLLEDIO needs ioc_count, which ttycommon_ioctl
924 924 * zaps. We know that ttycommon_ioctl doesn't know any CONS*
925 925 * ioctls, so keep the others safe too.
926 926 */
927 927 DEBUGCONT2(XENCONS_DEBUG_IOCTL, "async%d_ioctl: %s\n",
928 928 instance,
929 929 iocp->ioc_cmd == TIOCMGET ? "TIOCMGET" :
930 930 iocp->ioc_cmd == TIOCMSET ? "TIOCMSET" :
931 931 iocp->ioc_cmd == TIOCMBIS ? "TIOCMBIS" :
932 932 iocp->ioc_cmd == TIOCMBIC ? "TIOCMBIC" : "other");
933 933
934 934 switch (iocp->ioc_cmd) {
935 935 case TIOCMGET:
936 936 case TIOCGPPS:
937 937 case TIOCSPPS:
938 938 case TIOCGPPSEV:
939 939 case CONSOPENPOLLEDIO:
940 940 case CONSCLOSEPOLLEDIO:
941 941 case CONSSETABORTENABLE:
942 942 case CONSGETABORTENABLE:
943 943 error = -1; /* Do Nothing */
944 944 break;
945 945 default:
946 946
947 947 /*
948 948 * The only way in which "ttycommon_ioctl" can fail is if the
949 949 * "ioctl" requires a response containing data to be returned
950 950 * to the user, and no mblk could be allocated for the data.
951 951 * No such "ioctl" alters our state. Thus, we always go ahead
952 952 * and do any state-changes the "ioctl" calls for. If we
953 953 * couldn't allocate the data, "ttycommon_ioctl" has stashed
954 954 * the "ioctl" away safely, so we just call "bufcall" to
955 955 * request that we be called back when we stand a better
956 956 * chance of allocating the data.
957 957 */
958 958 if ((datasize = ttycommon_ioctl(tp, wq, mp, &error)) != 0) {
959 959 if (async->async_wbufcid)
960 960 unbufcall(async->async_wbufcid);
961 961 async->async_wbufcid = bufcall(datasize, BPRI_HI,
962 962 (void (*)(void *)) xcasync_reioctl,
963 963 (void *)(intptr_t)async->async_common->unit);
964 964 return;
965 965 }
966 966 }
967 967
968 968 mutex_enter(&xcp->excl);
969 969
970 970 if (error == 0) {
971 971 /*
972 972 * "ttycommon_ioctl" did most of the work; we just use the
973 973 * data it set up.
974 974 */
975 975 switch (iocp->ioc_cmd) {
976 976
977 977 case TCSETS:
978 978 case TCSETSF:
979 979 case TCSETSW:
980 980 case TCSETA:
981 981 case TCSETAW:
982 982 case TCSETAF:
983 983 break;
984 984 }
985 985 } else if (error < 0) {
986 986 /*
987 987 * "ttycommon_ioctl" didn't do anything; we process it here.
988 988 */
989 989 error = 0;
990 990 switch (iocp->ioc_cmd) {
991 991
992 992 case TCSBRK:
993 993 error = miocpullup(mp, sizeof (int));
994 994 break;
995 995
996 996 case TIOCSBRK:
997 997 mioc2ack(mp, NULL, 0, 0);
998 998 break;
999 999
1000 1000 case TIOCCBRK:
1001 1001 mioc2ack(mp, NULL, 0, 0);
1002 1002 break;
1003 1003
1004 1004 case CONSOPENPOLLEDIO:
1005 1005 error = miocpullup(mp, sizeof (cons_polledio_arg_t));
1006 1006 if (error != 0)
1007 1007 break;
1008 1008
1009 1009 *(cons_polledio_arg_t *)mp->b_cont->b_rptr =
1010 1010 (cons_polledio_arg_t)&xcp->polledio;
1011 1011
1012 1012 mp->b_datap->db_type = M_IOCACK;
1013 1013 break;
1014 1014
1015 1015 case CONSCLOSEPOLLEDIO:
1016 1016 mp->b_datap->db_type = M_IOCACK;
1017 1017 iocp->ioc_error = 0;
1018 1018 iocp->ioc_rval = 0;
1019 1019 break;
1020 1020
1021 1021 case CONSSETABORTENABLE:
1022 1022 error = secpolicy_console(iocp->ioc_cr);
1023 1023 if (error != 0)
1024 1024 break;
1025 1025
1026 1026 if (iocp->ioc_count != TRANSPARENT) {
1027 1027 error = EINVAL;
1028 1028 break;
1029 1029 }
1030 1030
1031 1031 if (*(intptr_t *)mp->b_cont->b_rptr)
1032 1032 xcp->flags |= ASY_CONSOLE;
1033 1033 else
1034 1034 xcp->flags &= ~ASY_CONSOLE;
1035 1035
1036 1036 mp->b_datap->db_type = M_IOCACK;
1037 1037 iocp->ioc_error = 0;
1038 1038 iocp->ioc_rval = 0;
1039 1039 break;
1040 1040
1041 1041 case CONSGETABORTENABLE:
1042 1042 /*CONSTANTCONDITION*/
1043 1043 ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *));
1044 1044 /*
1045 1045 * Store the return value right in the payload
1046 1046 * we were passed. Crude.
1047 1047 */
1048 1048 mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);
1049 1049 *(boolean_t *)mp->b_cont->b_rptr =
1050 1050 (xcp->flags & ASY_CONSOLE) != 0;
1051 1051 break;
1052 1052
1053 1053 default:
1054 1054 /*
1055 1055 * If we don't understand it, it's an error. NAK it.
1056 1056 */
1057 1057 error = EINVAL;
1058 1058 break;
1059 1059 }
1060 1060 }
1061 1061 if (error != 0) {
1062 1062 iocp->ioc_error = error;
1063 1063 mp->b_datap->db_type = M_IOCNAK;
1064 1064 }
1065 1065 mutex_exit(&xcp->excl);
1066 1066 qreply(wq, mp);
1067 1067 DEBUGCONT1(XENCONS_DEBUG_PROCS, "async%d_ioctl: done\n", instance);
1068 1068 }
1069 1069
1070 1070 static int
1071 1071 xenconsrsrv(queue_t *q)
1072 1072 {
1073 1073 mblk_t *bp;
1074 1074
1075 1075 while (canputnext(q) && (bp = getq(q)))
1076 1076 putnext(q, bp);
1077 1077 return (0);
1078 1078 }
1079 1079
1080 1080 /*
1081 1081 * Put procedure for write queue.
1082 1082 * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
1083 1083 * set the flow control character for M_STOPI and M_STARTI messages;
1084 1084 * queue up M_BREAK, M_DELAY, and M_DATA messages for processing
1085 1085 * by the start routine, and then call the start routine; discard
1086 1086 * everything else. Note that this driver does not incorporate any
1087 1087 * mechanism to negotiate to handle the canonicalization process.
1088 1088 * It expects that these functions are handled in upper module(s),
1089 1089 * as we do in ldterm.
1090 1090 */
1091 1091 static int
1092 1092 xenconswput(queue_t *q, mblk_t *mp)
1093 1093 {
1094 1094 struct asyncline *async;
1095 1095 struct xencons *xcp;
1096 1096
1097 1097 async = (struct asyncline *)q->q_ptr;
1098 1098 xcp = async->async_common;
1099 1099
1100 1100 switch (mp->b_datap->db_type) {
1101 1101
1102 1102 case M_STOP:
1103 1103 mutex_enter(&xcp->excl);
1104 1104 async->async_flags |= ASYNC_STOPPED;
1105 1105 mutex_exit(&xcp->excl);
1106 1106 freemsg(mp);
1107 1107 break;
1108 1108
1109 1109 case M_START:
1110 1110 mutex_enter(&xcp->excl);
1111 1111 if (async->async_flags & ASYNC_STOPPED) {
1112 1112 async->async_flags &= ~ASYNC_STOPPED;
1113 1113 xcasync_start(async);
1114 1114 }
1115 1115 mutex_exit(&xcp->excl);
1116 1116 freemsg(mp);
1117 1117 break;
1118 1118
1119 1119 case M_IOCTL:
1120 1120 switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
1121 1121
1122 1122 case TCSETSW:
1123 1123 case TCSETSF:
1124 1124 case TCSETAW:
1125 1125 case TCSETAF:
1126 1126 /*
1127 1127 * The changes do not take effect until all
1128 1128 * output queued before them is drained.
1129 1129 * Put this message on the queue, so that
1130 1130 * "xcasync_start" will see it when it's done
1131 1131 * with the output before it. Poke the
1132 1132 * start routine, just in case.
1133 1133 */
1134 1134 (void) putq(q, mp);
1135 1135 mutex_enter(&xcp->excl);
1136 1136 xcasync_start(async);
1137 1137 mutex_exit(&xcp->excl);
1138 1138 break;
1139 1139
1140 1140 default:
1141 1141 /*
1142 1142 * Do it now.
1143 1143 */
1144 1144 xcasync_ioctl(async, q, mp);
1145 1145 break;
1146 1146 }
1147 1147 break;
1148 1148
1149 1149 case M_FLUSH:
1150 1150 if (*mp->b_rptr & FLUSHW) {
1151 1151 mutex_enter(&xcp->excl);
1152 1152 /*
1153 1153 * Flush our write queue.
1154 1154 */
1155 1155 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */
1156 1156 if (async->async_xmitblk != NULL) {
1157 1157 freeb(async->async_xmitblk);
1158 1158 async->async_xmitblk = NULL;
1159 1159 }
1160 1160 mutex_exit(&xcp->excl);
1161 1161 *mp->b_rptr &= ~FLUSHW; /* it has been flushed */
1162 1162 }
1163 1163 if (*mp->b_rptr & FLUSHR) {
1164 1164 flushq(RD(q), FLUSHDATA);
1165 1165 qreply(q, mp); /* give the read queues a crack at it */
1166 1166 } else {
1167 1167 freemsg(mp);
1168 1168 }
1169 1169
1170 1170 /*
1171 1171 * We must make sure we process messages that survive the
1172 1172 * write-side flush.
1173 1173 */
1174 1174 mutex_enter(&xcp->excl);
1175 1175 xcasync_start(async);
1176 1176 mutex_exit(&xcp->excl);
1177 1177 break;
1178 1178
1179 1179 case M_BREAK:
1180 1180 case M_DELAY:
1181 1181 case M_DATA:
1182 1182 /*
1183 1183 * Queue the message up to be transmitted,
1184 1184 * and poke the start routine.
1185 1185 */
1186 1186 (void) putq(q, mp);
1187 1187 mutex_enter(&xcp->excl);
1188 1188 xcasync_start(async);
1189 1189 mutex_exit(&xcp->excl);
1190 1190 break;
1191 1191
1192 1192 case M_STOPI:
1193 1193 mutex_enter(&xcp->excl);
1194 1194 mutex_enter(&xcp->excl);
1195 1195 if (!(async->async_inflow_source & IN_FLOW_USER)) {
1196 1196 (void) xcasync_flowcontrol_sw_input(xcp, FLOW_STOP,
1197 1197 IN_FLOW_USER);
1198 1198 }
1199 1199 mutex_exit(&xcp->excl);
1200 1200 mutex_exit(&xcp->excl);
1201 1201 freemsg(mp);
1202 1202 break;
1203 1203
1204 1204 case M_STARTI:
1205 1205 mutex_enter(&xcp->excl);
1206 1206 mutex_enter(&xcp->excl);
1207 1207 if (async->async_inflow_source & IN_FLOW_USER) {
1208 1208 (void) xcasync_flowcontrol_sw_input(xcp, FLOW_START,
1209 1209 IN_FLOW_USER);
1210 1210 }
1211 1211 mutex_exit(&xcp->excl);
1212 1212 mutex_exit(&xcp->excl);
1213 1213 freemsg(mp);
1214 1214 break;
1215 1215
1216 1216 case M_CTL:
1217 1217 if (MBLKL(mp) >= sizeof (struct iocblk) &&
1218 1218 ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) {
1219 1219 ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX;
1220 1220 qreply(q, mp);
1221 1221 } else {
1222 1222 freemsg(mp);
1223 1223 }
1224 1224 break;
1225 1225
1226 1226 default:
1227 1227 freemsg(mp);
1228 1228 break;
1229 1229 }
1230 1230 return (0);
1231 1231 }
1232 1232
1233 1233 /*
1234 1234 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
1235 1235 * the buffer we need.
1236 1236 */
1237 1237 static void
1238 1238 xcasync_reioctl(void *unit)
1239 1239 {
1240 1240 int instance = (uintptr_t)unit;
1241 1241 struct asyncline *async;
1242 1242 struct xencons *xcp;
1243 1243 queue_t *q;
1244 1244 mblk_t *mp;
1245 1245
1246 1246 xcp = ddi_get_soft_state(xencons_soft_state, instance);
1247 1247 ASSERT(xcp != NULL);
1248 1248 async = xcp->priv;
1249 1249
1250 1250 /*
1251 1251 * The bufcall is no longer pending.
1252 1252 */
1253 1253 mutex_enter(&xcp->excl);
1254 1254 async->async_wbufcid = 0;
1255 1255 if ((q = async->async_ttycommon.t_writeq) == NULL) {
1256 1256 mutex_exit(&xcp->excl);
1257 1257 return;
1258 1258 }
1259 1259 if ((mp = async->async_ttycommon.t_iocpending) != NULL) {
1260 1260 /* not pending any more */
1261 1261 async->async_ttycommon.t_iocpending = NULL;
1262 1262 mutex_exit(&xcp->excl);
1263 1263 xcasync_ioctl(async, q, mp);
1264 1264 } else
1265 1265 mutex_exit(&xcp->excl);
1266 1266 }
1267 1267
1268 1268
1269 1269 /*
1270 1270 * debugger/console support routines.
1271 1271 */
1272 1272
1273 1273 /*
1274 1274 * put a character out
1275 1275 * Do not use interrupts. If char is LF, put out CR, LF.
1276 1276 */
1277 1277 /*ARGSUSED*/
1278 1278 static void
1279 1279 xenconsputchar(cons_polledio_arg_t arg, uchar_t c)
1280 1280 {
1281 1281 struct xencons *xcp = xencons_console;
1282 1282 volatile struct xencons_interface *ifp = xcp->ifp;
1283 1283 XENCONS_RING_IDX prod;
1284 1284
1285 1285 if (c == '\n')
1286 1286 xenconsputchar(arg, '\r');
1287 1287
1288 1288 /*
1289 1289 * domain 0 can use the console I/O...
1290 1290 */
1291 1291 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1292 1292 char buffer[1];
1293 1293
1294 1294 buffer[0] = c;
1295 1295 (void) HYPERVISOR_console_io(CONSOLEIO_write, 1, buffer);
1296 1296 return;
1297 1297 }
1298 1298
1299 1299 /*
1300 1300 * domU has to go through dom0 virtual console.
1301 1301 */
1302 1302 while (ifp->out_prod - ifp->out_cons == sizeof (ifp->out))
1303 1303 (void) HYPERVISOR_yield();
1304 1304
1305 1305 prod = ifp->out_prod;
1306 1306 ifp->out[MASK_XENCONS_IDX(prod++, ifp->out)] = c;
1307 1307 membar_producer();
1308 1308 ifp->out_prod = prod;
1309 1309 ec_notify_via_evtchn(xcp->evtchn);
1310 1310 }
1311 1311
1312 1312 /*
1313 1313 * See if there's a character available. If no character is
1314 1314 * available, return 0. Run in polled mode, no interrupts.
1315 1315 */
1316 1316 static boolean_t
1317 1317 xenconsischar(cons_polledio_arg_t arg)
1318 1318 {
1319 1319 struct xencons *xcp = (struct xencons *)arg;
1320 1320 volatile struct xencons_interface *ifp = xcp->ifp;
1321 1321
1322 1322 if (xcp->polldix < xcp->polllen)
1323 1323 return (B_TRUE);
1324 1324 /*
1325 1325 * domain 0 can use the console I/O...
1326 1326 */
1327 1327 xcp->polldix = 0;
1328 1328 xcp->polllen = 0;
1329 1329 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1330 1330 xcp->polllen = HYPERVISOR_console_io(CONSOLEIO_read, 1,
1331 1331 (char *)xcp->pollbuf);
1332 1332 return (xcp->polllen != 0);
1333 1333 }
1334 1334
1335 1335 /*
1336 1336 * domU has to go through virtual console device.
1337 1337 */
1338 1338 if (ifp->in_prod != ifp->in_cons) {
1339 1339 XENCONS_RING_IDX cons;
1340 1340
1341 1341 cons = ifp->in_cons;
1342 1342 membar_enter();
1343 1343 xcp->pollbuf[0] = ifp->in[MASK_XENCONS_IDX(cons++, ifp->in)];
1344 1344 membar_producer();
1345 1345 ifp->in_cons = cons;
1346 1346 xcp->polllen = 1;
1347 1347 }
1348 1348 return (xcp->polllen != 0);
1349 1349 }
1350 1350
1351 1351 /*
1352 1352 * Get a character. Run in polled mode, no interrupts.
1353 1353 */
1354 1354 static int
1355 1355 xenconsgetchar(cons_polledio_arg_t arg)
1356 1356 {
1357 1357 struct xencons *xcp = (struct xencons *)arg;
1358 1358
1359 1359 ec_wait_on_evtchn(xcp->evtchn, (int (*)(void *))xenconsischar, arg);
1360 1360
1361 1361 return (xcp->pollbuf[xcp->polldix++]);
1362 1362 }
1363 1363
1364 1364 static void
1365 1365 xenconserror(int level, const char *fmt, ...)
1366 1366 {
1367 1367 va_list adx;
1368 1368 static time_t last;
1369 1369 static const char *lastfmt;
1370 1370 time_t now;
1371 1371
1372 1372 /*
1373 1373 * Don't print the same error message too often.
1374 1374 * Print the message only if we have not printed the
1375 1375 * message within the last second.
1376 1376 * Note: that fmt cannot be a pointer to a string
1377 1377 * stored on the stack. The fmt pointer
1378 1378 * must be in the data segment otherwise lastfmt would point
1379 1379 * to non-sense.
1380 1380 */
1381 1381 now = gethrestime_sec();
1382 1382 if (last == now && lastfmt == fmt)
1383 1383 return;
1384 1384
1385 1385 last = now;
1386 1386 lastfmt = fmt;
1387 1387
1388 1388 va_start(adx, fmt);
1389 1389 vcmn_err(level, fmt, adx);
1390 1390 va_end(adx);
1391 1391 }
1392 1392
1393 1393
1394 1394 /*
1395 1395 * Check for abort character sequence
1396 1396 */
1397 1397 static boolean_t
1398 1398 abort_charseq_recognize(uchar_t ch)
1399 1399 {
1400 1400 static int state = 0;
1401 1401 #define CNTRL(c) ((c)&037)
1402 1402 static char sequence[] = { '\r', '~', CNTRL('b') };
1403 1403
1404 1404 if (ch == sequence[state]) {
1405 1405 if (++state >= sizeof (sequence)) {
1406 1406 state = 0;
1407 1407 return (B_TRUE);
1408 1408 }
1409 1409 } else {
1410 1410 state = (ch == sequence[0]) ? 1 : 0;
1411 1411 }
1412 1412 return (B_FALSE);
1413 1413 }
1414 1414
1415 1415 /*
1416 1416 * Flow control functions
1417 1417 */
1418 1418
1419 1419 /*
1420 1420 * Software output flow control
1421 1421 * This function can be executed sucessfully at any situation.
1422 1422 * It does not handle HW, and just change the SW output flow control flag.
1423 1423 * INPUT VALUE of onoff:
1424 1424 * FLOW_START means to clear SW output flow control flag,
1425 1425 * also set ASYNC_OUT_FLW_RESUME.
1426 1426 * FLOW_STOP means to set SW output flow control flag,
1427 1427 * also clear ASYNC_OUT_FLW_RESUME.
1428 1428 */
1429 1429 static void
1430 1430 xcasync_flowcontrol_sw_output(struct xencons *xcp, async_flowc_action onoff)
1431 1431 {
1432 1432 struct asyncline *async = xcp->priv;
1433 1433 int instance = xcp->unit;
1434 1434
1435 1435 ASSERT(mutex_owned(&xcp->excl));
1436 1436
1437 1437 if (!(async->async_ttycommon.t_iflag & IXON))
1438 1438 return;
1439 1439
1440 1440 switch (onoff) {
1441 1441 case FLOW_STOP:
1442 1442 async->async_flags |= ASYNC_SW_OUT_FLW;
1443 1443 async->async_flags &= ~ASYNC_OUT_FLW_RESUME;
1444 1444 DEBUGCONT1(XENCONS_DEBUG_SFLOW,
1445 1445 "xencons%d: output sflow stop\n", instance);
1446 1446 break;
1447 1447 case FLOW_START:
1448 1448 async->async_flags &= ~ASYNC_SW_OUT_FLW;
1449 1449 async->async_flags |= ASYNC_OUT_FLW_RESUME;
1450 1450 DEBUGCONT1(XENCONS_DEBUG_SFLOW,
1451 1451 "xencons%d: output sflow start\n", instance);
1452 1452 break;
1453 1453 default:
1454 1454 break;
1455 1455 }
1456 1456 }
1457 1457
1458 1458 /*
1459 1459 * Software input flow control
1460 1460 * This function can execute software input flow control
1461 1461 * INPUT VALUE of onoff:
1462 1462 * FLOW_START means to send out a XON char
1463 1463 * and clear SW input flow control flag.
1464 1464 * FLOW_STOP means to send out a XOFF char
1465 1465 * and set SW input flow control flag.
1466 1466 * FLOW_CHECK means to check whether there is pending XON/XOFF
1467 1467 * if it is true, send it out.
1468 1468 * INPUT VALUE of type:
1469 1469 * IN_FLOW_STREAMS means flow control is due to STREAMS
1470 1470 * IN_FLOW_USER means flow control is due to user's commands
1471 1471 * RETURN VALUE: B_FALSE means no flow control char is sent
1472 1472 * B_TRUE means one flow control char is sent
1473 1473 */
1474 1474 static boolean_t
1475 1475 xcasync_flowcontrol_sw_input(struct xencons *xcp, async_flowc_action onoff,
1476 1476 int type)
1477 1477 {
1478 1478 struct asyncline *async = xcp->priv;
1479 1479 int instance = xcp->unit;
1480 1480 int rval = B_FALSE;
1481 1481
1482 1482 ASSERT(mutex_owned(&xcp->excl));
1483 1483
1484 1484 if (!(async->async_ttycommon.t_iflag & IXOFF))
1485 1485 return (rval);
1486 1486
1487 1487 /*
1488 1488 * If we get this far, then we know IXOFF is set.
1489 1489 */
1490 1490 switch (onoff) {
1491 1491 case FLOW_STOP:
1492 1492 async->async_inflow_source |= type;
1493 1493
1494 1494 /*
1495 1495 * We'll send an XOFF character for each of up to
1496 1496 * three different input flow control attempts to stop input.
1497 1497 * If we already send out one XOFF, but FLOW_STOP comes again,
1498 1498 * it seems that input flow control becomes more serious,
1499 1499 * then send XOFF again.
1500 1500 */
1501 1501 if (async->async_inflow_source & (IN_FLOW_STREAMS |
1502 1502 IN_FLOW_USER))
1503 1503 async->async_flags |= ASYNC_SW_IN_FLOW |
1504 1504 ASYNC_SW_IN_NEEDED;
1505 1505 DEBUGCONT2(XENCONS_DEBUG_SFLOW, "xencons%d: input sflow stop, "
1506 1506 "type = %x\n", instance, async->async_inflow_source);
1507 1507 break;
1508 1508 case FLOW_START:
1509 1509 async->async_inflow_source &= ~type;
1510 1510 if (async->async_inflow_source == 0) {
1511 1511 async->async_flags = (async->async_flags &
1512 1512 ~ASYNC_SW_IN_FLOW) | ASYNC_SW_IN_NEEDED;
1513 1513 DEBUGCONT1(XENCONS_DEBUG_SFLOW, "xencons%d: "
1514 1514 "input sflow start\n", instance);
1515 1515 }
1516 1516 break;
1517 1517 default:
1518 1518 break;
1519 1519 }
1520 1520
1521 1521 if (async->async_flags & ASYNC_SW_IN_NEEDED) {
1522 1522 /*
1523 1523 * If we get this far, then we know we need to send out
1524 1524 * XON or XOFF char.
1525 1525 */
1526 1526 char c;
1527 1527
1528 1528 rval = B_TRUE;
1529 1529 c = (async->async_flags & ASYNC_SW_IN_FLOW) ?
1530 1530 async->async_stopc : async->async_startc;
1531 1531 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1532 1532 (void) HYPERVISOR_console_io(CONSOLEIO_write, 1, &c);
1533 1533 async->async_flags &= ~ASYNC_SW_IN_NEEDED;
1534 1534 return (rval);
1535 1535 } else {
1536 1536 xenconsputchar(NULL, c);
1537 1537 }
1538 1538 }
1539 1539 return (rval);
1540 1540 }
1541 1541
1542 1542 struct module_info xencons_info = {
1543 1543 0,
1544 1544 "xencons",
1545 1545 0,
1546 1546 INFPSZ,
1547 1547 4096,
1548 1548 128
1549 1549 };
1550 1550
1551 1551 static struct qinit xencons_rint = {
1552 1552 putq,
1553 1553 xenconsrsrv,
1554 1554 xenconsopen,
1555 1555 xenconsclose,
1556 1556 NULL,
1557 1557 &xencons_info,
1558 1558 NULL
1559 1559 };
1560 1560
1561 1561 static struct qinit xencons_wint = {
1562 1562 xenconswput,
1563 1563 NULL,
1564 1564 NULL,
1565 1565 NULL,
1566 1566 NULL,
1567 1567 &xencons_info,
1568 1568 NULL
1569 1569 };
1570 1570
1571 1571 struct streamtab xencons_str_info = {
1572 1572 &xencons_rint,
1573 1573 &xencons_wint,
1574 1574 NULL,
1575 1575 NULL
1576 1576 };
1577 1577
1578 1578 static struct cb_ops cb_xencons_ops = {
1579 1579 nodev, /* cb_open */
1580 1580 nodev, /* cb_close */
1581 1581 nodev, /* cb_strategy */
1582 1582 nodev, /* cb_print */
1583 1583 nodev, /* cb_dump */
1584 1584 nodev, /* cb_read */
1585 1585 nodev, /* cb_write */
1586 1586 nodev, /* cb_ioctl */
1587 1587 nodev, /* cb_devmap */
1588 1588 nodev, /* cb_mmap */
1589 1589 nodev, /* cb_segmap */
1590 1590 nochpoll, /* cb_chpoll */
1591 1591 ddi_prop_op, /* cb_prop_op */
1592 1592 &xencons_str_info, /* cb_stream */
1593 1593 D_MP /* cb_flag */
1594 1594 };
1595 1595
1596 1596 struct dev_ops xencons_ops = {
1597 1597 DEVO_REV, /* devo_rev */
1598 1598 0, /* devo_refcnt */
1599 1599 xenconsinfo, /* devo_getinfo */
1600 1600 nulldev, /* devo_identify */
1601 1601 nulldev, /* devo_probe */
1602 1602 xenconsattach, /* devo_attach */
1603 1603 xenconsdetach, /* devo_detach */
1604 1604 nodev, /* devo_reset */
1605 1605 &cb_xencons_ops, /* devo_cb_ops */
1606 1606 NULL, /* devo_bus_ops */
1607 1607 NULL, /* devo_power */
1608 1608 ddi_quiesce_not_needed, /* devo_quiesce */
↓ open down ↓ |
1608 lines elided |
↑ open up ↑ |
1609 1609 };
1610 1610
1611 1611 static struct modldrv modldrv = {
1612 1612 &mod_driverops, /* Type of module. This one is a driver */
1613 1613 "virtual console driver",
1614 1614 &xencons_ops, /* driver ops */
1615 1615 };
1616 1616
1617 1617 static struct modlinkage modlinkage = {
1618 1618 MODREV_1,
1619 - (void *)&modldrv,
1620 - NULL
1619 + { (void *)&modldrv, NULL }
1621 1620 };
1622 1621
1623 1622 int
1624 1623 _init(void)
1625 1624 {
1626 1625 int rv;
1627 1626
1628 1627 if ((rv = ddi_soft_state_init(&xencons_soft_state,
1629 1628 sizeof (struct xencons), 1)) != 0)
1630 1629 return (rv);
1631 1630 if ((rv = mod_install(&modlinkage)) != 0) {
1632 1631 ddi_soft_state_fini(&xencons_soft_state);
1633 1632 return (rv);
1634 1633 }
1635 1634 DEBUGCONT2(XENCONS_DEBUG_INIT, "%s, debug = %x\n",
1636 1635 modldrv.drv_linkinfo, debug);
1637 1636 return (0);
1638 1637 }
1639 1638
1640 1639 int
1641 1640 _fini(void)
1642 1641 {
1643 1642 int rv;
1644 1643
1645 1644 if ((rv = mod_remove(&modlinkage)) != 0)
1646 1645 return (rv);
1647 1646
1648 1647 ddi_soft_state_fini(&xencons_soft_state);
1649 1648 return (0);
1650 1649 }
1651 1650
1652 1651 int
1653 1652 _info(struct modinfo *modinfop)
1654 1653 {
1655 1654 return (mod_info(&modlinkage, modinfop));
1656 1655 }
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX