File Index
Files and directories
Sign in
FILE

sclp_cpi_sys.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/char/sclp_cpi_sys.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *    SCLP control program identification sysfs interface
  4 *
  5 *    Copyright IBM Corp. 2001, 2007
  6 *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  7 *		 Michael Ernst <mernst@de.ibm.com>
  8 */
  9
 10#define pr_fmt(fmt) "sclp_cpi: " 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 <linux/slab.h>
 22#include <linux/completion.h>
 23#include <linux/export.h>
 24#include <asm/ebcdic.h>
 25#include <asm/sclp.h>
 26
 27#include "sclp.h"
 28#include "sclp_rw.h"
 29#include "sclp_cpi_sys.h"
 30
 31#define CPI_LENGTH_NAME 8
 32#define CPI_LENGTH_LEVEL 16
 33
 34static DEFINE_MUTEX(sclp_cpi_mutex);
 35
 36struct cpi_evbuf {
 37	struct evbuf_header header;
 38	u8	id_format;
 39	u8	reserved0;
 40	u8	system_type[CPI_LENGTH_NAME];
 41	u64	reserved1;
 42	u8	system_name[CPI_LENGTH_NAME];
 43	u64	reserved2;
 44	u64	system_level;
 45	u64	reserved3;
 46	u8	sysplex_name[CPI_LENGTH_NAME];
 47	u8	reserved4[16];
 48} __attribute__((packed));
 49
 50struct cpi_sccb {
 51	struct sccb_header header;
 52	struct cpi_evbuf cpi_evbuf;
 53} __attribute__((packed));
 54
 55static struct sclp_register sclp_cpi_event = {
 56	.send_mask = EVTYP_CTLPROGIDENT_MASK,
 57};
 58
 59static char system_name[CPI_LENGTH_NAME + 1];
 60static char sysplex_name[CPI_LENGTH_NAME + 1];
 61static char system_type[CPI_LENGTH_NAME + 1];
 62static u64 system_level;
 63
 64static void set_data(char *field, char *data)
 65{
 66	memset(field, ' ', CPI_LENGTH_NAME);
 67	memcpy(field, data, strlen(data));
 68	sclp_ascebc_str(field, CPI_LENGTH_NAME);
 69}
 70
 71static void cpi_callback(struct sclp_req *req, void *data)
 72{
 73	struct completion *completion = data;
 74
 75	complete(completion);
 76}
 77
 78static struct sclp_req *cpi_prepare_req(void)
 79{
 80	struct sclp_req *req;
 81	struct cpi_sccb *sccb;
 82	struct cpi_evbuf *evb;
 83
 84	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
 85	if (!req)
 86		return ERR_PTR(-ENOMEM);
 87	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 88	if (!sccb) {
 89		kfree(req);
 90		return ERR_PTR(-ENOMEM);
 91	}
 92
 93	/* setup SCCB for Control-Program Identification */
 94	sccb->header.length = sizeof(struct cpi_sccb);
 95	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
 96	sccb->cpi_evbuf.header.type = EVTYP_CTLPROGIDENT;
 97	evb = &sccb->cpi_evbuf;
 98
 99	/* set system type */
100	set_data(evb->system_type, system_type);
101
102	/* set system name */
103	set_data(evb->system_name, system_name);
104
105	/* set system level */
106	evb->system_level = system_level;
107
108	/* set sysplex name */
109	set_data(evb->sysplex_name, sysplex_name);
110
111	/* prepare request data structure presented to SCLP driver */
112	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
113	req->sccb = sccb;
114	req->status = SCLP_REQ_FILLED;
115	req->callback = cpi_callback;
116	return req;
117}
118
119static void cpi_free_req(struct sclp_req *req)
120{
121	free_page((unsigned long) req->sccb);
122	kfree(req);
123}
124
125static int cpi_req(void)
126{
127	struct completion completion;
128	struct sclp_req *req;
129	int rc;
130	int response;
131
132	rc = sclp_register(&sclp_cpi_event);
133	if (rc)
134		goto out;
135	if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) {
136		rc = -EOPNOTSUPP;
137		goto out_unregister;
138	}
139
140	req = cpi_prepare_req();
141	if (IS_ERR(req)) {
142		rc = PTR_ERR(req);
143		goto out_unregister;
144	}
145
146	init_completion(&completion);
147	req->callback_data = &completion;
148
149	/* Add request to sclp queue */
150	rc = sclp_add_request(req);
151	if (rc)
152		goto out_free_req;
153
154	wait_for_completion(&completion);
155
156	if (req->status != SCLP_REQ_DONE) {
157		pr_warn("request failed (status=0x%02x)\n", req->status);
158		rc = -EIO;
159		goto out_free_req;
160	}
161
162	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
163	if (response != 0x0020) {
164		pr_warn("request failed with response code 0x%x\n", response);
165		rc = -EIO;
166	}
167
168out_free_req:
169	cpi_free_req(req);
170
171out_unregister:
172	sclp_unregister(&sclp_cpi_event);
173
174out:
175	return rc;
176}
177
178static int check_string(const char *attr, const char *str)
179{
180	size_t len;
181	size_t i;
182
183	len = strlen(str);
184
185	if ((len > 0) && (str[len - 1] == '\n'))
186		len--;
187
188	if (len > CPI_LENGTH_NAME)
189		return -EINVAL;
190
191	for (i = 0; i < len ; i++) {
192		if (isalpha(str[i]) || isdigit(str[i]) ||
193		    strchr("$@# ", str[i]))
194			continue;
195		return -EINVAL;
196	}
197
198	return 0;
199}
200
201static void set_string(char *attr, const char *value)
202{
203	size_t len;
204	size_t i;
205
206	len = strlen(value);
207
208	if ((len > 0) && (value[len - 1] == '\n'))
209		len--;
210
211	for (i = 0; i < CPI_LENGTH_NAME; i++) {
212		if (i < len)
213			attr[i] = toupper(value[i]);
214		else
215			attr[i] = ' ';
216	}
217}
218
219static ssize_t system_name_show(struct kobject *kobj,
220				struct kobj_attribute *attr, char *page)
221{
222	int rc;
223
224	mutex_lock(&sclp_cpi_mutex);
225	rc = sysfs_emit(page, "%s\n", system_name);
226	mutex_unlock(&sclp_cpi_mutex);
227	return rc;
228}
229
230static ssize_t system_name_store(struct kobject *kobj,
231				 struct kobj_attribute *attr,
232				 const char *buf,
233	size_t len)
234{
235	int rc;
236
237	rc = check_string("system_name", buf);
238	if (rc)
239		return rc;
240
241	mutex_lock(&sclp_cpi_mutex);
242	set_string(system_name, buf);
243	mutex_unlock(&sclp_cpi_mutex);
244
245	return len;
246}
247
248static struct kobj_attribute system_name_attr =
249	__ATTR(system_name, 0644, system_name_show, system_name_store);
250
251static ssize_t sysplex_name_show(struct kobject *kobj,
252				 struct kobj_attribute *attr, char *page)
253{
254	int rc;
255
256	mutex_lock(&sclp_cpi_mutex);
257	rc = sysfs_emit(page, "%s\n", sysplex_name);
258	mutex_unlock(&sclp_cpi_mutex);
259	return rc;
260}
261
262static ssize_t sysplex_name_store(struct kobject *kobj,
263				  struct kobj_attribute *attr,
264				  const char *buf,
265	size_t len)
266{
267	int rc;
268
269	rc = check_string("sysplex_name", buf);
270	if (rc)
271		return rc;
272
273	mutex_lock(&sclp_cpi_mutex);
274	set_string(sysplex_name, buf);
275	mutex_unlock(&sclp_cpi_mutex);
276
277	return len;
278}
279
280static struct kobj_attribute sysplex_name_attr =
281	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
282
283static ssize_t system_type_show(struct kobject *kobj,
284				struct kobj_attribute *attr, char *page)
285{
286	int rc;
287
288	mutex_lock(&sclp_cpi_mutex);
289	rc = sysfs_emit(page, "%s\n", system_type);
290	mutex_unlock(&sclp_cpi_mutex);
291	return rc;
292}
293
294static ssize_t system_type_store(struct kobject *kobj,
295				 struct kobj_attribute *attr,
296				 const char *buf,
297	size_t len)
298{
299	int rc;
300
301	rc = check_string("system_type", buf);
302	if (rc)
303		return rc;
304
305	mutex_lock(&sclp_cpi_mutex);
306	set_string(system_type, buf);
307	mutex_unlock(&sclp_cpi_mutex);
308
309	return len;
310}
311
312static struct kobj_attribute system_type_attr =
313	__ATTR(system_type, 0644, system_type_show, system_type_store);
314
315static ssize_t system_level_show(struct kobject *kobj,
316				 struct kobj_attribute *attr, char *page)
317{
318	unsigned long long level;
319
320	mutex_lock(&sclp_cpi_mutex);
321	level = system_level;
322	mutex_unlock(&sclp_cpi_mutex);
323	return sysfs_emit(page, "%#018llx\n", level);
324}
325
326static ssize_t system_level_store(struct kobject *kobj,
327				  struct kobj_attribute *attr,
328				  const char *buf,
329	size_t len)
330{
331	unsigned long long level;
332	char *endp;
333
334	level = simple_strtoull(buf, &endp, 16);
335
336	if (endp == buf)
337		return -EINVAL;
338	if (*endp == '\n')
339		endp++;
340	if (*endp)
341		return -EINVAL;
342
343	mutex_lock(&sclp_cpi_mutex);
344	system_level = level;
345	mutex_unlock(&sclp_cpi_mutex);
346	return len;
347}
348
349static struct kobj_attribute system_level_attr =
350	__ATTR(system_level, 0644, system_level_show, system_level_store);
351
352static ssize_t set_store(struct kobject *kobj,
353			 struct kobj_attribute *attr,
354			 const char *buf, size_t len)
355{
356	int rc;
357
358	mutex_lock(&sclp_cpi_mutex);
359	rc = cpi_req();
360	mutex_unlock(&sclp_cpi_mutex);
361	if (rc)
362		return rc;
363
364	return len;
365}
366
367static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
368
369static struct attribute *cpi_attrs[] = {
370	&system_name_attr.attr,
371	&sysplex_name_attr.attr,
372	&system_type_attr.attr,
373	&system_level_attr.attr,
374	&set_attr.attr,
375	NULL,
376};
377
378static struct attribute_group cpi_attr_group = {
379	.attrs = cpi_attrs,
380};
381
382static struct kset *cpi_kset;
383
384int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
385		      const u64 level)
386{
387	int rc;
388
389	rc = check_string("system_name", system);
390	if (rc)
391		return rc;
392	rc = check_string("sysplex_name", sysplex);
393	if (rc)
394		return rc;
395	rc = check_string("system_type", type);
396	if (rc)
397		return rc;
398
399	mutex_lock(&sclp_cpi_mutex);
400	set_string(system_name, system);
401	set_string(sysplex_name, sysplex);
402	set_string(system_type, type);
403	system_level = level;
404
405	rc = cpi_req();
406	mutex_unlock(&sclp_cpi_mutex);
407
408	return rc;
409}
410EXPORT_SYMBOL(sclp_cpi_set_data);
411
412static int __init cpi_init(void)
413{
414	int rc;
415
416	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
417	if (!cpi_kset)
418		return -ENOMEM;
419
420	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
421	if (rc)
422		kset_unregister(cpi_kset);
423
424	return rc;
425}
426
427__initcall(cpi_init);
~/ Read-only file preview.