Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3056

kernel-2.6.18-194.11.1.el5.src.rpm

From: Hans-Joachim Picht <hpicht@redhat.com>
Date: Thu, 12 Mar 2009 15:23:31 +0100
Subject: [s390] add Call Home data
Message-id: 20090312142331.GG5103@redhat.com
O-Subject: [RHEL5 U4 PATCH 6/20] s390 - FEAT: Linux to add Call Home data
Bugzilla: 475820

Description
============

This request is for Red Hat to integrate a kernel patch that implements
the sclp_cpi_sysfs interface for s390x.

The sclp_cpi sysfs interface allows the association of a set of
descriptive data called 'Control Program Identification' (CPI) with
an operating system instance (currently LPAR only).

This information is not persistent and has to be set once per IPL. CPI data
will be visible at the HMC/SE.

CPI information is also referred to as 'Call Home data' in some
contexts. CPI information could previously be set by loading the
sclp_cpi kernel module.

This item implements a new CPI interface in sysfs which complements the
existing one. The new interface was included in Linux kernel 2.6.25.

These sysfs-attributes can be used to specify the CPI information
locally:
* /sys/firmware/cpi/system_name
* /sys/firmware/cpi/sysplex_name
* /sys/firmware/cpi/system_type
* /sys/firmware/cpi/system_level
* /sys/firmware/cpi/system_set

Bugzilla
=========

BZ 475820
https://bugzilla.redhat.com/show_bug.cgi?id=475820

Upstream status of the patch:
=============================

The patch is upstream.
c05ffc4f2b208da8ba7d3a9b5ab886c76f8939b5

Test status:
============

The patch has been verified by the IBM test department.

Please ACK.

With best regards,

	--Hans

diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index e3f5f9a..400aff3 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-	 sclp_chp.o sclp_config.o
+	 sclp_chp.o sclp_config.o sclp_cpi_sys.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 732dfbd..2a3b0d4 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -1,253 +1,41 @@
 /*
- * Author: Martin Peschke <mpeschke@de.ibm.com>
- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ *  drivers/s390/char/sclp_cpi.c
+ *    SCLP control programm identification
  *
- * SCLP Control-Program Identification.
+ *    Copyright IBM Corp. 2001, 2009
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
  */
 
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <asm/ebcdic.h>
-#include <asm/semaphore.h>
-
-#include "sclp.h"
-#include "sclp_rw.h"
-
-#define CPI_LENGTH_SYSTEM_TYPE	8
-#define CPI_LENGTH_SYSTEM_NAME	8
-#define CPI_LENGTH_SYSPLEX_NAME	8
-
-struct cpi_evbuf {
-	struct evbuf_header header;
-	u8	id_format;
-	u8	reserved0;
-	u8	system_type[CPI_LENGTH_SYSTEM_TYPE];
-	u64	reserved1;
-	u8	system_name[CPI_LENGTH_SYSTEM_NAME];
-	u64	reserved2;
-	u64	system_level;
-	u64	reserved3;
-	u8	sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
-	u8	reserved4[16];
-} __attribute__((packed));
-
-struct cpi_sccb {
-	struct sccb_header header;
-	struct cpi_evbuf cpi_evbuf;
-} __attribute__((packed));
-
-/* Event type structure for write message and write priority message */
-static struct sclp_register sclp_cpi_event =
-{
-	.send_mask = EvTyp_CtlProgIdent_Mask
-};
+#include <linux/version.h>
+#include "sclp_cpi_sys.h"
 
-MODULE_AUTHOR(
-	"Martin Peschke, IBM Deutschland Entwicklung GmbH "
-	"<mpeschke@de.ibm.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Identify this operating system instance "
+		   "to the System z hardware");
+MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
+	      "Michael Ernst <mernst@de.ibm.com>");
 
-MODULE_DESCRIPTION(
-	"identify this operating system instance to the S/390 "
-	"or zSeries hardware");
+static char *system_name = "";
+static char *sysplex_name = "";
 
-static char *system_name = NULL;
 module_param(system_name, charp, 0);
 MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-
-static char *sysplex_name = NULL;
-#ifdef ALLOW_SYSPLEX_NAME
 module_param(sysplex_name, charp, 0);
 MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-#endif
