aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJochen Schweflinghaus <schwefel@de.ibm.com>2015-11-26 13:13:01 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-11-27 03:24:18 -0500
commitc6f70d3b8a32fdec60d3f78cb59423f056f16688 (patch)
tree9f0299bab2d8c2f9a1b19cf6758c2e47eaeae9e2
parent9eb31be33cf84266abd61de0f6d3d1fe609587cf (diff)
s390/sclp: add open for business support
Provide a user space interface and an enhancement to the sclp device driver which allows to send an 'Open for Business' event from the operating system to the Support Element. The 'Open for Business' event is used to signal the Support Element that the operating system (or an application running on top of it) is up and running. Signed-off-by: Jochen Schweflinghaus <schwefel@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/char/Kconfig8
-rw-r--r--drivers/s390/char/sclp_config.c102
2 files changed, 109 insertions, 1 deletions
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 1f9078fdaf8c..b3f1c458905f 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -112,6 +112,14 @@ config HMC_DRV
112 transfer cache size from it's default value 0.5MB to N bytes. If N 112 transfer cache size from it's default value 0.5MB to N bytes. If N
113 is zero, then no caching is performed. 113 is zero, then no caching is performed.
114 114
115config SCLP_OFB
116 def_bool n
117 prompt "Support for Open-for-Business SCLP Event"
118 depends on S390
119 help
120 This option enables the Open-for-Business interface to the s390
121 Service Element.
122
115config S390_TAPE 123config S390_TAPE
116 def_tristate m 124 def_tristate m
117 prompt "S/390 tape device support" 125 prompt "S/390 tape device support"
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 944156207477..2ced50ccca63 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -11,6 +11,8 @@
11#include <linux/cpu.h> 11#include <linux/cpu.h>
12#include <linux/device.h> 12#include <linux/device.h>
13#include <linux/workqueue.h> 13#include <linux/workqueue.h>
14#include <linux/slab.h>
15#include <linux/sysfs.h>
14#include <asm/smp.h> 16#include <asm/smp.h>
15 17
16#include "sclp.h" 18#include "sclp.h"
@@ -20,8 +22,22 @@ struct conf_mgm_data {
20 u8 ev_qualifier; 22 u8 ev_qualifier;
21} __attribute__((packed)); 23} __attribute__((packed));
22 24
25#define OFB_DATA_MAX 64
26
27struct sclp_ofb_evbuf {
28 struct evbuf_header header;
29 struct conf_mgm_data cm_data;
30 char ev_data[OFB_DATA_MAX];
31} __packed;
32
33struct sclp_ofb_sccb {
34 struct sccb_header header;
35 struct sclp_ofb_evbuf ofb_evbuf;
36} __packed;
37
23#define EV_QUAL_CPU_CHANGE 1 38#define EV_QUAL_CPU_CHANGE 1
24#define EV_QUAL_CAP_CHANGE 3 39#define EV_QUAL_CAP_CHANGE 3
40#define EV_QUAL_OPEN4BUSINESS 5
25 41
26static struct work_struct sclp_cpu_capability_work; 42static struct work_struct sclp_cpu_capability_work;
27static struct work_struct sclp_cpu_change_work; 43static struct work_struct sclp_cpu_change_work;
@@ -63,15 +79,99 @@ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
63 79
64static struct sclp_register sclp_conf_register = 80static struct sclp_register sclp_conf_register =
65{ 81{
82#ifdef CONFIG_SCLP_OFB
83 .send_mask = EVTYP_CONFMGMDATA_MASK,
84#endif
66 .receive_mask = EVTYP_CONFMGMDATA_MASK, 85 .receive_mask = EVTYP_CONFMGMDATA_MASK,
67 .receiver_fn = sclp_conf_receiver_fn, 86 .receiver_fn = sclp_conf_receiver_fn,
68}; 87};
69 88
89#ifdef CONFIG_SCLP_OFB
90static int sclp_ofb_send_req(char *ev_data, size_t len)
91{
92 static DEFINE_MUTEX(send_mutex);
93 struct sclp_ofb_sccb *sccb;
94 int rc, response;
95
96 if (len > OFB_DATA_MAX)
97 return -EINVAL;
98 sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
99 if (!sccb)
100 return -ENOMEM;
101 /* Setup SCCB for Control-Program Identification */
102 sccb->header.length = sizeof(struct sclp_ofb_sccb);
103 sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
104 sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
105 sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
106 memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
107
108 if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
109 pr_warn("SCLP receiver did not register to receive "
110 "Configuration Management Data Events.\n");
111
112 mutex_lock(&send_mutex);
113 rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
114 mutex_unlock(&send_mutex);
115 if (rc)
116 goto out;
117 response = sccb->header.response_code;
118 if (response != 0x0020) {
119 pr_err("Open for Business request failed with response code "
120 "0x%04x\n", response);
121 rc = -EIO;
122 }
123out:
124 free_page((unsigned long)sccb);
125 return rc;
126}
127
128static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
129 struct bin_attribute *bin_attr,
130 char *buf, loff_t off, size_t count)
131{
132 int rc;
133
134 rc = sclp_ofb_send_req(buf, count);
135 return rc ?: count;
136}
137
138static struct bin_attribute ofb_bin_attr = {
139 .attr = {
140 .name = "event_data",
141 .mode = S_IWUSR,
142 },
143 .write = sysfs_ofb_data_write,
144};
145#endif
146
147static int __init sclp_ofb_setup(void)
148{
149#ifdef CONFIG_SCLP_OFB
150 struct kset *ofb_kset;
151 int rc;
152
153 ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
154 if (!ofb_kset)
155 return -ENOMEM;
156 rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
157 if (rc) {
158 kset_unregister(ofb_kset);
159 return rc;
160 }
161#endif
162 return 0;
163}
164
70static int __init sclp_conf_init(void) 165static int __init sclp_conf_init(void)
71{ 166{
167 int rc;
168
72 INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); 169 INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
73 INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); 170 INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
74 return sclp_register(&sclp_conf_register); 171 rc = sclp_register(&sclp_conf_register);
172 if (rc)
173 return rc;
174 return sclp_ofb_setup();
75} 175}
76 176
77__initcall(sclp_conf_init); 177__initcall(sclp_conf_init);