linux/drivers/s390/char/sclp_cpi_sys.c
<<
>>
Prefs
   1/*
   2 *  drivers/s390/char/sclp_cpi_sys.c
   3 *    SCLP control program identification sysfs interface
   4 *
   5 *    Copyright IBM Corp. 2001, 2007
   6 *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
   7 *               Michael Ernst <mernst@de.ibm.com>
   8 */
   9
  10#define KMSG_COMPONENT "sclp_cpi"
  11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  12
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/stat.h>
  16#include <linux/device.h>
  17#include <linux/string.h>
  18#include <linux/ctype.h>
  19#include <linux/kmod.h>
  20#include <linux/timer.h>
  21#include <linux/err.h>
  22#include <linux/slab.h>
  23#include <linux/completion.h>
  24#include <linux/export.h>
  25#include <asm/ebcdic.h>
  26#include <asm/sclp.h>
  27
  28#include "sclp.h"
  29#include "sclp_rw.h"
  30#include "sclp_cpi_sys.h"
  31
  32#define CPI_LENGTH_NAME 8
  33#define CPI_LENGTH_LEVEL 16
  34
  35static DEFINE_MUTEX(sclp_cpi_mutex);
  36
  37struct cpi_evbuf {
  38        struct evbuf_header header;
  39        u8      id_format;
  40        u8      reserved0;
  41        u8      system_type[CPI_LENGTH_NAME];
  42        u64     reserved1;
  43        u8      system_name[CPI_LENGTH_NAME];
  44        u64     reserved2;
  45        u64     system_level;
  46        u64     reserved3;
  47        u8      sysplex_name[CPI_LENGTH_NAME];
  48        u8      reserved4[16];
  49} __attribute__((packed));
  50
  51struct cpi_sccb {
  52        struct sccb_header header;
  53        struct cpi_evbuf cpi_evbuf;
  54} __attribute__((packed));
  55
  56static struct sclp_register sclp_cpi_event = {
  57        .send_mask = EVTYP_CTLPROGIDENT_MASK,
  58};
  59
  60static char system_name[CPI_LENGTH_NAME + 1];
  61static char sysplex_name[CPI_LENGTH_NAME + 1];
  62static char system_type[CPI_LENGTH_NAME + 1];
  63static u64 system_level;
  64
  65static void set_data(char *field, char *data)
  66{
  67        memset(field, ' ', CPI_LENGTH_NAME);
  68        memcpy(field, data, strlen(data));
  69        sclp_ascebc_str(field, CPI_LENGTH_NAME);
  70}
  71
  72static void cpi_callback(struct sclp_req *req, void *data)
  73{
  74        struct completion *completion = data;
  75
  76        complete(completion);
  77}
  78
  79static struct sclp_req *cpi_prepare_req(void)
  80{
  81        struct sclp_req *req;
  82        struct cpi_sccb *sccb;
  83        struct cpi_evbuf *evb;
  84
  85        req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
  86        if (!req)
  87                return ERR_PTR(-ENOMEM);
  88        sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  89        if (!sccb) {
  90                kfree(req);
  91                return ERR_PTR(-ENOMEM);
  92        }
  93
  94        /* setup SCCB for Control-Program Identification */
  95        sccb->header.length = sizeof(struct cpi_sccb);
  96        sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
  97        sccb->cpi_evbuf.header.type = 0x0b;
  98        evb = &sccb->cpi_evbuf;
  99
 100        /* set system type */
 101        set_data(evb->system_type, system_type);
 102
 103        /* set system name */
 104        set_data(evb->system_name, system_name);
 105
 106        /* set system level */
 107        evb->system_level = system_level;
 108
 109        /* set sysplex name */
 110        set_data(evb->sysplex_name, sysplex_name);
 111
 112        /* prepare request data structure presented to SCLP driver */
 113        req->command = SCLP_CMDW_WRITE_EVENT_DATA;
 114        req->sccb = sccb;
 115        req->status = SCLP_REQ_FILLED;
 116        req->callback = cpi_callback;
 117        return req;
 118}
 119
 120static void cpi_free_req(struct sclp_req *req)
 121{
 122        free_page((unsigned long) req->sccb);
 123        kfree(req);
 124}
 125
 126static int cpi_req(void)
 127{
 128        struct completion completion;
 129        struct sclp_req *req;
 130        int rc;
 131        int response;
 132
 133        rc = sclp_register(&sclp_cpi_event);
 134        if (rc)
 135                goto out;
 136        if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) {
 137                rc = -EOPNOTSUPP;
 138                goto out_unregister;
 139        }
 140
 141        req = cpi_prepare_req();
 142        if (IS_ERR(req)) {
 143                rc = PTR_ERR(req);
 144                goto out_unregister;
 145        }
 146
 147        init_completion(&completion);
 148        req->callback_data = &completion;
 149
 150        /* Add request to sclp queue */
 151        rc = sclp_add_request(req);
 152        if (rc)
 153                goto out_free_req;
 154
 155        wait_for_completion(&completion);
 156
 157        if (req->status != SCLP_REQ_DONE) {
 158                pr_warning("request failed (status=0x%02x)\n",
 159                           req->status);
 160                rc = -EIO;
 161                goto out_free_req;
 162        }
 163
 164        response = ((struct cpi_sccb *) req->sccb)->header.response_code;
 165        if (response != 0x0020) {
 166                pr_warning("request failed with response code 0x%x\n",
 167                           response);
 168                rc = -EIO;
 169        }
 170
 171out_free_req:
 172        cpi_free_req(req);
 173
 174out_unregister:
 175        sclp_unregister(&sclp_cpi_event);
 176
 177out:
 178        return rc;
 179}
 180
 181static int check_string(const char *attr, const char *str)
 182{
 183        size_t len;
 184        size_t i;
 185
 186        len = strlen(str);
 187
 188        if ((len > 0) && (str[len - 1] == '\n'))
 189                len--;
 190
 191        if (len > CPI_LENGTH_NAME)
 192                return -EINVAL;
 193
 194        for (i = 0; i < len ; i++) {
 195                if (isalpha(str[i]) || isdigit(str[i]) ||
 196                    strchr("$@# ", str[i]))
 197                        continue;
 198                return -EINVAL;
 199        }
 200
 201        return 0;
 202}
 203
 204static void set_string(char *attr, const char *value)
 205{
 206        size_t len;
 207        size_t i;
 208
 209        len = strlen(value);
 210
 211        if ((len > 0) && (value[len - 1] == '\n'))
 212                len--;
 213
 214        for (i = 0; i < CPI_LENGTH_NAME; i++) {
 215                if (i < len)
 216                        attr[i] = toupper(value[i]);
 217                else
 218                        attr[i] = ' ';
 219        }
 220}
 221
 222static ssize_t system_name_show(struct kobject *kobj,
 223                                struct kobj_attribute *attr, char *page)
 224{
 225        int rc;
 226
 227        mutex_lock(&sclp_cpi_mutex);
 228        rc = snprintf(page, PAGE_SIZE, "%s\n", system_name);
 229        mutex_unlock(&sclp_cpi_mutex);
 230        return rc;
 231}
 232
 233static ssize_t system_name_store(struct kobject *kobj,
 234                                 struct kobj_attribute *attr,
 235                                 const char *buf,
 236        size_t len)
 237{
 238        int rc;
 239
 240        rc = check_string("system_name", buf);
 241        if (rc)
 242                return rc;
 243
 244        mutex_lock(&sclp_cpi_mutex);
 245        set_string(system_name, buf);
 246        mutex_unlock(&sclp_cpi_mutex);
 247
 248        return len;
 249}
 250
 251static struct kobj_attribute system_name_attr =
 252        __ATTR(system_name, 0644, system_name_show, system_name_store);
 253
 254static ssize_t sysplex_name_show(struct kobject *kobj,
 255                                 struct kobj_attribute *attr, char *page)
 256{
 257        int rc;
 258
 259        mutex_lock(&sclp_cpi_mutex);
 260        rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
 261        mutex_unlock(&sclp_cpi_mutex);
 262        return rc;
 263}
 264
 265static ssize_t sysplex_name_store(struct kobject *kobj,
 266                                  struct kobj_attribute *attr,
 267                                  const char *buf,
 268        size_t len)
 269{
 270        int rc;
 271
 272        rc = check_string("sysplex_name", buf);
 273        if (rc)
 274                return rc;
 275
 276        mutex_lock(&sclp_cpi_mutex);
 277        set_string(sysplex_name, buf);
 278        mutex_unlock(&sclp_cpi_mutex);
 279
 280        return len;
 281}
 282
 283static struct kobj_attribute sysplex_name_attr =
 284        __ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
 285
 286static ssize_t system_type_show(struct kobject *kobj,
 287                                struct kobj_attribute *attr, char *page)
 288{
 289        int rc;
 290
 291        mutex_lock(&sclp_cpi_mutex);
 292        rc = snprintf(page, PAGE_SIZE, "%s\n", system_type);
 293        mutex_unlock(&sclp_cpi_mutex);
 294        return rc;
 295}
 296
 297static ssize_t system_type_store(struct kobject *kobj,
 298                                 struct kobj_attribute *attr,
 299                                 const char *buf,
 300        size_t len)
 301{
 302        int rc;
 303
 304        rc = check_string("system_type", buf);
 305        if (rc)
 306                return rc;
 307
 308        mutex_lock(&sclp_cpi_mutex);
 309        set_string(system_type, buf);
 310        mutex_unlock(&sclp_cpi_mutex);
 311
 312        return len;
 313}
 314
 315static struct kobj_attribute system_type_attr =
 316        __ATTR(system_type, 0644, system_type_show, system_type_store);
 317
 318static ssize_t system_level_show(struct kobject *kobj,
 319                                 struct kobj_attribute *attr, char *page)
 320{
 321        unsigned long long level;
 322
 323        mutex_lock(&sclp_cpi_mutex);
 324        level = system_level;
 325        mutex_unlock(&sclp_cpi_mutex);
 326        return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
 327}
 328
 329static ssize_t system_level_store(struct kobject *kobj,
 330                                  struct kobj_attribute *attr,
 331                                  const char *buf,
 332        size_t len)
 333{
 334        unsigned long long level;
 335        char *endp;
 336
 337        level = simple_strtoull(buf, &endp, 16);
 338
 339        if (endp == buf)
 340                return -EINVAL;
 341        if (*endp == '\n')
 342                endp++;
 343        if (*endp)
 344                return -EINVAL;
 345
 346        mutex_lock(&sclp_cpi_mutex);
 347        system_level = level;
 348        mutex_unlock(&sclp_cpi_mutex);
 349        return len;
 350}
 351
 352static struct kobj_attribute system_level_attr =
 353        __ATTR(system_level, 0644, system_level_show, system_level_store);
 354
 355static ssize_t set_store(struct kobject *kobj,
 356                         struct kobj_attribute *attr,
 357                         const char *buf, size_t len)
 358{
 359        int rc;
 360
 361        mutex_lock(&sclp_cpi_mutex);
 362        rc = cpi_req();
 363        mutex_unlock(&sclp_cpi_mutex);
 364        if (rc)
 365                return rc;
 366
 367        return len;
 368}
 369
 370static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
 371
 372static struct attribute *cpi_attrs[] = {
 373        &system_name_attr.attr,
 374        &sysplex_name_attr.attr,
 375        &system_type_attr.attr,
 376        &system_level_attr.attr,
 377        &set_attr.attr,
 378        NULL,
 379};
 380
 381static struct attribute_group cpi_attr_group = {
 382        .attrs = cpi_attrs,
 383};
 384
 385static struct kset *cpi_kset;
 386
 387int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
 388                      const u64 level)
 389{
 390        int rc;
 391
 392        rc = check_string("system_name", system);
 393        if (rc)
 394                return rc;
 395        rc = check_string("sysplex_name", sysplex);
 396        if (rc)
 397                return rc;
 398        rc = check_string("system_type", type);
 399        if (rc)
 400                return rc;
 401
 402        mutex_lock(&sclp_cpi_mutex);
 403        set_string(system_name, system);
 404        set_string(sysplex_name, sysplex);
 405        set_string(system_type, type);
 406        system_level = level;
 407
 408        rc = cpi_req();
 409        mutex_unlock(&sclp_cpi_mutex);
 410
 411        return rc;
 412}
 413EXPORT_SYMBOL(sclp_cpi_set_data);
 414
 415static int __init cpi_init(void)
 416{
 417        int rc;
 418
 419        cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
 420        if (!cpi_kset)
 421                return -ENOMEM;
 422
 423        rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
 424        if (rc)
 425                kset_unregister(cpi_kset);
 426
 427        return rc;
 428}
 429
 430__initcall(cpi_init);
 431