chp.c revision e6b6e10ac1de116fc6d2288f185393014851cccf
1e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* 2e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * drivers/s390/cio/chp.c 3e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 4e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Copyright IBM Corp. 1999,2007 5e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) 6e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Arnd Bergmann (arndb@de.ibm.com) 7e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 8e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 9e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 10e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include <linux/bug.h> 11e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include <linux/workqueue.h> 12e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include <linux/spinlock.h> 13e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include <asm/errno.h> 14e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 15e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "chpid.h" 16e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "cio.h" 17e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "css.h" 18e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "ioasm.h" 19e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "cio_debug.h" 20e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "chp.h" 21e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 22e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#define to_channelpath(device) container_of(device, struct channel_path, dev) 23e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 24e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* Return channel_path struct for given chpid. */ 25e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic inline struct channel_path *chpid_to_chp(struct chp_id chpid) 26e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 27e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return css[chpid.cssid]->chps[chpid.id]; 28e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 29e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 30e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* Set vary state for given chpid. */ 31e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic void set_chp_logically_online(struct chp_id chpid, int onoff) 32e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 33e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid_to_chp(chpid)->state = onoff; 34e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 35e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 36e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* On succes return 0 if channel-path is varied offline, 1 if it is varied 37e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * online. Return -ENODEV if channel-path is not registered. */ 38e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterint chp_get_status(struct chp_id chpid) 39e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 40e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV); 41e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 42e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 43e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/** 44e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * chp_get_sch_opm - return opm for subchannel 45e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @sch: subchannel 46e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 47e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Calculate and return the operational path mask (opm) based on the chpids 48e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * used by the subchannel and the status of the associated channel-paths. 49e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 50e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiteru8 chp_get_sch_opm(struct subchannel *sch) 51e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 52e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct chp_id chpid; 53e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int opm; 54e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int i; 55e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 56e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter opm = 0; 57e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp_id_init(&chpid); 58e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter for (i=0; i < 8; i++) { 59e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter opm <<= 1; 60e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.id = sch->schib.pmcw.chpid[i]; 61e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (chp_get_status(chpid) != 0) 62e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter opm |= 1; 63e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 64e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return opm; 65e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 66e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 67e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/** 68e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * chp_is_registered - check if a channel-path is registered 69e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @chpid: channel-path ID 70e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 71e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Return non-zero if a channel-path with the given chpid is registered, 72e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * zero otherwise. 73e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 74e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterint chp_is_registered(struct chp_id chpid) 75e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 76e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return chpid_to_chp(chpid) != NULL; 77e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 78e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 79e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* 80e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Function: s390_vary_chpid 81e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Varies the specified chpid online or offline 82e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 83e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic int s390_vary_chpid(struct chp_id chpid, int on) 84e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 85e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter char dbf_text[15]; 86e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int status; 87e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 88e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, 89e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.id); 90e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter CIO_TRACE_EVENT( 2, dbf_text); 91e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 92e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter status = chp_get_status(chpid); 93e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (status < 0) { 94e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n", 95e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.cssid, chpid.id); 96e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return -EINVAL; 97e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 98e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 99e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!on && !status) { 100e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter printk(KERN_ERR "chpid %x.%02x is already offline\n", 101e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.cssid, chpid.id); 102e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return -EINVAL; 103e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 104e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 105e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter set_chp_logically_online(chpid, on); 106e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chsc_chp_vary(chpid, on); 107e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 108e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 109e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 110e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* 111e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Channel measurement related functions 112e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 113e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, 114e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter loff_t off, size_t count) 115e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 116e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp; 117e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter unsigned int size; 118e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 119e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp = to_channelpath(container_of(kobj, struct device, kobj)); 120e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp->cmg_chars) 121e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 122e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 123e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter size = sizeof(struct cmg_chars); 124e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 125e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (off > size) 126e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 127e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (off + count > size) 128e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter count = size - off; 129e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter memcpy(buf, chp->cmg_chars + off, count); 130e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return count; 131e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 132e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 133e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic struct bin_attribute chp_measurement_chars_attr = { 134e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .attr = { 135e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .name = "measurement_chars", 136e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .mode = S_IRUSR, 137e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .owner = THIS_MODULE, 138e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter }, 139e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .size = sizeof(struct cmg_chars), 140e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .read = chp_measurement_chars_read, 141e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter}; 142e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 143e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic void chp_measurement_copy_block(struct cmg_entry *buf, 144e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_subsystem *css, 145e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct chp_id chpid) 146e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 147e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter void *area; 148e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct cmg_entry *entry, reference_buf; 149e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int idx; 150e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 151e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (chpid.id < 128) { 152e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter area = css->cub_addr1; 153e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter idx = chpid.id; 154e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } else { 155e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter area = css->cub_addr2; 156e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter idx = chpid.id - 128; 157e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 158e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter entry = area + (idx * sizeof(struct cmg_entry)); 159e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter do { 160e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter memcpy(buf, entry, sizeof(*entry)); 161e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter memcpy(&reference_buf, entry, sizeof(*entry)); 162e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } while (reference_buf.values[0] != buf->values[0]); 163e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 164e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 165e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_measurement_read(struct kobject *kobj, char *buf, 166e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter loff_t off, size_t count) 167e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 168e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp; 169e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_subsystem *css; 170e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter unsigned int size; 171e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 172e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp = to_channelpath(container_of(kobj, struct device, kobj)); 173e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter css = to_css(chp->dev.parent); 174e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 175e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter size = sizeof(struct cmg_entry); 176e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 177e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter /* Only allow single reads. */ 178e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (off || count < size) 179e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 180e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid); 181e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter count = size; 182e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return count; 183e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 184e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 185e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic struct bin_attribute chp_measurement_attr = { 186e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .attr = { 187e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .name = "measurement", 188e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .mode = S_IRUSR, 189e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .owner = THIS_MODULE, 190e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter }, 191e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .size = sizeof(struct cmg_entry), 192e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .read = chp_measurement_read, 193e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter}; 194e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 195e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleitervoid chp_remove_cmg_attr(struct channel_path *chp) 196e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 197e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); 198e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter device_remove_bin_file(&chp->dev, &chp_measurement_attr); 199e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 200e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 201e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterint chp_add_cmg_attr(struct channel_path *chp) 202e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 203e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int ret; 204e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 205e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); 206e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) 207e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return ret; 208e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); 209e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) 210e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); 211e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return ret; 212e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 213e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 214e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/* 215e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Files for the channel path entries. 216e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 217e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_status_show(struct device *dev, 218e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct device_attribute *attr, char *buf) 219e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 220e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp = container_of(dev, struct channel_path, dev); 221e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 222e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 223e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 224e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") : 225e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter sprintf(buf, "offline\n")); 226e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 227e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 228e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_status_write(struct device *dev, 229e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct device_attribute *attr, 230e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter const char *buf, size_t count) 231e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 232e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *cp = container_of(dev, struct channel_path, dev); 233e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter char cmd[10]; 234e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int num_args; 235e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int error; 236e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 237e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter num_args = sscanf(buf, "%5s", cmd); 238e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!num_args) 239e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return count; 240e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 241e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) 242e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter error = s390_vary_chpid(cp->chpid, 1); 243e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) 244e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter error = s390_vary_chpid(cp->chpid, 0); 245e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter else 246e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter error = -EINVAL; 247e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 248e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return error < 0 ? error : count; 249e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 250e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 251e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 252e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); 253e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 254e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, 255e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter char *buf) 256e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 257e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp = container_of(dev, struct channel_path, dev); 258e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 259e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 260e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 261e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return sprintf(buf, "%x\n", chp->desc.desc); 262e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 263e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 264e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic DEVICE_ATTR(type, 0444, chp_type_show, NULL); 265e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 266e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr, 267e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter char *buf) 268e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 269e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp = to_channelpath(dev); 270e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 271e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 272e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 273e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (chp->cmg == -1) /* channel measurements not available */ 274e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return sprintf(buf, "unknown\n"); 275e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return sprintf(buf, "%x\n", chp->cmg); 276e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 277e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 278e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL); 279e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 280e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic ssize_t chp_shared_show(struct device *dev, 281e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct device_attribute *attr, char *buf) 282e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 283e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp = to_channelpath(dev); 284e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 285e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 286e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 287e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (chp->shared == -1) /* channel measurements not available */ 288e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return sprintf(buf, "unknown\n"); 289e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return sprintf(buf, "%x\n", chp->shared); 290e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 291e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 292e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); 293e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 294e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic struct attribute * chp_attrs[] = { 295e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter &dev_attr_status.attr, 296e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter &dev_attr_type.attr, 297e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter &dev_attr_cmg.attr, 298e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter &dev_attr_shared.attr, 299e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter NULL, 300e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter}; 301e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 302e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic struct attribute_group chp_attr_group = { 303e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter .attrs = chp_attrs, 304e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter}; 305e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 306e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterstatic void chp_release(struct device *dev) 307e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 308e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *cp; 309e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 310e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter cp = container_of(dev, struct channel_path, dev); 311e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter kfree(cp); 312e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 313e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 314e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/** 315e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * chp_new - register a new channel-path 316e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @chpid - channel-path ID 317e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 318e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Create and register data structure representing new channel-path. Return 319e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * zero on success, non-zero otherwise. 320e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 321e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterint chp_new(struct chp_id chpid) 322e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 323e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp; 324e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter int ret; 325e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 326e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL); 327e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 328e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return -ENOMEM; 329e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 330e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter /* fill in status, etc. */ 331e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp->chpid = chpid; 332e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp->state = 1; 333e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp->dev.parent = &css[chpid.cssid]->device; 334e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp->dev.release = chp_release; 335e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, 336e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.id); 337e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 338e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter /* Obtain channel path description and fill it in. */ 339e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = chsc_determine_channel_path_description(chpid, &chp->desc); 340e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) 341e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter goto out_free; 342e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter /* Get channel-measurement characteristics. */ 343e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (css_characteristics_avail && css_chsc_characteristics.scmc 344e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter && css_chsc_characteristics.secm) { 345e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = chsc_get_channel_measurement_chars(chp); 346e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) 347e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter goto out_free; 348e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } else { 349e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter static int msg_done; 350e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 351e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!msg_done) { 352e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter printk(KERN_WARNING "cio: Channel measurements not " 353e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter "available, continuing.\n"); 354e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter msg_done = 1; 355e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 356e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp->cmg = -1; 357e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 358e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 359e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter /* make it known to the system */ 360e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = device_register(&chp->dev); 361e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) { 362e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter printk(KERN_WARNING "%s: could not register %x.%02x\n", 363e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter __func__, chpid.cssid, chpid.id); 364e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter goto out_free; 365e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 366e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); 367e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) { 368e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter device_unregister(&chp->dev); 369e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter goto out_free; 370e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 371e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter mutex_lock(&css[chpid.cssid]->mutex); 372e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (css[chpid.cssid]->cm_enabled) { 373e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter ret = chp_add_cmg_attr(chp); 374e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (ret) { 375e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); 376e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter device_unregister(&chp->dev); 377e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter mutex_unlock(&css[chpid.cssid]->mutex); 378e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter goto out_free; 379e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 380e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 381e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter css[chpid.cssid]->chps[chpid.id] = chp; 382e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter mutex_unlock(&css[chpid.cssid]->mutex); 383e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return ret; 384e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterout_free: 385e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter kfree(chp); 386e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return ret; 387e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 388e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 389e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/** 390e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * chp_get_chp_desc - return newly allocated channel-path description 391e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @chpid: channel-path ID 392e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 393e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * On success return a newly allocated copy of the channel-path description 394e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * data associated with the given channel-path ID. Return %NULL on error. 395e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 396e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleitervoid *chp_get_chp_desc(struct chp_id chpid) 397e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 398e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path *chp; 399e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct channel_path_desc *desc; 400e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 401e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp = chpid_to_chp(chpid); 402e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp) 403e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return NULL; 404e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); 405e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!desc) 406e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return NULL; 407e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); 408e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return desc; 409e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 410e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 411e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter/** 412e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * chp_process_crw - process channel-path status change 413e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @id: channel-path ID number 414e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * @status: non-zero if channel-path has become available, zero otherwise 415e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * 416e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * Handle channel-report-words indicating that the status of a channel-path 417e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter * has changed. 418e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter */ 419e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiterint chp_process_crw(int id, int status) 420e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter{ 421e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter struct chp_id chpid; 422e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter 423e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp_id_init(&chpid); 424e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chpid.id = id; 425e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (status) { 426e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter if (!chp_is_registered(chpid)) 427e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chp_new(chpid); 428e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return chsc_chp_online(chpid); 429e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } else { 430e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter chsc_chp_offline(chpid); 431e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter return 0; 432e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter } 433e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter} 434