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>
This commit is contained in:
Родитель
9eb31be33c
Коммит
c6f70d3b8a
|
@ -112,6 +112,14 @@ config HMC_DRV
|
||||||
transfer cache size from it's default value 0.5MB to N bytes. If N
|
transfer cache size from it's default value 0.5MB to N bytes. If N
|
||||||
is zero, then no caching is performed.
|
is zero, then no caching is performed.
|
||||||
|
|
||||||
|
config SCLP_OFB
|
||||||
|
def_bool n
|
||||||
|
prompt "Support for Open-for-Business SCLP Event"
|
||||||
|
depends on S390
|
||||||
|
help
|
||||||
|
This option enables the Open-for-Business interface to the s390
|
||||||
|
Service Element.
|
||||||
|
|
||||||
config S390_TAPE
|
config S390_TAPE
|
||||||
def_tristate m
|
def_tristate m
|
||||||
prompt "S/390 tape device support"
|
prompt "S/390 tape device support"
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
#include <asm/smp.h>
|
#include <asm/smp.h>
|
||||||
|
|
||||||
#include "sclp.h"
|
#include "sclp.h"
|
||||||
|
@ -20,8 +22,22 @@ struct conf_mgm_data {
|
||||||
u8 ev_qualifier;
|
u8 ev_qualifier;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define OFB_DATA_MAX 64
|
||||||
|
|
||||||
|
struct sclp_ofb_evbuf {
|
||||||
|
struct evbuf_header header;
|
||||||
|
struct conf_mgm_data cm_data;
|
||||||
|
char ev_data[OFB_DATA_MAX];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct sclp_ofb_sccb {
|
||||||
|
struct sccb_header header;
|
||||||
|
struct sclp_ofb_evbuf ofb_evbuf;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define EV_QUAL_CPU_CHANGE 1
|
#define EV_QUAL_CPU_CHANGE 1
|
||||||
#define EV_QUAL_CAP_CHANGE 3
|
#define EV_QUAL_CAP_CHANGE 3
|
||||||
|
#define EV_QUAL_OPEN4BUSINESS 5
|
||||||
|
|
||||||
static struct work_struct sclp_cpu_capability_work;
|
static struct work_struct sclp_cpu_capability_work;
|
||||||
static struct work_struct sclp_cpu_change_work;
|
static struct work_struct sclp_cpu_change_work;
|
||||||
|
@ -63,15 +79,99 @@ static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
|
||||||
|
|
||||||
static struct sclp_register sclp_conf_register =
|
static struct sclp_register sclp_conf_register =
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SCLP_OFB
|
||||||
|
.send_mask = EVTYP_CONFMGMDATA_MASK,
|
||||||
|
#endif
|
||||||
.receive_mask = EVTYP_CONFMGMDATA_MASK,
|
.receive_mask = EVTYP_CONFMGMDATA_MASK,
|
||||||
.receiver_fn = sclp_conf_receiver_fn,
|
.receiver_fn = sclp_conf_receiver_fn,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCLP_OFB
|
||||||
|
static int sclp_ofb_send_req(char *ev_data, size_t len)
|
||||||
|
{
|
||||||
|
static DEFINE_MUTEX(send_mutex);
|
||||||
|
struct sclp_ofb_sccb *sccb;
|
||||||
|
int rc, response;
|
||||||
|
|
||||||
|
if (len > OFB_DATA_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
sccb = (struct sclp_ofb_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
|
||||||
|
if (!sccb)
|
||||||
|
return -ENOMEM;
|
||||||
|
/* Setup SCCB for Control-Program Identification */
|
||||||
|
sccb->header.length = sizeof(struct sclp_ofb_sccb);
|
||||||
|
sccb->ofb_evbuf.header.length = sizeof(struct sclp_ofb_evbuf);
|
||||||
|
sccb->ofb_evbuf.header.type = EVTYP_CONFMGMDATA;
|
||||||
|
sccb->ofb_evbuf.cm_data.ev_qualifier = EV_QUAL_OPEN4BUSINESS;
|
||||||
|
memcpy(sccb->ofb_evbuf.ev_data, ev_data, len);
|
||||||
|
|
||||||
|
if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK))
|
||||||
|
pr_warn("SCLP receiver did not register to receive "
|
||||||
|
"Configuration Management Data Events.\n");
|
||||||
|
|
||||||
|
mutex_lock(&send_mutex);
|
||||||
|
rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
|
||||||
|
mutex_unlock(&send_mutex);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
response = sccb->header.response_code;
|
||||||
|
if (response != 0x0020) {
|
||||||
|
pr_err("Open for Business request failed with response code "
|
||||||
|
"0x%04x\n", response);
|
||||||
|
rc = -EIO;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
free_page((unsigned long)sccb);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr,
|
||||||
|
char *buf, loff_t off, size_t count)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sclp_ofb_send_req(buf, count);
|
||||||
|
return rc ?: count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bin_attribute ofb_bin_attr = {
|
||||||
|
.attr = {
|
||||||
|
.name = "event_data",
|
||||||
|
.mode = S_IWUSR,
|
||||||
|
},
|
||||||
|
.write = sysfs_ofb_data_write,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __init sclp_ofb_setup(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SCLP_OFB
|
||||||
|
struct kset *ofb_kset;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ofb_kset = kset_create_and_add("ofb", NULL, firmware_kobj);
|
||||||
|
if (!ofb_kset)
|
||||||
|
return -ENOMEM;
|
||||||
|
rc = sysfs_create_bin_file(&ofb_kset->kobj, &ofb_bin_attr);
|
||||||
|
if (rc) {
|
||||||
|
kset_unregister(ofb_kset);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init sclp_conf_init(void)
|
static int __init sclp_conf_init(void)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
|
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
|
||||||
INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
|
INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
|
||||||
return sclp_register(&sclp_conf_register);
|
rc = sclp_register(&sclp_conf_register);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
return sclp_ofb_setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
__initcall(sclp_conf_init);
|
__initcall(sclp_conf_init);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче