-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 250550 b: refs/heads/master c: 7eb9d5b h: refs/heads/master v: v3
- Loading branch information
Martin Schwidefsky
committed
May 23, 2011
1 parent
7e72b37
commit 4341437
Showing
4 changed files
with
149 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 30c2df51173ea4e4755ad52be7f2914f01e32404 | ||
refs/heads/master: 7eb9d5bec552eff896ebf079386dc47e9dc2fc89 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/* | ||
* drivers/s390/char/sclp_ocf.c | ||
* SCLP OCF communication parameters sysfs interface | ||
* | ||
* Copyright IBM Corp. 2011 | ||
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
*/ | ||
|
||
#define KMSG_COMPONENT "sclp_ocf" | ||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/stat.h> | ||
#include <linux/device.h> | ||
#include <linux/string.h> | ||
#include <linux/ctype.h> | ||
#include <linux/kmod.h> | ||
#include <linux/timer.h> | ||
#include <linux/err.h> | ||
#include <asm/ebcdic.h> | ||
#include <asm/sclp.h> | ||
|
||
#include "sclp.h" | ||
|
||
#define OCF_LENGTH_HMC_NETWORK 8UL | ||
#define OCF_LENGTH_CPC_NAME 8UL | ||
|
||
static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1]; | ||
static char cpc_name[OCF_LENGTH_CPC_NAME + 1]; | ||
|
||
static DEFINE_SPINLOCK(sclp_ocf_lock); | ||
static struct work_struct sclp_ocf_change_work; | ||
|
||
static struct kset *ocf_kset; | ||
|
||
static void sclp_ocf_change_notify(struct work_struct *work) | ||
{ | ||
kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE); | ||
} | ||
|
||
/* Handler for OCF event. Look for the CPC image name. */ | ||
static void sclp_ocf_handler(struct evbuf_header *evbuf) | ||
{ | ||
struct gds_vector *v; | ||
struct gds_subvector *sv, *netid, *cpc; | ||
size_t size; | ||
|
||
/* Find the 0x9f00 block. */ | ||
v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, | ||
0x9f00); | ||
if (!v) | ||
return; | ||
/* Find the 0x9f22 block inside the 0x9f00 block. */ | ||
v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22); | ||
if (!v) | ||
return; | ||
/* Find the 0x81 block inside the 0x9f22 block. */ | ||
sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81); | ||
if (!sv) | ||
return; | ||
/* Find the 0x01 block inside the 0x81 block. */ | ||
netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1); | ||
/* Find the 0x02 block inside the 0x81 block. */ | ||
cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2); | ||
/* Copy network name and cpc name. */ | ||
spin_lock(&sclp_ocf_lock); | ||
if (netid) { | ||
size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length); | ||
memcpy(hmc_network, netid + 1, size); | ||
EBCASC(hmc_network, size); | ||
hmc_network[size] = 0; | ||
} | ||
if (cpc) { | ||
size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length); | ||
memcpy(cpc_name, cpc + 1, size); | ||
EBCASC(cpc_name, size); | ||
cpc_name[size] = 0; | ||
} | ||
spin_unlock(&sclp_ocf_lock); | ||
schedule_work(&sclp_ocf_change_work); | ||
} | ||
|
||
static struct sclp_register sclp_ocf_event = { | ||
.receive_mask = EVTYP_OCF_MASK, | ||
.receiver_fn = sclp_ocf_handler, | ||
}; | ||
|
||
static ssize_t cpc_name_show(struct kobject *kobj, | ||
struct kobj_attribute *attr, char *page) | ||
{ | ||
int rc; | ||
|
||
spin_lock_irq(&sclp_ocf_lock); | ||
rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name); | ||
spin_unlock_irq(&sclp_ocf_lock); | ||
return rc; | ||
} | ||
|
||
static struct kobj_attribute cpc_name_attr = | ||
__ATTR(cpc_name, 0444, cpc_name_show, NULL); | ||
|
||
static ssize_t hmc_network_show(struct kobject *kobj, | ||
struct kobj_attribute *attr, char *page) | ||
{ | ||
int rc; | ||
|
||
spin_lock_irq(&sclp_ocf_lock); | ||
rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); | ||
spin_unlock_irq(&sclp_ocf_lock); | ||
return rc; | ||
} | ||
|
||
static struct kobj_attribute hmc_network_attr = | ||
__ATTR(hmc_network, 0444, hmc_network_show, NULL); | ||
|
||
static struct attribute *ocf_attrs[] = { | ||
&cpc_name_attr.attr, | ||
&hmc_network_attr.attr, | ||
NULL, | ||
}; | ||
|
||
static struct attribute_group ocf_attr_group = { | ||
.attrs = ocf_attrs, | ||
}; | ||
|
||
static int __init ocf_init(void) | ||
{ | ||
int rc; | ||
|
||
INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify); | ||
ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj); | ||
if (!ocf_kset) | ||
return -ENOMEM; | ||
|
||
rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group); | ||
if (rc) { | ||
kset_unregister(ocf_kset); | ||
return rc; | ||
} | ||
|
||
return sclp_register(&sclp_ocf_event); | ||
} | ||
|
||
device_initcall(ocf_init); |