[PATCH] solaris emulation: incorrect tty locking
[linux-2.6] / drivers / char / viocons.c
1 /* -*- linux-c -*-
2  *
3  *  drivers/char/viocons.c
4  *
5  *  iSeries Virtual Terminal
6  *
7  *  Authors: Dave Boutcher <boutcher@us.ibm.com>
8  *           Ryan Arnold <ryanarn@us.ibm.com>
9  *           Colin Devilbiss <devilbis@us.ibm.com>
10  *           Stephen Rothwell <sfr@au1.ibm.com>
11  *
12  * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation
13  *
14  * This program is free software;  you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) anyu later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27  */
28 #include <linux/kernel.h>
29 #include <linux/proc_fs.h>
30 #include <linux/errno.h>
31 #include <linux/vmalloc.h>
32 #include <linux/mm.h>
33 #include <linux/console.h>
34 #include <linux/module.h>
35 #include <asm/uaccess.h>
36 #include <linux/init.h>
37 #include <linux/wait.h>
38 #include <linux/spinlock.h>
39 #include <asm/ioctls.h>
40 #include <linux/kd.h>
41 #include <linux/tty.h>
42 #include <linux/tty_flip.h>
43 #include <linux/sysrq.h>
44
45 #include <asm/iseries/vio.h>
46 #include <asm/iseries/hv_lp_event.h>
47 #include <asm/iseries/hv_call_event.h>
48 #include <asm/iseries/hv_lp_config.h>
49 #include <asm/iseries/hv_call.h>
50
51 #ifdef CONFIG_VT
52 #error You must turn off CONFIG_VT to use CONFIG_VIOCONS
53 #endif
54
55 #define VIOTTY_MAGIC (0x0DCB)
56 #define VTTY_PORTS 10
57
58 #define VIOCONS_KERN_WARN       KERN_WARNING "viocons: "
59 #define VIOCONS_KERN_INFO       KERN_INFO "viocons: "
60
61 static DEFINE_SPINLOCK(consolelock);
62 static DEFINE_SPINLOCK(consoleloglock);
63
64 #ifdef CONFIG_MAGIC_SYSRQ
65 static int vio_sysrq_pressed;
66 extern int sysrq_enabled;
67 #endif
68
69 #define VIOCHAR_NUM_BUF         16
70
71 /*
72  * Our port information.  We store a pointer to one entry in the
73  * tty_driver_data
74  */
75 static struct port_info {
76         int magic;
77         struct tty_struct *tty;
78         HvLpIndex lp;
79         u8 vcons;
80         u64 seq;        /* sequence number of last HV send */
81         u64 ack;        /* last ack from HV */
82 /*
83  * When we get writes faster than we can send it to the partition,
84  * buffer the data here. Note that used is a bit map of used buffers.
85  * It had better have enough bits to hold VIOCHAR_NUM_BUF the bitops assume
86  * it is a multiple of unsigned long
87  */
88         unsigned long used;
89         u8 *buffer[VIOCHAR_NUM_BUF];
90         int bufferBytes[VIOCHAR_NUM_BUF];
91         int curbuf;
92         int bufferOverflow;
93         int overflowMessage;
94 } port_info[VTTY_PORTS];
95
96 #define viochar_is_console(pi)  ((pi) == &port_info[0])
97 #define viochar_port(pi)        ((pi) - &port_info[0])
98
99 static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
100
101 static struct tty_driver *viotty_driver;
102
103 static void hvlog(char *fmt, ...)
104 {
105         int i;
106         unsigned long flags;
107         va_list args;
108         static char buf[256];
109
110         spin_lock_irqsave(&consoleloglock, flags);
111         va_start(args, fmt);
112         i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
113         va_end(args);
114         buf[i++] = '\r';
115         HvCall_writeLogBuffer(buf, i);
116         spin_unlock_irqrestore(&consoleloglock, flags);
117 }
118
119 static void hvlogOutput(const char *buf, int count)
120 {
121         unsigned long flags;
122         int begin;
123         int index;
124         static const char cr = '\r';
125
126         begin = 0;
127         spin_lock_irqsave(&consoleloglock, flags);
128         for (index = 0; index < count; index++) {
129                 if (buf[index] == '\n') {
130                         /*
131                          * Start right after the last '\n' or at the zeroth
132                          * array position and output the number of characters
133                          * including the newline.
134                          */
135                         HvCall_writeLogBuffer(&buf[begin], index - begin + 1);
136                         begin = index + 1;
137                         HvCall_writeLogBuffer(&cr, 1);
138                 }
139         }
140         if ((index - begin) > 0)
141                 HvCall_writeLogBuffer(&buf[begin], index - begin);
142         spin_unlock_irqrestore(&consoleloglock, flags);
143 }
144
145 /*
146  * Make sure we're pointing to a valid port_info structure.  Shamelessly
147  * plagerized from serial.c
148  */
149 static inline int viotty_paranoia_check(struct port_info *pi,
150                                         char *name, const char *routine)
151 {
152         static const char *bad_pi_addr = VIOCONS_KERN_WARN
153                 "warning: bad address for port_info struct (%s) in %s\n";
154         static const char *badmagic = VIOCONS_KERN_WARN
155                 "warning: bad magic number for port_info struct (%s) in %s\n";
156
157         if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) {
158                 printk(bad_pi_addr, name, routine);
159                 return 1;
160         }
161         if (pi->magic != VIOTTY_MAGIC) {
162                 printk(badmagic, name, routine);
163                 return 1;
164         }
165         return 0;
166 }
167
168 /*
169  * Add data to our pending-send buffers.  
170  *
171  * NOTE: Don't use printk in here because it gets nastily recursive.
172  * hvlog can be used to log to the hypervisor buffer
173  */
174 static int buffer_add(struct port_info *pi, const char *buf, size_t len)
175 {
176         size_t bleft;
177         size_t curlen;
178         const char *curbuf;
179         int nextbuf;
180
181         curbuf = buf;
182         bleft = len;
183         while (bleft > 0) {
184                 /*
185                  * If there is no space left in the current buffer, we have
186                  * filled everything up, so return.  If we filled the previous
187                  * buffer we would already have moved to the next one.
188                  */
189                 if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
190                         hvlog ("\n\rviocons: No overflow buffer available for memcpy().\n");
191                         pi->bufferOverflow++;
192                         pi->overflowMessage = 1;
193                         break;
194                 }
195
196                 /*
197                  * Turn on the "used" bit for this buffer.  If it's already on,
198                  * that's fine.
199                  */
200                 set_bit(pi->curbuf, &pi->used);
201
202                 /*
203                  * See if this buffer has been allocated.  If not, allocate it.
204                  */
205                 if (pi->buffer[pi->curbuf] == NULL) {
206                         pi->buffer[pi->curbuf] =
207                             kmalloc(VIOCHAR_MAX_DATA, GFP_ATOMIC);
208                         if (pi->buffer[pi->curbuf] == NULL) {
209                                 hvlog("\n\rviocons: kmalloc failed allocating spaces for buffer %d.",
210                                         pi->curbuf);
211                                 break;
212                         }
213                 }
214
215                 /* Figure out how much we can copy into this buffer. */
216                 if (bleft < (VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf]))
217                         curlen = bleft;
218                 else
219                         curlen = VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf];
220
221                 /* Copy the data into the buffer. */
222                 memcpy(pi->buffer[pi->curbuf] + pi->bufferBytes[pi->curbuf],
223                                 curbuf, curlen);
224
225                 pi->bufferBytes[pi->curbuf] += curlen;
226                 curbuf += curlen;
227                 bleft -= curlen;
228
229                 /*
230                  * Now see if we've filled this buffer.  If not then
231                  * we'll try to use it again later.  If we've filled it
232                  * up then we'll advance the curbuf to the next in the
233                  * circular queue.
234                  */
235                 if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
236                         nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
237                         /*
238                          * Move to the next buffer if it hasn't been used yet
239                          */
240                         if (test_bit(nextbuf, &pi->used) == 0)
241                                 pi->curbuf = nextbuf;
242                 }
243         }
244         return len - bleft;
245 }
246
247 /*
248  * Send pending data
249  *
250  * NOTE: Don't use printk in here because it gets nastily recursive.
251  * hvlog can be used to log to the hypervisor buffer
252  */
253 static void send_buffers(struct port_info *pi)
254 {
255         HvLpEvent_Rc hvrc;
256         int nextbuf;
257         struct viocharlpevent *viochar;
258         unsigned long flags;
259
260         spin_lock_irqsave(&consolelock, flags);
261
262         viochar = (struct viocharlpevent *)
263             vio_get_event_buffer(viomajorsubtype_chario);
264
265         /* Make sure we got a buffer */
266         if (viochar == NULL) {
267                 hvlog("\n\rviocons: Can't get viochar buffer in sendBuffers().");
268                 spin_unlock_irqrestore(&consolelock, flags);
269                 return;
270         }
271
272         if (pi->used == 0) {
273                 hvlog("\n\rviocons: in sendbuffers(), but no buffers used.\n");
274                 vio_free_event_buffer(viomajorsubtype_chario, viochar);
275                 spin_unlock_irqrestore(&consolelock, flags);
276                 return;
277         }
278
279         /*
280          * curbuf points to the buffer we're filling.  We want to
281          * start sending AFTER this one.  
282          */
283         nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
284
285         /*
286          * Loop until we find a buffer with the used bit on
287          */
288         while (test_bit(nextbuf, &pi->used) == 0)
289                 nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
290
291         initDataEvent(viochar, pi->lp);
292
293         /*
294          * While we have buffers with data, and our send window
295          * is open, send them
296          */
297         while ((test_bit(nextbuf, &pi->used)) &&
298                ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
299                 viochar->len = pi->bufferBytes[nextbuf];
300                 viochar->event.xCorrelationToken = pi->seq++;
301                 viochar->event.xSizeMinus1 =
302                         offsetof(struct viocharlpevent, data) + viochar->len;
303
304                 memcpy(viochar->data, pi->buffer[nextbuf], viochar->len);
305
306                 hvrc = HvCallEvent_signalLpEvent(&viochar->event);
307                 if (hvrc) {
308                         /*
309                          * MUST unlock the spinlock before doing a printk
310                          */
311                         vio_free_event_buffer(viomajorsubtype_chario, viochar);
312                         spin_unlock_irqrestore(&consolelock, flags);
313
314                         printk(VIOCONS_KERN_WARN
315                                "error sending event! return code %d\n",
316                                (int)hvrc);
317                         return;
318                 }
319
320                 /*
321                  * clear the used bit, zero the number of bytes in
322                  * this buffer, and move to the next buffer
323                  */
324                 clear_bit(nextbuf, &pi->used);
325                 pi->bufferBytes[nextbuf] = 0;
326                 nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
327         }
328
329         /*
330          * If we have emptied all the buffers, start at 0 again.
331          * this will re-use any allocated buffers
332          */
333         if (pi->used == 0) {
334                 pi->curbuf = 0;
335
336                 if (pi->overflowMessage)
337                         pi->overflowMessage = 0;
338
339                 if (pi->tty) {
340                         tty_wakeup(pi->tty);
341                 }
342         }
343
344         vio_free_event_buffer(viomajorsubtype_chario, viochar);
345         spin_unlock_irqrestore(&consolelock, flags);
346 }
347
348 /*
349  * Our internal writer.  Gets called both from the console device and
350  * the tty device.  the tty pointer will be NULL if called from the console.
351  * Return total number of bytes "written".
352  *
353  * NOTE: Don't use printk in here because it gets nastily recursive.  hvlog
354  * can be used to log to the hypervisor buffer
355  */
356 static int internal_write(struct port_info *pi, const char *buf, size_t len)
357 {
358         HvLpEvent_Rc hvrc;
359         size_t bleft;
360         size_t curlen;
361         const char *curbuf;
362         unsigned long flags;
363         struct viocharlpevent *viochar;
364
365         /*
366          * Write to the hvlog of inbound data are now done prior to
367          * calling internal_write() since internal_write() is only called in
368          * the event that an lp event path is active, which isn't the case for
369          * logging attempts prior to console initialization.
370          *
371          * If there is already data queued for this port, send it prior to
372          * attempting to send any new data.
373          */
374         if (pi->used)
375                 send_buffers(pi);
376
377         spin_lock_irqsave(&consolelock, flags);
378
379         viochar = vio_get_event_buffer(viomajorsubtype_chario);
380         if (viochar == NULL) {
381                 spin_unlock_irqrestore(&consolelock, flags);
382                 hvlog("\n\rviocons: Can't get vio buffer in internal_write().");
383                 return -EAGAIN;
384         }
385         initDataEvent(viochar, pi->lp);
386
387         curbuf = buf;
388         bleft = len;
389
390         while ((bleft > 0) && (pi->used == 0) &&
391                ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
392                 if (bleft > VIOCHAR_MAX_DATA)
393                         curlen = VIOCHAR_MAX_DATA;
394                 else
395                         curlen = bleft;
396
397                 viochar->event.xCorrelationToken = pi->seq++;
398                 memcpy(viochar->data, curbuf, curlen);
399                 viochar->len = curlen;
400                 viochar->event.xSizeMinus1 =
401                     offsetof(struct viocharlpevent, data) + curlen;
402
403                 hvrc = HvCallEvent_signalLpEvent(&viochar->event);
404                 if (hvrc) {
405                         hvlog("viocons: error sending event! %d\n", (int)hvrc);
406                         goto out;
407                 }
408                 curbuf += curlen;
409                 bleft -= curlen;
410         }
411
412         /* If we didn't send it all, buffer as much of it as we can. */
413         if (bleft > 0)
414                 bleft -= buffer_add(pi, curbuf, bleft);
415 out:
416         vio_free_event_buffer(viomajorsubtype_chario, viochar);
417         spin_unlock_irqrestore(&consolelock, flags);
418         return len - bleft;
419 }
420
421 static struct port_info *get_port_data(struct tty_struct *tty)
422 {
423         unsigned long flags;
424         struct port_info *pi;
425
426         spin_lock_irqsave(&consolelock, flags);
427         if (tty) {
428                 pi = (struct port_info *)tty->driver_data;
429                 if (!pi || viotty_paranoia_check(pi, tty->name,
430                                              "get_port_data")) {
431                         pi = NULL;
432                 }
433         } else
434                 /*
435                  * If this is the console device, use the lp from
436                  * the first port entry
437                  */
438                 pi = &port_info[0];
439         spin_unlock_irqrestore(&consolelock, flags);
440         return pi;
441 }
442
443 /*
444  * Initialize the common fields in a charLpEvent
445  */
446 static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp)
447 {
448         struct HvLpEvent *hev = &viochar->event;
449
450         memset(viochar, 0, sizeof(struct viocharlpevent));
451
452         hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
453                 HV_LP_EVENT_INT;
454         hev->xType = HvLpEvent_Type_VirtualIo;
455         hev->xSubtype = viomajorsubtype_chario | viochardata;
456         hev->xSourceLp = HvLpConfig_getLpIndex();
457         hev->xTargetLp = lp;
458         hev->xSizeMinus1 = sizeof(struct viocharlpevent);
459         hev->xSourceInstanceId = viopath_sourceinst(lp);
460         hev->xTargetInstanceId = viopath_targetinst(lp);
461 }
462
463 /*
464  * early console device write
465  */
466 static void viocons_write_early(struct console *co, const char *s, unsigned count)
467 {
468         hvlogOutput(s, count);
469 }
470
471 /*
472  * console device write
473  */
474 static void viocons_write(struct console *co, const char *s, unsigned count)
475 {
476         int index;
477         int begin;
478         struct port_info *pi;
479
480         static const char cr = '\r';
481
482         /*
483          * Check port data first because the target LP might be valid but
484          * simply not active, in which case we want to hvlog the output.
485          */
486         pi = get_port_data(NULL);
487         if (pi == NULL) {
488                 hvlog("\n\rviocons_write: unable to get port data.");
489                 return;
490         }
491
492         hvlogOutput(s, count);
493
494         if (!viopath_isactive(pi->lp))
495                 return;
496
497         /* 
498          * Any newline character found will cause a
499          * carriage return character to be emitted as well. 
500          */
501         begin = 0;
502         for (index = 0; index < count; index++) {
503                 if (s[index] == '\n') {
504                         /* 
505                          * Newline found. Print everything up to and 
506                          * including the newline
507                          */
508                         internal_write(pi, &s[begin], index - begin + 1);
509                         begin = index + 1;
510                         /* Emit a carriage return as well */
511                         internal_write(pi, &cr, 1);
512                 }
513         }
514
515         /* If any characters left to write, write them now */
516         if ((index - begin) > 0)
517                 internal_write(pi, &s[begin], index - begin);
518 }
519
520 /*
521  * Work out the device associate with this console
522  */
523 static struct tty_driver *viocons_device(struct console *c, int *index)
524 {
525         *index = c->index;
526         return viotty_driver;
527 }
528
529 /*
530  * console device I/O methods
531  */
532 static struct console viocons_early = {
533         .name = "viocons",
534         .write = viocons_write_early,
535         .flags = CON_PRINTBUFFER,
536         .index = -1,
537 };
538
539 static struct console viocons = {
540         .name = "viocons",
541         .write = viocons_write,
542         .device = viocons_device,
543         .flags = CON_PRINTBUFFER,
544         .index = -1,
545 };
546
547 /*
548  * TTY Open method
549  */
550 static int viotty_open(struct tty_struct *tty, struct file *filp)
551 {
552         int port;
553         unsigned long flags;
554         struct port_info *pi;
555
556         port = tty->index;
557
558         if ((port < 0) || (port >= VTTY_PORTS))
559                 return -ENODEV;
560
561         spin_lock_irqsave(&consolelock, flags);
562
563         pi = &port_info[port];
564         /* If some other TTY is already connected here, reject the open */
565         if ((pi->tty) && (pi->tty != tty)) {
566                 spin_unlock_irqrestore(&consolelock, flags);
567                 printk(VIOCONS_KERN_WARN
568                        "attempt to open device twice from different ttys\n");
569                 return -EBUSY;
570         }
571         tty->driver_data = pi;
572         pi->tty = tty;
573         spin_unlock_irqrestore(&consolelock, flags);
574
575         return 0;
576 }
577
578 /*
579  * TTY Close method
580  */
581 static void viotty_close(struct tty_struct *tty, struct file *filp)
582 {
583         unsigned long flags;
584         struct port_info *pi;
585
586         spin_lock_irqsave(&consolelock, flags);
587         pi = (struct port_info *)tty->driver_data;
588
589         if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) {
590                 spin_unlock_irqrestore(&consolelock, flags);
591                 return;
592         }
593         if (tty->count == 1)
594                 pi->tty = NULL;
595         spin_unlock_irqrestore(&consolelock, flags);
596 }
597
598 /*
599  * TTY Write method
600  */
601 static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
602                 int count)
603 {
604         struct port_info *pi;
605
606         pi = get_port_data(tty);
607         if (pi == NULL) {
608                 hvlog("\n\rviotty_write: no port data.");
609                 return -ENODEV;
610         }
611
612         if (viochar_is_console(pi))
613                 hvlogOutput(buf, count);
614
615         /*
616          * If the path to this LP is closed, don't bother doing anything more.
617          * just dump the data on the floor and return count.  For some reason
618          * some user level programs will attempt to probe available tty's and
619          * they'll attempt a viotty_write on an invalid port which maps to an
620          * invalid target lp.  If this is the case then ignore the
621          * viotty_write call and, since the viopath isn't active to this
622          * partition, return count.
623          */
624         if (!viopath_isactive(pi->lp))
625                 return count;
626
627         return internal_write(pi, buf, count);
628 }
629
630 /*
631  * TTY put_char method
632  */
633 static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
634 {
635         struct port_info *pi;
636
637         pi = get_port_data(tty);
638         if (pi == NULL)
639                 return;
640
641         /* This will append '\r' as well if the char is '\n' */
642         if (viochar_is_console(pi))
643                 hvlogOutput(&ch, 1);
644
645         if (viopath_isactive(pi->lp))
646                 internal_write(pi, &ch, 1);
647 }
648
649 /*
650  * TTY write_room method
651  */
652 static int viotty_write_room(struct tty_struct *tty)
653 {
654         int i;
655         int room = 0;
656         struct port_info *pi;
657         unsigned long flags;
658
659         spin_lock_irqsave(&consolelock, flags);
660         pi = (struct port_info *)tty->driver_data;
661         if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) {
662                 spin_unlock_irqrestore(&consolelock, flags);
663                 return 0;
664         }
665
666         /* If no buffers are used, return the max size. */
667         if (pi->used == 0) {
668                 spin_unlock_irqrestore(&consolelock, flags);
669                 return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF;
670         }
671
672         /*
673          * We retain the spinlock because we want to get an accurate
674          * count and it can change on us between each operation if we
675          * don't hold the spinlock.
676          */
677         for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++)
678                 room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]);
679         spin_unlock_irqrestore(&consolelock, flags);
680
681         if (room > VIOCHAR_MAX_DATA)
682                 room = VIOCHAR_MAX_DATA;
683         return room;
684 }
685
686 /*
687  * TTY chars_in_buffer method
688  */
689 static int viotty_chars_in_buffer(struct tty_struct *tty)
690 {
691         return 0;
692 }
693
694 static int viotty_ioctl(struct tty_struct *tty, struct file *file,
695                         unsigned int cmd, unsigned long arg)
696 {
697         switch (cmd) {
698         /*
699          * the ioctls below read/set the flags usually shown in the leds
700          * don't use them - they will go away without warning
701          */
702         case KDGETLED:
703         case KDGKBLED:
704                 return put_user(0, (char *)arg);
705
706         case KDSKBLED:
707                 return 0;
708         }
709
710         return n_tty_ioctl(tty, file, cmd, arg);
711 }
712
713 /*
714  * Handle an open charLpEvent.  Could be either interrupt or ack
715  */
716 static void vioHandleOpenEvent(struct HvLpEvent *event)
717 {
718         unsigned long flags;
719         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
720         u8 port = cevent->virtual_device;
721         struct port_info *pi;
722         int reject = 0;
723
724         if (hvlpevent_is_ack(event)) {
725                 if (port >= VTTY_PORTS)
726                         return;
727
728                 spin_lock_irqsave(&consolelock, flags);
729                 /* Got the lock, don't cause console output */
730
731                 pi = &port_info[port];
732                 if (event->xRc == HvLpEvent_Rc_Good) {
733                         pi->seq = pi->ack = 0;
734                         /*
735                          * This line allows connections from the primary
736                          * partition but once one is connected from the
737                          * primary partition nothing short of a reboot
738                          * of linux will allow access from the hosting
739                          * partition again without a required iSeries fix.
740                          */
741                         pi->lp = event->xTargetLp;
742                 }
743
744                 spin_unlock_irqrestore(&consolelock, flags);
745                 if (event->xRc != HvLpEvent_Rc_Good)
746                         printk(VIOCONS_KERN_WARN
747                                "handle_open_event: event->xRc == (%d).\n",
748                                event->xRc);
749
750                 if (event->xCorrelationToken != 0) {
751                         atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
752                         atomic_set(aptr, 1);
753                 } else
754                         printk(VIOCONS_KERN_WARN
755                                "weird...got open ack without atomic\n");
756                 return;
757         }
758
759         /* This had better require an ack, otherwise complain */
760         if (!hvlpevent_need_ack(event)) {
761                 printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n");
762                 return;
763         }
764
765         spin_lock_irqsave(&consolelock, flags);
766         /* Got the lock, don't cause console output */
767
768         /* Make sure this is a good virtual tty */
769         if (port >= VTTY_PORTS) {
770                 event->xRc = HvLpEvent_Rc_SubtypeError;
771                 cevent->subtype_result_code = viorc_openRejected;
772                 /*
773                  * Flag state here since we can't printk while holding
774                  * a spinlock.
775                  */
776                 reject = 1;
777         } else {
778                 pi = &port_info[port];
779                 if ((pi->lp != HvLpIndexInvalid) &&
780                                 (pi->lp != event->xSourceLp)) {
781                         /*
782                          * If this is tty is already connected to a different
783                          * partition, fail.
784                          */
785                         event->xRc = HvLpEvent_Rc_SubtypeError;
786                         cevent->subtype_result_code = viorc_openRejected;
787                         reject = 2;
788                 } else {
789                         pi->lp = event->xSourceLp;
790                         event->xRc = HvLpEvent_Rc_Good;
791                         cevent->subtype_result_code = viorc_good;
792                         pi->seq = pi->ack = 0;
793                         reject = 0;
794                 }
795         }
796
797         spin_unlock_irqrestore(&consolelock, flags);
798
799         if (reject == 1)
800                 printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n");
801         else if (reject == 2)
802                 printk(VIOCONS_KERN_WARN
803                         "open rejected: console in exclusive use by another partition.\n");
804
805         /* Return the acknowledgement */
806         HvCallEvent_ackLpEvent(event);
807 }
808
809 /*
810  * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
811  * virtual console should never actually issue a close event to the hypervisor
812  * because the virtual console never goes away.  A close event coming from the
813  * hypervisor simply means that there are no client consoles connected to the
814  * virtual console.
815  *
816  * Regardless of the number of connections masqueraded on the other side of
817  * the hypervisor ONLY ONE close event should be called to accompany the ONE
818  * open event that is called.  The close event should ONLY be called when NO
819  * MORE connections (masqueraded or not) exist on the other side of the
820  * hypervisor.
821  */
822 static void vioHandleCloseEvent(struct HvLpEvent *event)
823 {
824         unsigned long flags;
825         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
826         u8 port = cevent->virtual_device;
827
828         if (hvlpevent_is_int(event)) {
829                 if (port >= VTTY_PORTS) {
830                         printk(VIOCONS_KERN_WARN
831                                         "close message from invalid virtual device.\n");
832                         return;
833                 }
834
835                 /* For closes, just mark the console partition invalid */
836                 spin_lock_irqsave(&consolelock, flags);
837                 /* Got the lock, don't cause console output */
838
839                 if (port_info[port].lp == event->xSourceLp)
840                         port_info[port].lp = HvLpIndexInvalid;
841
842                 spin_unlock_irqrestore(&consolelock, flags);
843                 printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp);
844         } else
845                 printk(VIOCONS_KERN_WARN
846                                 "got unexpected close acknowlegement\n");
847 }
848
849 /*
850  * Handle a config charLpEvent.  Could be either interrupt or ack
851  */
852 static void vioHandleConfig(struct HvLpEvent *event)
853 {
854         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
855
856         HvCall_writeLogBuffer(cevent->data, cevent->len);
857
858         if (cevent->data[0] == 0x01)
859                 printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n",
860                        cevent->data[1], cevent->data[2],
861                        cevent->data[3], cevent->data[4]);
862         else
863                 printk(VIOCONS_KERN_WARN "unknown config event\n");
864 }
865
866 /*
867  * Handle a data charLpEvent. 
868  */
869 static void vioHandleData(struct HvLpEvent *event)
870 {
871         struct tty_struct *tty;
872         unsigned long flags;
873         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
874         struct port_info *pi;
875         int index;
876         int num_pushed;
877         u8 port = cevent->virtual_device;
878
879         if (port >= VTTY_PORTS) {
880                 printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n",
881                                 port);
882                 return;
883         }
884
885         /*
886          * Hold the spinlock so that we don't take an interrupt that
887          * changes tty between the time we fetch the port_info
888          * pointer and the time we paranoia check.
889          */
890         spin_lock_irqsave(&consolelock, flags);
891         pi = &port_info[port];
892
893         /*
894          * Change 05/01/2003 - Ryan Arnold: If a partition other than
895          * the current exclusive partition tries to send us data
896          * events then just drop them on the floor because we don't
897          * want his stinking data.  He isn't authorized to receive
898          * data because he wasn't the first one to get the console,
899          * therefore he shouldn't be allowed to send data either.
900          * This will work without an iSeries fix.
901          */
902         if (pi->lp != event->xSourceLp) {
903                 spin_unlock_irqrestore(&consolelock, flags);
904                 return;
905         }
906
907         tty = pi->tty;
908         if (tty == NULL) {
909                 spin_unlock_irqrestore(&consolelock, flags);
910                 printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n",
911                                 port);
912                 return;
913         }
914
915         if (tty->magic != TTY_MAGIC) {
916                 spin_unlock_irqrestore(&consolelock, flags);
917                 printk(VIOCONS_KERN_WARN "tty bad magic\n");
918                 return;
919         }
920
921         /*
922          * Just to be paranoid, make sure the tty points back to this port
923          */
924         pi = (struct port_info *)tty->driver_data;
925         if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) {
926                 spin_unlock_irqrestore(&consolelock, flags);
927                 return;
928         }
929         spin_unlock_irqrestore(&consolelock, flags);
930
931         /*
932          * Change 07/21/2003 - Ryan Arnold: functionality added to
933          * support sysrq utilizing ^O as the sysrq key.  The sysrq
934          * functionality will only work if built into the kernel and
935          * then only if sysrq is enabled through the proc filesystem.
936          */
937         num_pushed = 0;
938         for (index = 0; index < cevent->len; index++) {
939 #ifdef CONFIG_MAGIC_SYSRQ
940                 if (sysrq_enabled) {
941                         /* 0x0f is the ascii character for ^O */
942                         if (cevent->data[index] == '\x0f') {
943                                 vio_sysrq_pressed = 1;
944                                 /*
945                                  * continue because we don't want to add
946                                  * the sysrq key into the data string.
947                                  */
948                                 continue;
949                         } else if (vio_sysrq_pressed) {
950                                 handle_sysrq(cevent->data[index], NULL, tty);
951                                 vio_sysrq_pressed = 0;
952                                 /*
953                                  * continue because we don't want to add
954                                  * the sysrq sequence into the data string.
955                                  */
956                                 continue;
957                         }
958                 }
959 #endif
960                 /*
961                  * The sysrq sequence isn't included in this check if
962                  * sysrq is enabled and compiled into the kernel because
963                  * the sequence will never get inserted into the buffer.
964                  * Don't attempt to copy more data into the buffer than we
965                  * have room for because it would fail without indication.
966                  */
967                 if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) {
968                         printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
969                         break;
970                 }
971                 num_pushed++;
972         }
973
974         if (num_pushed)
975                 tty_flip_buffer_push(tty);
976 }
977
978 /*
979  * Handle an ack charLpEvent. 
980  */
981 static void vioHandleAck(struct HvLpEvent *event)
982 {
983         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
984         unsigned long flags;
985         u8 port = cevent->virtual_device;
986
987         if (port >= VTTY_PORTS) {
988                 printk(VIOCONS_KERN_WARN "data on invalid virtual device\n");
989                 return;
990         }
991
992         spin_lock_irqsave(&consolelock, flags);
993         port_info[port].ack = event->xCorrelationToken;
994         spin_unlock_irqrestore(&consolelock, flags);
995
996         if (port_info[port].used)
997                 send_buffers(&port_info[port]);
998 }
999
1000 /*
1001  * Handle charLpEvents and route to the appropriate routine
1002  */
1003 static void vioHandleCharEvent(struct HvLpEvent *event)
1004 {
1005         int charminor;
1006
1007         if (event == NULL)
1008                 return;
1009
1010         charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
1011         switch (charminor) {
1012         case viocharopen:
1013                 vioHandleOpenEvent(event);
1014                 break;
1015         case viocharclose:
1016                 vioHandleCloseEvent(event);
1017                 break;
1018         case viochardata:
1019                 vioHandleData(event);
1020                 break;
1021         case viocharack:
1022                 vioHandleAck(event);
1023                 break;
1024         case viocharconfig:
1025                 vioHandleConfig(event);
1026                 break;
1027         default:
1028                 if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
1029                         event->xRc = HvLpEvent_Rc_InvalidSubtype;
1030                         HvCallEvent_ackLpEvent(event);
1031                 }
1032         }
1033 }
1034
1035 /*
1036  * Send an open event
1037  */
1038 static int send_open(HvLpIndex remoteLp, void *sem)
1039 {
1040         return HvCallEvent_signalLpEventFast(remoteLp,
1041                         HvLpEvent_Type_VirtualIo,
1042                         viomajorsubtype_chario | viocharopen,
1043                         HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
1044                         viopath_sourceinst(remoteLp),
1045                         viopath_targetinst(remoteLp),
1046                         (u64)(unsigned long)sem, VIOVERSION << 16,
1047                         0, 0, 0, 0);
1048 }
1049
1050 static struct tty_operations serial_ops = {
1051         .open = viotty_open,
1052         .close = viotty_close,
1053         .write = viotty_write,
1054         .put_char = viotty_put_char,
1055         .write_room = viotty_write_room,
1056         .chars_in_buffer = viotty_chars_in_buffer,
1057         .ioctl = viotty_ioctl,
1058 };
1059
1060 static int __init viocons_init2(void)
1061 {
1062         atomic_t wait_flag;
1063         int rc;
1064
1065         /* +2 for fudge */
1066         rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
1067                         viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
1068         if (rc)
1069                 printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc);
1070
1071         if (viopath_hostLp == HvLpIndexInvalid)
1072                 vio_set_hostlp();
1073
1074         /*
1075          * And if the primary is not the same as the hosting LP, open to the 
1076          * hosting lp
1077          */
1078         if ((viopath_hostLp != HvLpIndexInvalid) &&
1079             (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
1080                 printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n",
1081                                 viopath_hostLp);
1082                 rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
1083                                 VIOCHAR_WINDOW + 2);    /* +2 for fudge */
1084                 if (rc)
1085                         printk(VIOCONS_KERN_WARN
1086                                 "error opening to partition %d: %d\n",
1087                                 viopath_hostLp, rc);
1088         }
1089
1090         if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0)
1091                 printk(VIOCONS_KERN_WARN
1092                                 "error seting handler for console events!\n");
1093
1094         /*
1095          * First, try to open the console to the hosting lp.
1096          * Wait on a semaphore for the response.
1097          */
1098         atomic_set(&wait_flag, 0);
1099         if ((viopath_isactive(viopath_hostLp)) &&
1100             (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) {
1101                 printk(VIOCONS_KERN_INFO "hosting partition %d\n",
1102                         viopath_hostLp);
1103                 while (atomic_read(&wait_flag) == 0)
1104                         mb();
1105                 atomic_set(&wait_flag, 0);
1106         }
1107
1108         /*
1109          * If we don't have an active console, try the primary
1110          */
1111         if ((!viopath_isactive(port_info[0].lp)) &&
1112             (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
1113             (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag)
1114              == 0)) {
1115                 printk(VIOCONS_KERN_INFO "opening console to primary partition\n");
1116                 while (atomic_read(&wait_flag) == 0)
1117                         mb();
1118         }
1119
1120         /* Initialize the tty_driver structure */
1121         viotty_driver = alloc_tty_driver(VTTY_PORTS);
1122         viotty_driver->owner = THIS_MODULE;
1123         viotty_driver->driver_name = "vioconsole";
1124         viotty_driver->name = "tty";
1125         viotty_driver->name_base = 1;
1126         viotty_driver->major = TTY_MAJOR;
1127         viotty_driver->minor_start = 1;
1128         viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
1129         viotty_driver->subtype = 1;
1130         viotty_driver->init_termios = tty_std_termios;
1131         viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
1132         tty_set_operations(viotty_driver, &serial_ops);
1133
1134         if (tty_register_driver(viotty_driver)) {
1135                 printk(VIOCONS_KERN_WARN "couldn't register console driver\n");
1136                 put_tty_driver(viotty_driver);
1137                 viotty_driver = NULL;
1138         }
1139
1140         unregister_console(&viocons_early);
1141         register_console(&viocons);
1142
1143         return 0;
1144 }
1145
1146 static int __init viocons_init(void)
1147 {
1148         int i;
1149
1150         printk(VIOCONS_KERN_INFO "registering console\n");
1151         for (i = 0; i < VTTY_PORTS; i++) {
1152                 port_info[i].lp = HvLpIndexInvalid;
1153                 port_info[i].magic = VIOTTY_MAGIC;
1154         }
1155         HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
1156         add_preferred_console("viocons", 0, NULL);
1157         register_console(&viocons_early);
1158         return 0;
1159 }
1160
1161 console_initcall(viocons_init);
1162 module_init(viocons_init2);