s390/sclp_vt220: support magic sysrequests
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Mon, 17 Aug 2015 14:13:41 +0000 (16:13 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 26 Aug 2015 15:20:45 +0000 (17:20 +0200)
Implement magic sysrequest handling for the VT220 terminal (also known as
the Integrated ASCII console on the HMC/SE).
To invoke a "magic sysrequest" function, press "Ctrl+o" followed by a
second character that designates the debugging function.

The handling of the sysrq is scheduled away from the SCLP IRQ context;
because large amounts of sysrq output might fill up the console buffers.
The console might deadlock because it cannot empty the buffers while still
in the receiving IRQ context.  This behavior is the same as for the SCLP
console.

Reported-by: Horst Weber <hweber@de.ibm.com>
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/char/sclp_vt220.c

index ae67386..68d6ee7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/wait.h>
 #include <linux/timer.h>
 #include <linux/kernel.h>
+#include <linux/sysrq.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
@@ -27,6 +28,7 @@
 
 #include <asm/uaccess.h>
 #include "sclp.h"
+#include "ctrlchar.h"
 
 #define SCLP_VT220_MAJOR               TTY_MAJOR
 #define SCLP_VT220_MINOR               65
@@ -477,6 +479,53 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
 #define        SCLP_VT220_SESSION_STARTED      0x80
 #define SCLP_VT220_SESSION_DATA                0x00
 
+#ifdef CONFIG_MAGIC_SYSRQ
+
+static int sysrq_pressed;
+static struct sysrq_work sysrq;
+
+static void sclp_vt220_reset_session(void)
+{
+       sysrq_pressed = 0;
+}
+
+static void sclp_vt220_handle_input(const char *buffer, unsigned int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               /* Handle magic sys request */
+               if (buffer[i] == ('O' ^ 0100)) { /* CTRL-O */
+                       /*
+                        * If pressed again, reset sysrq_pressed
+                        * and flip CTRL-O character
+                        */
+                       sysrq_pressed = !sysrq_pressed;
+                       if (sysrq_pressed)
+                               continue;
+               } else if (sysrq_pressed) {
+                       sysrq.key = buffer[i];
+                       schedule_sysrq_work(&sysrq);
+                       sysrq_pressed = 0;
+                       continue;
+               }
+               tty_insert_flip_char(&sclp_vt220_port, buffer[i], 0);
+       }
+}
+
+#else
+
+static void sclp_vt220_reset_session(void)
+{
+}
+
+static void sclp_vt220_handle_input(const char *buffer, unsigned int count)
+{
+       tty_insert_flip_string(&sclp_vt220_port, buffer, count);
+}
+
+#endif
+
 /*
  * Called by the SCLP to report incoming event buffers.
  */
@@ -492,12 +541,13 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
        switch (*buffer) {
        case SCLP_VT220_SESSION_ENDED:
        case SCLP_VT220_SESSION_STARTED:
+               sclp_vt220_reset_session();
                break;
        case SCLP_VT220_SESSION_DATA:
                /* Send input to line discipline */
                buffer++;
                count--;
-               tty_insert_flip_string(&sclp_vt220_port, buffer, count);
+               sclp_vt220_handle_input(buffer, count);
                tty_flip_buffer_push(&sclp_vt220_port);
                break;
        }