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