brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · d35f10e Raw
153 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *    SCLP OCF communication parameters sysfs interface4 *5 *    Copyright IBM Corp. 20116 *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>7 */8 9#define KMSG_COMPONENT "sclp_ocf"10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt11 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 8UL27#define OCF_LENGTH_CPC_NAME 8UL28 29static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];30static char cpc_name[OCF_LENGTH_CPC_NAME]; /* in EBCDIC */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		memset(cpc_name, 0, OCF_LENGTH_CPC_NAME);77		memcpy(cpc_name, cpc + 1, size);78	}79	spin_unlock(&sclp_ocf_lock);80	schedule_work(&sclp_ocf_change_work);81}82 83static struct sclp_register sclp_ocf_event = {84	.receive_mask = EVTYP_OCF_MASK,85	.receiver_fn = sclp_ocf_handler,86};87 88void sclp_ocf_cpc_name_copy(char *dst)89{90	spin_lock_irq(&sclp_ocf_lock);91	memcpy(dst, cpc_name, OCF_LENGTH_CPC_NAME);92	spin_unlock_irq(&sclp_ocf_lock);93}94EXPORT_SYMBOL(sclp_ocf_cpc_name_copy);95 96static ssize_t cpc_name_show(struct kobject *kobj,97			     struct kobj_attribute *attr, char *page)98{99	char name[OCF_LENGTH_CPC_NAME + 1];100 101	sclp_ocf_cpc_name_copy(name);102	name[OCF_LENGTH_CPC_NAME] = 0;103	EBCASC(name, OCF_LENGTH_CPC_NAME);104	return snprintf(page, PAGE_SIZE, "%s\n", name);105}106 107static struct kobj_attribute cpc_name_attr =108	__ATTR(cpc_name, 0444, cpc_name_show, NULL);109 110static ssize_t hmc_network_show(struct kobject *kobj,111				struct kobj_attribute *attr, char *page)112{113	int rc;114 115	spin_lock_irq(&sclp_ocf_lock);116	rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);117	spin_unlock_irq(&sclp_ocf_lock);118	return rc;119}120 121static struct kobj_attribute hmc_network_attr =122	__ATTR(hmc_network, 0444, hmc_network_show, NULL);123 124static struct attribute *ocf_attrs[] = {125	&cpc_name_attr.attr,126	&hmc_network_attr.attr,127	NULL,128};129 130static const struct attribute_group ocf_attr_group = {131	.attrs = ocf_attrs,132};133 134static int __init ocf_init(void)135{136	int rc;137 138	INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);139	ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);140	if (!ocf_kset)141		return -ENOMEM;142 143	rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);144	if (rc) {145		kset_unregister(ocf_kset);146		return rc;147	}148 149	return sclp_register(&sclp_ocf_event);150}151 152device_initcall(ocf_init);153