1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 27eb9d5beSMartin Schwidefsky /* 37eb9d5beSMartin Schwidefsky * SCLP OCF communication parameters sysfs interface 47eb9d5beSMartin Schwidefsky * 57eb9d5beSMartin Schwidefsky * Copyright IBM Corp. 2011 67eb9d5beSMartin Schwidefsky * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 77eb9d5beSMartin Schwidefsky */ 87eb9d5beSMartin Schwidefsky 97eb9d5beSMartin Schwidefsky #define KMSG_COMPONENT "sclp_ocf" 107eb9d5beSMartin Schwidefsky #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 117eb9d5beSMartin Schwidefsky 127eb9d5beSMartin Schwidefsky #include <linux/kernel.h> 137eb9d5beSMartin Schwidefsky #include <linux/init.h> 147eb9d5beSMartin Schwidefsky #include <linux/stat.h> 157eb9d5beSMartin Schwidefsky #include <linux/device.h> 167eb9d5beSMartin Schwidefsky #include <linux/string.h> 177eb9d5beSMartin Schwidefsky #include <linux/ctype.h> 187eb9d5beSMartin Schwidefsky #include <linux/kmod.h> 197eb9d5beSMartin Schwidefsky #include <linux/timer.h> 207eb9d5beSMartin Schwidefsky #include <linux/err.h> 217eb9d5beSMartin Schwidefsky #include <asm/ebcdic.h> 227eb9d5beSMartin Schwidefsky #include <asm/sclp.h> 237eb9d5beSMartin Schwidefsky 247eb9d5beSMartin Schwidefsky #include "sclp.h" 257eb9d5beSMartin Schwidefsky 267eb9d5beSMartin Schwidefsky #define OCF_LENGTH_HMC_NETWORK 8UL 277eb9d5beSMartin Schwidefsky #define OCF_LENGTH_CPC_NAME 8UL 287eb9d5beSMartin Schwidefsky 297eb9d5beSMartin Schwidefsky static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1]; 30e435dc31SJanosch Frank static char cpc_name[OCF_LENGTH_CPC_NAME]; /* in EBCDIC */ 317eb9d5beSMartin Schwidefsky 327eb9d5beSMartin Schwidefsky static DEFINE_SPINLOCK(sclp_ocf_lock); 337eb9d5beSMartin Schwidefsky static struct work_struct sclp_ocf_change_work; 347eb9d5beSMartin Schwidefsky 357eb9d5beSMartin Schwidefsky static struct kset *ocf_kset; 367eb9d5beSMartin Schwidefsky 377eb9d5beSMartin Schwidefsky static void sclp_ocf_change_notify(struct work_struct *work) 387eb9d5beSMartin Schwidefsky { 397eb9d5beSMartin Schwidefsky kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE); 407eb9d5beSMartin Schwidefsky } 417eb9d5beSMartin Schwidefsky 427eb9d5beSMartin Schwidefsky /* Handler for OCF event. Look for the CPC image name. */ 437eb9d5beSMartin Schwidefsky static void sclp_ocf_handler(struct evbuf_header *evbuf) 447eb9d5beSMartin Schwidefsky { 457eb9d5beSMartin Schwidefsky struct gds_vector *v; 467eb9d5beSMartin Schwidefsky struct gds_subvector *sv, *netid, *cpc; 477eb9d5beSMartin Schwidefsky size_t size; 487eb9d5beSMartin Schwidefsky 497eb9d5beSMartin Schwidefsky /* Find the 0x9f00 block. */ 507eb9d5beSMartin Schwidefsky v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, 517eb9d5beSMartin Schwidefsky 0x9f00); 527eb9d5beSMartin Schwidefsky if (!v) 537eb9d5beSMartin Schwidefsky return; 547eb9d5beSMartin Schwidefsky /* Find the 0x9f22 block inside the 0x9f00 block. */ 557eb9d5beSMartin Schwidefsky v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22); 567eb9d5beSMartin Schwidefsky if (!v) 577eb9d5beSMartin Schwidefsky return; 587eb9d5beSMartin Schwidefsky /* Find the 0x81 block inside the 0x9f22 block. */ 597eb9d5beSMartin Schwidefsky sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81); 607eb9d5beSMartin Schwidefsky if (!sv) 617eb9d5beSMartin Schwidefsky return; 627eb9d5beSMartin Schwidefsky /* Find the 0x01 block inside the 0x81 block. */ 637eb9d5beSMartin Schwidefsky netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1); 647eb9d5beSMartin Schwidefsky /* Find the 0x02 block inside the 0x81 block. */ 657eb9d5beSMartin Schwidefsky cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2); 667eb9d5beSMartin Schwidefsky /* Copy network name and cpc name. */ 677eb9d5beSMartin Schwidefsky spin_lock(&sclp_ocf_lock); 687eb9d5beSMartin Schwidefsky if (netid) { 697eb9d5beSMartin Schwidefsky size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length); 707eb9d5beSMartin Schwidefsky memcpy(hmc_network, netid + 1, size); 717eb9d5beSMartin Schwidefsky EBCASC(hmc_network, size); 727eb9d5beSMartin Schwidefsky hmc_network[size] = 0; 737eb9d5beSMartin Schwidefsky } 747eb9d5beSMartin Schwidefsky if (cpc) { 757eb9d5beSMartin Schwidefsky size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length); 76e435dc31SJanosch Frank memset(cpc_name, 0, OCF_LENGTH_CPC_NAME); 777eb9d5beSMartin Schwidefsky memcpy(cpc_name, cpc + 1, size); 787eb9d5beSMartin Schwidefsky } 797eb9d5beSMartin Schwidefsky spin_unlock(&sclp_ocf_lock); 807eb9d5beSMartin Schwidefsky schedule_work(&sclp_ocf_change_work); 817eb9d5beSMartin Schwidefsky } 827eb9d5beSMartin Schwidefsky 837eb9d5beSMartin Schwidefsky static struct sclp_register sclp_ocf_event = { 847eb9d5beSMartin Schwidefsky .receive_mask = EVTYP_OCF_MASK, 857eb9d5beSMartin Schwidefsky .receiver_fn = sclp_ocf_handler, 867eb9d5beSMartin Schwidefsky }; 877eb9d5beSMartin Schwidefsky 88e435dc31SJanosch Frank void sclp_ocf_cpc_name_copy(char *dst) 89e435dc31SJanosch Frank { 90e435dc31SJanosch Frank spin_lock_irq(&sclp_ocf_lock); 91e435dc31SJanosch Frank memcpy(dst, cpc_name, OCF_LENGTH_CPC_NAME); 92e435dc31SJanosch Frank spin_unlock_irq(&sclp_ocf_lock); 93e435dc31SJanosch Frank } 94e435dc31SJanosch Frank EXPORT_SYMBOL(sclp_ocf_cpc_name_copy); 95e435dc31SJanosch Frank 967eb9d5beSMartin Schwidefsky static ssize_t cpc_name_show(struct kobject *kobj, 977eb9d5beSMartin Schwidefsky struct kobj_attribute *attr, char *page) 987eb9d5beSMartin Schwidefsky { 99e435dc31SJanosch Frank char name[OCF_LENGTH_CPC_NAME + 1]; 1007eb9d5beSMartin Schwidefsky 101e435dc31SJanosch Frank sclp_ocf_cpc_name_copy(name); 102e435dc31SJanosch Frank name[OCF_LENGTH_CPC_NAME] = 0; 103e435dc31SJanosch Frank EBCASC(name, OCF_LENGTH_CPC_NAME); 104e435dc31SJanosch Frank return snprintf(page, PAGE_SIZE, "%s\n", name); 1057eb9d5beSMartin Schwidefsky } 1067eb9d5beSMartin Schwidefsky 1077eb9d5beSMartin Schwidefsky static struct kobj_attribute cpc_name_attr = 1087eb9d5beSMartin Schwidefsky __ATTR(cpc_name, 0444, cpc_name_show, NULL); 1097eb9d5beSMartin Schwidefsky 1107eb9d5beSMartin Schwidefsky static ssize_t hmc_network_show(struct kobject *kobj, 1117eb9d5beSMartin Schwidefsky struct kobj_attribute *attr, char *page) 1127eb9d5beSMartin Schwidefsky { 1137eb9d5beSMartin Schwidefsky int rc; 1147eb9d5beSMartin Schwidefsky 1157eb9d5beSMartin Schwidefsky spin_lock_irq(&sclp_ocf_lock); 1167eb9d5beSMartin Schwidefsky rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); 1177eb9d5beSMartin Schwidefsky spin_unlock_irq(&sclp_ocf_lock); 1187eb9d5beSMartin Schwidefsky return rc; 1197eb9d5beSMartin Schwidefsky } 1207eb9d5beSMartin Schwidefsky 1217eb9d5beSMartin Schwidefsky static struct kobj_attribute hmc_network_attr = 1227eb9d5beSMartin Schwidefsky __ATTR(hmc_network, 0444, hmc_network_show, NULL); 1237eb9d5beSMartin Schwidefsky 1247eb9d5beSMartin Schwidefsky static struct attribute *ocf_attrs[] = { 1257eb9d5beSMartin Schwidefsky &cpc_name_attr.attr, 1267eb9d5beSMartin Schwidefsky &hmc_network_attr.attr, 1277eb9d5beSMartin Schwidefsky NULL, 1287eb9d5beSMartin Schwidefsky }; 1297eb9d5beSMartin Schwidefsky 1308351378fSArvind Yadav static const struct attribute_group ocf_attr_group = { 1317eb9d5beSMartin Schwidefsky .attrs = ocf_attrs, 1327eb9d5beSMartin Schwidefsky }; 1337eb9d5beSMartin Schwidefsky 1347eb9d5beSMartin Schwidefsky static int __init ocf_init(void) 1357eb9d5beSMartin Schwidefsky { 1367eb9d5beSMartin Schwidefsky int rc; 1377eb9d5beSMartin Schwidefsky 1387eb9d5beSMartin Schwidefsky INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify); 1397eb9d5beSMartin Schwidefsky ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj); 1407eb9d5beSMartin Schwidefsky if (!ocf_kset) 1417eb9d5beSMartin Schwidefsky return -ENOMEM; 1427eb9d5beSMartin Schwidefsky 1437eb9d5beSMartin Schwidefsky rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group); 1447eb9d5beSMartin Schwidefsky if (rc) { 1457eb9d5beSMartin Schwidefsky kset_unregister(ocf_kset); 1467eb9d5beSMartin Schwidefsky return rc; 1477eb9d5beSMartin Schwidefsky } 1487eb9d5beSMartin Schwidefsky 1497eb9d5beSMartin Schwidefsky return sclp_register(&sclp_ocf_event); 1507eb9d5beSMartin Schwidefsky } 1517eb9d5beSMartin Schwidefsky 1527eb9d5beSMartin Schwidefsky device_initcall(ocf_init); 153