-
-/* use default value for this field (as well as for system level) */
-static char *system_type = "LINUX";
-
-static int
-cpi_check_parms(void)
-{
-	/* reject if no system type specified */
-	if (!system_type) {
-		printk("cpi: bug: no system type specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system type larger than 8 characters */
-	if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: bug: system type has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
-		return -EINVAL;
-	}
-
-	/* reject if no system name specified */
-	if (!system_name) {
-		printk("cpi: no system name specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system name larger than 8 characters */
-	if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: system name has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
-		return -EINVAL;
-	}
-
-	/* reject if specified sysplex name larger than 8 characters */
-	if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
-		printk("cpi: sysplex name has length of %li characters"
-		       " - only %i characters supported\n",
-		       strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void
-cpi_callback(struct sclp_req *req, void *data)
-{
-	struct semaphore *sem;
-
-	sem = (struct semaphore *) data;
-	up(sem);
-}
-
-static struct sclp_req *
-cpi_prepare_req(void)
-{
-	struct sclp_req *req;
-	struct cpi_sccb *sccb;
-	struct cpi_evbuf *evb;
-
-	req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
-	if (req == NULL)
-		return ERR_PTR(-ENOMEM);
-	sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
-	if (sccb == NULL) {
-		kfree(req);
-		return ERR_PTR(-ENOMEM);
-	}
-	memset(sccb, 0, sizeof(struct cpi_sccb));
-
-	/* setup SCCB for Control-Program Identification */
-	sccb->header.length = sizeof(struct cpi_sccb);
-	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
-	sccb->cpi_evbuf.header.type = 0x0B;
-	evb = &sccb->cpi_evbuf;
-
-	/* set system type */
-	memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
-	memcpy(evb->system_type, system_type, strlen(system_type));
-	sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-	EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-
-	/* set system name */
-	memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
-	memcpy(evb->system_name, system_name, strlen(system_name));
-	sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-	EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-
-	/* set sytem level */
-	evb->system_level = LINUX_VERSION_CODE;
-
-	/* set sysplex name */
-	if (sysplex_name) {
-		memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
-		memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
-		sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-		EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-	}
-
-	/* prepare request data structure presented to SCLP driver */
-	req->command = SCLP_CMDW_WRITEDATA;
-	req->sccb = sccb;
-	req->status = SCLP_REQ_FILLED;
-	req->callback = cpi_callback;
-	return req;
-}
-
-static void
-cpi_free_req(struct sclp_req *req)
-{
-	free_page((unsigned long) req->sccb);
-	kfree(req);
-}
 
-static int __init
-cpi_module_init(void)
+static int __init cpi_module_init(void)
 {
-	struct semaphore sem;
-	struct sclp_req *req;
-	int rc;
-
-	rc = cpi_check_parms();
-	if (rc)
-		return rc;
-
-	rc = sclp_register(&sclp_cpi_event);
-	if (rc) {
-		/* could not register sclp event. Die. */
-		printk(KERN_WARNING "cpi: could not register to hardware "
-		       "console.\n");
-		return -EINVAL;
-	}
-	if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) {
-		printk(KERN_WARNING "cpi: no control program identification "
-		       "support\n");
-		sclp_unregister(&sclp_cpi_event);
-		return -EOPNOTSUPP;
-	}
-
-	req = cpi_prepare_req();
-	if (IS_ERR(req)) {
-		printk(KERN_WARNING "cpi: couldn't allocate request\n");
-		sclp_unregister(&sclp_cpi_event);
-		return PTR_ERR(req);
-	}
-
-	/* Prepare semaphore */
-	sema_init(&sem, 0);
-	req->callback_data = &sem;
-	/* Add request to sclp queue */
-	rc = sclp_add_request(req);
-	if (rc) {
-		printk(KERN_WARNING "cpi: could not start request\n");
-		cpi_free_req(req);
-		sclp_unregister(&sclp_cpi_event);
-		return rc;
-	}
-	/* make "insmod" sleep until callback arrives */
-	down(&sem);
-
-	rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
-	if (rc != 0x0020) {
-		printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
-		       rc);
-		rc = -ECOMM;
-	} else
-		rc = 0;
-
-	cpi_free_req(req);
-	sclp_unregister(&sclp_cpi_event);
-
-	return rc;
+	return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
+				 LINUX_VERSION_CODE);
 }
 
-
 static void __exit cpi_module_exit(void)
 {
 }
 
-
-/* declare driver module init/cleanup functions */
 module_init(cpi_module_init);
 module_exit(cpi_module_exit);
-
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
new file mode 100644
index 0000000..f0726aa
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -0,0 +1,413 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.c
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2001, 2009
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <asm/ebcdic.h>
+
+#include "sclp.h"
+#include "sclp_cpi_sys.h"
+
+#define KMSG_COMPONENT "sclp_cpi"
+
+#define CPI_LENGTH_NAME 8
+#define CPI_LENGTH_LEVEL 16
+
+static DEFINE_MUTEX(sclp_cpi_mutex);
+
+struct cpi_evbuf {
+	struct evbuf_header header;
+	u8	id_format;
+	u8	reserved0;
+	u8	system_type[CPI_LENGTH_NAME];
+	u64	reserved1;
+	u8	system_name[CPI_LENGTH_NAME];
+	u64	reserved2;
+	u64	system_level;
+	u64	reserved3;
+	u8	sysplex_name[CPI_LENGTH_NAME];
+	u8	reserved4[16];
+} __attribute__((packed));
+
+struct cpi_sccb {
+	struct sccb_header header;
+	struct cpi_evbuf cpi_evbuf;
+} __attribute__((packed));
+
+static struct sclp_register sclp_cpi_event = {
+	.send_mask = EvTyp_CtlProgIdent_Mask,
+};
+
+static char system_name[CPI_LENGTH_NAME + 1];
+static char sysplex_name[CPI_LENGTH_NAME + 1];
+static char system_type[CPI_LENGTH_NAME + 1];
+static u64 system_level;
+
+static void set_data(char *field, char *data)
+{
+	memset(field, ' ', CPI_LENGTH_NAME);
+	memcpy(field, data, strlen(data));
+	sclp_ascebc_str(field, CPI_LENGTH_NAME);
+}
+
+static void cpi_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+static struct sclp_req *cpi_prepare_req(void)
+{
+	struct sclp_req *req;
+	struct cpi_sccb *sccb;
+	struct cpi_evbuf *evb;
+
+	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb) {
+		kfree(req);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* setup SCCB for Control-Program Identification */
+	sccb->header.length = sizeof(struct cpi_sccb);
+	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
+	sccb->cpi_evbuf.header.type = 0x0b;
+	evb = &sccb->cpi_evbuf;
+
+	/* set system type */
+	set_data(evb->system_type, system_type);
+
+	/* set system name */
+	set_data(evb->system_name, system_name);
+
+	/* set sytem level */
+	evb->system_level = system_level;
+
+	/* set sysplex name */
+	set_data(evb->sysplex_name, sysplex_name);
+
+	/* prepare request data structure presented to SCLP driver */
+	req->command = SCLP_CMDW_WRITEDATA;
+	req->sccb = sccb;
+	req->status = SCLP_REQ_FILLED;
+	req->callback = cpi_callback;
+	return req;
+}
+
+static void cpi_free_req(struct sclp_req *req)
+{
+	free_page((unsigned long) req->sccb);
+	kfree(req);
+}
+
+static int cpi_req(void)
+{
+	struct completion completion;
+	struct sclp_req *req;
+	int rc;
+	int response;
+
+	rc = sclp_register(&sclp_cpi_event);
+	if (rc)
+		goto out;
+	if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) {
+		rc = -EOPNOTSUPP;
+		goto out_unregister;
+	}
+
+	req = cpi_prepare_req();
+	if (IS_ERR(req)) {
+		rc = PTR_ERR(req);
+		goto out_unregister;
+	}
+
+	init_completion(&completion);
+	req->callback_data = &completion;
+
+	/* Add request to sclp queue */
+	rc = sclp_add_request(req);
+	if (rc)
+		goto out_free_req;
+
+	wait_for_completion(&completion);
+
+	if (req->status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING "request failed (status=0x%02x)\n",
+		       req->status);
+		rc = -EIO;
+		goto out_free_req;
+	}
+
+	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
+	if (response != 0x0020) {
+		printk(KERN_WARNING "request failed with response code 0x%x\n",
+		       response);
+		rc = -EIO;
+	}
+
+out_free_req:
+	cpi_free_req(req);
+
+out_unregister:
+	sclp_unregister(&sclp_cpi_event);
+
+out:
+	return rc;
+}
+
+static int check_string(const char *attr, const char *str)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(str);
+
+	if ((len > 0) && (str[len - 1] == '\n'))
+		len--;
+
+	if (len > CPI_LENGTH_NAME)
+		return -EINVAL;
+
+	for (i = 0; i < len ; i++) {
+		if (isalpha(str[i]) || isdigit(str[i]) ||
+		    strchr("$@# ", str[i]))
+			continue;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void set_string(char *attr, const char *value)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(value);
+
+	if ((len > 0) && (value[len - 1] == '\n'))
+		len--;
+
+	for (i = 0; i < CPI_LENGTH_NAME; i++) {
+		if (i < len)
+			attr[i] = toupper(value[i]);
+		else
+			attr[i] = ' ';
+	}
+}
+
+static ssize_t system_name_show(struct subsystem *subsys, char *page)
+{
+	int rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	rc = snprintf(page, PAGE_SIZE, "%s\n", system_name);
+	mutex_unlock(&sclp_cpi_mutex);
+	return rc;
+}
+
+static ssize_t system_name_store(struct subsystem *subsyst, const char *buf,
+				 size_t len)
+{
+	int rc;
+
+	rc = check_string("system_name", buf);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	set_string(system_name, buf);
+	mutex_unlock(&sclp_cpi_mutex);
+
+	return len;
+}
+
+static struct subsys_attribute system_name_attr =
+	__ATTR(system_name, 0644, system_name_show, system_name_store);
+
+static ssize_t sysplex_name_show(struct subsystem *subsystem, char *page)
+{
+	int rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+	mutex_unlock(&sclp_cpi_mutex);
+	return rc;
+}
+
+static ssize_t sysplex_name_store(struct subsystem *subsystem, const char *buf,
+				  size_t len)
+{
+	int rc;
+
+	rc = check_string("sysplex_name", buf);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	set_string(sysplex_name, buf);
+	mutex_unlock(&sclp_cpi_mutex);
+
+	return len;
+}
+
+static struct subsys_attribute sysplex_name_attr =
+	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
+
+static ssize_t system_type_show(struct subsystem *subsys, char *page)
+{
+	int rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	rc = snprintf(page, PAGE_SIZE, "%s\n", system_type);
+	mutex_unlock(&sclp_cpi_mutex);
+	return rc;
+}
+
+static ssize_t system_type_store(struct subsystem *subsys, const char *buf,
+				 size_t len)
+{
+	int rc;
+
+	rc = check_string("system_type", buf);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	set_string(system_type, buf);
+	mutex_unlock(&sclp_cpi_mutex);
+
+	return len;
+}
+
+static struct subsys_attribute system_type_attr =
+	__ATTR(system_type, 0644, system_type_show, system_type_store);
+
+static ssize_t system_level_show(struct subsystem *subsys, char *page)
+{
+	unsigned long long level;
+
+	mutex_lock(&sclp_cpi_mutex);
+	level = system_level;
+	mutex_unlock(&sclp_cpi_mutex);
+	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
+}
+
+static ssize_t system_level_store(struct subsystem *subsys, const char *buf,
+				  size_t len)
+{
+	unsigned long long level;
+	char *endp;
+
+	level = simple_strtoull(buf, &endp, 16);
+
+	if (endp == buf)
+		return -EINVAL;
+	if (*endp == '\n')
+		endp++;
+	if (*endp)
+		return -EINVAL;
+
+	mutex_lock(&sclp_cpi_mutex);
+	system_level = level;
+	mutex_unlock(&sclp_cpi_mutex);
+	return len;
+}
+
+static struct subsys_attribute system_level_attr =
+	__ATTR(system_level, 0644, system_level_show, system_level_store);
+
+static ssize_t set_store(struct subsystem *subsys, const char *buf, size_t len)
+{
+	int rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	rc = cpi_req();
+	mutex_unlock(&sclp_cpi_mutex);
+	if (rc)
+		return rc;
+
+	return len;
+}
+
+static struct subsys_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
+
+static struct attribute *cpi_attrs[] = {
+	&system_name_attr.attr,
+	&sysplex_name_attr.attr,
+	&system_type_attr.attr,
+	&system_level_attr.attr,
+	&set_attr.attr,
+	NULL,
+};
+
+static struct attribute_group cpi_attr_group = {
+	.attrs = cpi_attrs,
+};
+
+int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
+		      const u64 level)
+{
+	int rc;
+
+	rc = check_string("system_name", system);
+	if (rc)
+		return rc;
+	rc = check_string("sysplex_name", sysplex);
+	if (rc)
+		return rc;
+	rc = check_string("system_type", type);
+	if (rc)
+		return rc;
+
+	mutex_lock(&sclp_cpi_mutex);
+	set_string(system_name, system);
+	set_string(sysplex_name, sysplex);
+	set_string(system_type, type);
+	system_level = level;
+
+	rc = cpi_req();
+	mutex_unlock(&sclp_cpi_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(sclp_cpi_set_data);
+
+static decl_subsys(cpi, NULL, NULL);
+
+static int __init cpi_init(void)
+{
+	int rc;
+
+	rc = firmware_register(&cpi_subsys);
+	if (rc)
+		return rc;
+
+	rc = sysfs_create_group(&cpi_subsys.kset.kobj, &cpi_attr_group);
+	if (rc)
+		firmware_unregister(&cpi_subsys);
+
+	return rc;
+}
+
+__initcall(cpi_init);
diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
new file mode 100644
index 0000000..e6598a1
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.h
@@ -0,0 +1,15 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.h
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2009
+ *    Author(s): Michael Ernst <mernst@de.ibm.com>
+ */
+
+#ifndef __SCLP_CPI_SYS_H__
+#define __SCLP_CPI_SYS_H__
+
+int sclp_cpi_set_data(const char *system, const char *sysplex,
+		      const char *type, u64 level);
+
+#endif	 /* __SCLP_CPI_SYS_H__ */