aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-05-23 04:24:43 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-05-23 04:24:32 -0400
commit7eb9d5bec552eff896ebf079386dc47e9dc2fc89 (patch)
tree2ccffd0b2426759008ba1221fd081295e7830e6b
parent30c2df51173ea4e4755ad52be7f2914f01e32404 (diff)
[S390] get CPC image name
Provide sysfs attributes that contain the CPC name and the HMC network name of the machine the operating system is running on. This information is retrieved with the operation communication parameters (OCF) sclp interface. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/char/Makefile2
-rw-r--r--drivers/s390/char/sclp.h2
-rw-r--r--drivers/s390/char/sclp_ocf.c145
3 files changed, 148 insertions, 1 deletions
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index af01b5abd069..f3c325207445 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ 5obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
6 sclp_cmd.o sclp_config.o sclp_cpi_sys.o 6 sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o
7 7
8obj-$(CONFIG_TN3270) += raw3270.o 8obj-$(CONFIG_TN3270) += raw3270.o
9obj-$(CONFIG_TN3270_CONSOLE) += con3270.o 9obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index bc23b05bfe7d..49a1bb52bc87 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -28,6 +28,7 @@
28#define EVTYP_CONFMGMDATA 0x04 28#define EVTYP_CONFMGMDATA 0x04
29#define EVTYP_SDIAS 0x1C 29#define EVTYP_SDIAS 0x1C
30#define EVTYP_ASYNC 0x0A 30#define EVTYP_ASYNC 0x0A
31#define EVTYP_OCF 0x1E
31 32
32#define EVTYP_OPCMD_MASK 0x80000000 33#define EVTYP_OPCMD_MASK 0x80000000
33#define EVTYP_MSG_MASK 0x40000000 34#define EVTYP_MSG_MASK 0x40000000
@@ -40,6 +41,7 @@
40#define EVTYP_CONFMGMDATA_MASK 0x10000000 41#define EVTYP_CONFMGMDATA_MASK 0x10000000
41#define EVTYP_SDIAS_MASK 0x00000010 42#define EVTYP_SDIAS_MASK 0x00000010
42#define EVTYP_ASYNC_MASK 0x00400000 43#define EVTYP_ASYNC_MASK 0x00400000
44#define EVTYP_OCF_MASK 0x00000004
43 45
44#define GNRLMSGFLGS_DOM 0x8000 46#define GNRLMSGFLGS_DOM 0x8000
45#define GNRLMSGFLGS_SNDALRM 0x4000 47#define GNRLMSGFLGS_SNDALRM 0x4000
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c
new file mode 100644
index 000000000000..ab294d5a534e
--- /dev/null
+++ b/drivers/s390/char/sclp_ocf.c
@@ -0,0 +1,145 @@
1/*
2 * drivers/s390/char/sclp_ocf.c
3 * SCLP OCF communication parameters sysfs interface
4 *
5 * Copyright IBM Corp. 2011
6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7 */
8
9#define KMSG_COMPONENT "sclp_ocf"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
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>
22#include <asm/sclp.h>
23
24#include "sclp.h"
25
26#define OCF_LENGTH_HMC_NETWORK 8UL
27#define OCF_LENGTH_CPC_NAME 8UL
28
29static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
30static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
31
32static DEFINE_SPINLOCK(sclp_ocf_lock);
33static struct work_struct sclp_ocf_change_work;
34
35static struct kset *ocf_kset;
36
37static void sclp_ocf_change_notify(struct work_struct *work)
38{
39 kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
40}
41
42/* Handler for OCF event. Look for the CPC image name. */
43static void sclp_ocf_handler(struct evbuf_header *evbuf)
44{
45 struct gds_vector *v;
46 struct gds_subvector *sv, *netid, *cpc;
47 size_t size;
48
49 /* Find the 0x9f00 block. */
50 v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
51 0x9f00);
52 if (!v)
53 return;
54 /* Find the 0x9f22 block inside the 0x9f00 block. */
55 v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
56 if (!v)
57 return;
58 /* Find the 0x81 block inside the 0x9f22 block. */
59 sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
60 if (!sv)
61 return;
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);
68 if (netid) {
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;
73 }
74 if (cpc) {
75 size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
76 memcpy(cpc_name, cpc + 1, size);
77 EBCASC(cpc_name, size);
78 cpc_name[size] = 0;
79 }
80 spin_unlock(&sclp_ocf_lock);
81 schedule_work(&sclp_ocf_change_work);
82}
83
84static struct sclp_register sclp_ocf_event = {
85 .receive_mask = EVTYP_OCF_MASK,
86 .receiver_fn = sclp_ocf_handler,
87};
88
89static ssize_t cpc_name_show(struct kobject *kobj,
90 struct kobj_attribute *attr, char *page)
91{
92 int rc;
93
94 spin_lock_irq(&sclp_ocf_lock);
95 rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
96 spin_unlock_irq(&sclp_ocf_lock);
97 return rc;
98}
99
100static struct kobj_attribute cpc_name_attr =
101 __ATTR(cpc_name, 0444, cpc_name_show, NULL);
102
103static ssize_t hmc_network_show(struct kobject *kobj,
104 struct kobj_attribute *attr, char *page)
105{
106 int rc;
107
108 spin_lock_irq(&sclp_ocf_lock);
109 rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
110 spin_unlock_irq(&sclp_ocf_lock);
111 return rc;
112}
113
114static struct kobj_attribute hmc_network_attr =
115 __ATTR(hmc_network, 0444, hmc_network_show, NULL);
116
117static struct attribute *ocf_attrs[] = {
118 &cpc_name_attr.attr,
119 &hmc_network_attr.attr,
120 NULL,
121};
122
123static struct attribute_group ocf_attr_group = {
124 .attrs = ocf_attrs,
125};
126
127static int __init ocf_init(void)
128{
129 int rc;
130
131 INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
132 ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
133 if (!ocf_kset)
134 return -ENOMEM;
135
136 rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
137 if (rc) {
138 kset_unregister(ocf_kset);
139 return rc;
140 }
141
142 return sclp_register(&sclp_ocf_event);
143}
144
145device_initcall(ocf_init);