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