]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[S390] add call home support
authorHans-Joachim Picht <hans@de.ibm.com>
Fri, 11 Sep 2009 08:28:47 +0000 (10:28 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 11 Sep 2009 08:29:49 +0000 (10:29 +0200)
Signed-off-by: Hans-Joachim Picht <hans@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Documentation/sysctl/kernel.txt
drivers/s390/char/Kconfig
drivers/s390/char/Makefile
drivers/s390/char/sclp.h
drivers/s390/char/sclp_async.c [new file with mode: 0644]

index 322a00bb99d97f703130de7f349f2dbc9b6fa24e..2dbff53369d0ea734b7a3c4c446d70d5297c8dc2 100644 (file)
@@ -19,6 +19,7 @@ Currently, these files might (depending on your configuration)
 show up in /proc/sys/kernel:
 - acpi_video_flags
 - acct
 show up in /proc/sys/kernel:
 - acpi_video_flags
 - acct
+- callhome                  [ S390 only ]
 - auto_msgmni
 - core_pattern
 - core_uses_pid
 - auto_msgmni
 - core_pattern
 - core_uses_pid
@@ -91,6 +92,21 @@ valid for 30 seconds.
 
 ==============================================================
 
 
 ==============================================================
 
+callhome:
+
+Controls the kernel's callhome behavior in case of a kernel panic.
+
+The s390 hardware allows an operating system to send a notification
+to a service organization (callhome) in case of an operating system panic.
+
+When the value in this file is 0 (which is the default behavior)
+nothing happens in case of a kernel panic. If this value is set to "1"
+the complete kernel oops message is send to the IBM customer service
+organization in case the mainframe the Linux operating system is running
+on has a service contract with IBM.
+
+==============================================================
+
 core_pattern:
 
 core_pattern is used to specify a core dumpfile pattern name.
 core_pattern:
 
 core_pattern is used to specify a core dumpfile pattern name.
index 0769ced52dbd64c3b5583f7c447971fd2e8eeb4d..4e34d3686c233d7b55aea1a7dcdc9b667818f5be 100644 (file)
@@ -82,6 +82,16 @@ config SCLP_CPI
          You should only select this option if you know what you are doing,
          need this feature and intend to run your kernel in LPAR.
 
          You should only select this option if you know what you are doing,
          need this feature and intend to run your kernel in LPAR.
 
+config SCLP_ASYNC
+       tristate "Support for Call Home via Asynchronous SCLP Records"
+       depends on S390
+       help
+         This option enables the call home function, which is able to inform
+         the service element and connected organisations about a kernel panic.
+         You should only select this option if you know what you are doing,
+         want for inform other people about your kernel panics,
+         need this feature and intend to run your kernel in LPAR.
+
 config S390_TAPE
        tristate "S/390 tape device support"
        depends on CCW
 config S390_TAPE
        tristate "S/390 tape device support"
        depends on CCW
index 7e73e39a174122462cc917f953e8b2406278e4f9..efb500ab66c07d84c79176328d6596d92aa8ca00 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
 obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
 obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
+obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o
 
 obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
 
 obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
index 60e7cb07095b6fa2c6e0b2908a6886c2cfc5c1c6..6bb5a6bdfab52a6d7e66dbcd872b0b2ed9d9ed37 100644 (file)
@@ -27,6 +27,7 @@
 #define EVTYP_VT220MSG         0x1A
 #define EVTYP_CONFMGMDATA      0x04
 #define EVTYP_SDIAS            0x1C
 #define EVTYP_VT220MSG         0x1A
 #define EVTYP_CONFMGMDATA      0x04
 #define EVTYP_SDIAS            0x1C
+#define EVTYP_ASYNC            0x0A
 
 #define EVTYP_OPCMD_MASK       0x80000000
 #define EVTYP_MSG_MASK         0x40000000
 
 #define EVTYP_OPCMD_MASK       0x80000000
 #define EVTYP_MSG_MASK         0x40000000
@@ -38,6 +39,7 @@
 #define EVTYP_VT220MSG_MASK    0x00000040
 #define EVTYP_CONFMGMDATA_MASK 0x10000000
 #define EVTYP_SDIAS_MASK       0x00000010
 #define EVTYP_VT220MSG_MASK    0x00000040
 #define EVTYP_CONFMGMDATA_MASK 0x10000000
 #define EVTYP_SDIAS_MASK       0x00000010
+#define EVTYP_ASYNC_MASK       0x00400000
 
 #define GNRLMSGFLGS_DOM                0x8000
 #define GNRLMSGFLGS_SNDALRM    0x4000
 
 #define GNRLMSGFLGS_DOM                0x8000
 #define GNRLMSGFLGS_SNDALRM    0x4000
@@ -85,12 +87,12 @@ struct sccb_header {
 } __attribute__((packed));
 
 extern u64 sclp_facilities;
 } __attribute__((packed));
 
 extern u64 sclp_facilities;
-
 #define SCLP_HAS_CHP_INFO      (sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG  (sclp_facilities & 0x2000000000000000ULL)
 #define SCLP_HAS_CPU_INFO      (sclp_facilities & 0x0800000000000000ULL)
 #define SCLP_HAS_CPU_RECONFIG  (sclp_facilities & 0x0400000000000000ULL)
 
 #define SCLP_HAS_CHP_INFO      (sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG  (sclp_facilities & 0x2000000000000000ULL)
 #define SCLP_HAS_CPU_INFO      (sclp_facilities & 0x0800000000000000ULL)
 #define SCLP_HAS_CPU_RECONFIG  (sclp_facilities & 0x0400000000000000ULL)
 
+
 struct gds_subvector {
        u8      length;
        u8      key;
 struct gds_subvector {
        u8      length;
        u8      key;
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c
new file mode 100644 (file)
index 0000000..daaec18
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Enable Asynchronous Notification via SCLP.
+ *
+ * Copyright IBM Corp. 2009
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/utsname.h>
+#include "sclp.h"
+
+static int callhome_enabled;
+static struct sclp_req *request;
+static struct sclp_async_sccb *sccb;
+static int sclp_async_send_wait(char *message);
+static struct ctl_table_header *callhome_sysctl_header;
+static DEFINE_SPINLOCK(sclp_async_lock);
+static char nodename[64];
+#define SCLP_NORMAL_WRITE      0x00
+
+struct async_evbuf {
+       struct evbuf_header header;
+       u64 reserved;
+       u8 rflags;
+       u8 empty;
+       u8 rtype;
+       u8 otype;
+       char comp_id[12];
+       char data[3000]; /* there is still some space left */
+} __attribute__((packed));
+
+struct sclp_async_sccb {
+       struct sccb_header header;
+       struct async_evbuf evbuf;
+} __attribute__((packed));
+
+static struct sclp_register sclp_async_register = {
+       .send_mask = EVTYP_ASYNC_MASK,
+};
+
+static int call_home_on_panic(struct notifier_block *self,
+                             unsigned long event, void *data)
+{
+               strncat(data, nodename, strlen(nodename));
+               sclp_async_send_wait(data);
+               return NOTIFY_DONE;
+}
+
+static struct notifier_block call_home_panic_nb = {
+       .notifier_call = call_home_on_panic,
+       .priority = INT_MAX,
+};
+
+static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp,
+                                void __user *buffer, size_t *count,
+                                loff_t *ppos)
+{
+       unsigned long val;
+       int len, rc;
+       char buf[2];
+
+       if (!*count | (*ppos && !write)) {
+               *count = 0;
+               return 0;
+       }
+       if (!write) {
+               len =  sprintf(buf, "%d\n", callhome_enabled);
+               buf[len] = '\0';
+               rc = copy_to_user(buffer, buf, sizeof(buf));
+               if (rc != 0)
+                       return -EFAULT;
+       } else {
+               len = *count;
+               rc = copy_from_user(buf, buffer, sizeof(buf));
+               if (rc != 0)
+                       return -EFAULT;
+               if (strict_strtoul(buf, 0, &val) != 0)
+                       return -EINVAL;
+               if (val != 0 && val != 1)
+                       return -EINVAL;
+               callhome_enabled = val;
+       }
+       *count = len;
+       *ppos += len;
+       return 0;
+}
+
+static struct ctl_table callhome_table[] = {
+       {
+               .procname       = "callhome",
+               .mode           = 0644,
+               .proc_handler   = &proc_handler_callhome,
+       },
+       { .ctl_name = 0 }
+};
+
+static struct ctl_table kern_dir_table[] = {
+       {
+               .ctl_name       = CTL_KERN,
+               .procname       = "kernel",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = callhome_table,
+       },
+       { .ctl_name = 0 }
+};
+
+/*
+ * Function used to transfer asynchronous notification
+ * records which waits for send completion
+ */
+static int sclp_async_send_wait(char *message)
+{
+       struct async_evbuf *evb;
+       int rc;
+       unsigned long flags;
+
+       if (!callhome_enabled)
+               return 0;
+       sccb->evbuf.header.type = EVTYP_ASYNC;
+       sccb->evbuf.rtype = 0xA5;
+       sccb->evbuf.otype = 0x00;
+       evb = &sccb->evbuf;
+       request->command = SCLP_CMDW_WRITE_EVENT_DATA;
+       request->sccb = sccb;
+       request->status = SCLP_REQ_FILLED;
+       strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data));
+       /*
+        * Retain Queue
+        * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS)
+        */
+       strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id));
+       sccb->evbuf.header.length = sizeof(sccb->evbuf);
+       sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header);
+       sccb->header.function_code = SCLP_NORMAL_WRITE;
+       rc = sclp_add_request(request);
+       if (rc)
+               return rc;
+       spin_lock_irqsave(&sclp_async_lock, flags);
+       while (request->status != SCLP_REQ_DONE &&
+               request->status != SCLP_REQ_FAILED) {
+                sclp_sync_wait();
+       }
+       spin_unlock_irqrestore(&sclp_async_lock, flags);
+       if (request->status != SCLP_REQ_DONE)
+               return -EIO;
+       rc = ((struct sclp_async_sccb *)
+              request->sccb)->header.response_code;
+       if (rc != 0x0020)
+               return -EIO;
+       if (evb->header.flags != 0x80)
+               return -EIO;
+       return rc;
+}
+
+static int __init sclp_async_init(void)
+{
+       int rc;
+
+       rc = sclp_register(&sclp_async_register);
+       if (rc)
+               return rc;
+       callhome_sysctl_header = register_sysctl_table(kern_dir_table);
+       if (!callhome_sysctl_header) {
+               rc = -ENOMEM;
+               goto out_sclp;
+       }
+       if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) {
+               rc = -EOPNOTSUPP;
+               goto out_sclp;
+       }
+       rc = -ENOMEM;
+       request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
+       if (!request)
+               goto out_sys;
+       sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               goto out_mem;
+       rc =  atomic_notifier_chain_register(&panic_notifier_list,
+                                            &call_home_panic_nb);
+       if (rc)
+               goto out_mem;
+
+       strncpy(nodename, init_utsname()->nodename, 64);
+       return 0;
+
+out_mem:
+       kfree(request);
+       free_page((unsigned long) sccb);
+out_sys:
+       unregister_sysctl_table(callhome_sysctl_header);
+out_sclp:
+       sclp_unregister(&sclp_async_register);
+       return rc;
+
+}
+module_init(sclp_async_init);
+
+static void __exit sclp_async_exit(void)
+{
+       atomic_notifier_chain_unregister(&panic_notifier_list,
+                                        &call_home_panic_nb);
+       unregister_sysctl_table(callhome_sysctl_header);
+       sclp_unregister(&sclp_async_register);
+       free_page((unsigned long) sccb);
+       kfree(request);
+}
+module_exit(sclp_async_exit);
+
+MODULE_AUTHOR("Copyright IBM Corp. 2009");
+MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SCLP Asynchronous Notification Records");