2
* drivers/s390/char/sclp_ocf.c
3
* SCLP OCF communication parameters sysfs interface
5
* Copyright IBM Corp. 2011
6
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
9
#define KMSG_COMPONENT "sclp_ocf"
10
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
#include <linux/kernel.h>
13
#include <linux/init.h>
14
#include <linux/stat.h>
15
#include <linux/device.h>
16
#include <linux/string.h>
17
#include <linux/ctype.h>
18
#include <linux/kmod.h>
19
#include <linux/timer.h>
20
#include <linux/err.h>
21
#include <asm/ebcdic.h>
26
#define OCF_LENGTH_HMC_NETWORK 8UL
27
#define OCF_LENGTH_CPC_NAME 8UL
29
static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
30
static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
32
static DEFINE_SPINLOCK(sclp_ocf_lock);
33
static struct work_struct sclp_ocf_change_work;
35
static struct kset *ocf_kset;
37
static void sclp_ocf_change_notify(struct work_struct *work)
39
kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
42
/* Handler for OCF event. Look for the CPC image name. */
43
static void sclp_ocf_handler(struct evbuf_header *evbuf)
46
struct gds_subvector *sv, *netid, *cpc;
49
/* Find the 0x9f00 block. */
50
v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
54
/* Find the 0x9f22 block inside the 0x9f00 block. */
55
v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
58
/* Find the 0x81 block inside the 0x9f22 block. */
59
sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
62
/* Find the 0x01 block inside the 0x81 block. */
63
netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1);
64
/* Find the 0x02 block inside the 0x81 block. */
65
cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2);
66
/* Copy network name and cpc name. */
67
spin_lock(&sclp_ocf_lock);
69
size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
70
memcpy(hmc_network, netid + 1, size);
71
EBCASC(hmc_network, size);
72
hmc_network[size] = 0;
75
size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
76
memcpy(cpc_name, cpc + 1, size);
77
EBCASC(cpc_name, size);
80
spin_unlock(&sclp_ocf_lock);
81
schedule_work(&sclp_ocf_change_work);
84
static struct sclp_register sclp_ocf_event = {
85
.receive_mask = EVTYP_OCF_MASK,
86
.receiver_fn = sclp_ocf_handler,
89
static ssize_t cpc_name_show(struct kobject *kobj,
90
struct kobj_attribute *attr, char *page)
94
spin_lock_irq(&sclp_ocf_lock);
95
rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
96
spin_unlock_irq(&sclp_ocf_lock);
100
static struct kobj_attribute cpc_name_attr =
101
__ATTR(cpc_name, 0444, cpc_name_show, NULL);
103
static ssize_t hmc_network_show(struct kobject *kobj,
104
struct kobj_attribute *attr, char *page)
108
spin_lock_irq(&sclp_ocf_lock);
109
rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
110
spin_unlock_irq(&sclp_ocf_lock);
114
static struct kobj_attribute hmc_network_attr =
115
__ATTR(hmc_network, 0444, hmc_network_show, NULL);
117
static struct attribute *ocf_attrs[] = {
119
&hmc_network_attr.attr,
123
static struct attribute_group ocf_attr_group = {
127
static int __init ocf_init(void)
131
INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
132
ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
136
rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
138
kset_unregister(ocf_kset);
142
return sclp_register(&sclp_ocf_event);
145
device_initcall(ocf_init);