root/drivers/s390/char/sclp_cpi_sys.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_data
  2. cpi_callback
  3. cpi_prepare_req
  4. cpi_free_req
  5. cpi_req
  6. check_string
  7. set_string
  8. system_name_show
  9. system_name_store
  10. sysplex_name_show
  11. sysplex_name_store
  12. system_type_show
  13. system_type_store
  14. system_level_show
  15. system_level_store
  16. set_store
  17. sclp_cpi_set_data
  18. cpi_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   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 
  35 static DEFINE_MUTEX(sclp_cpi_mutex);
  36 
  37 struct 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 
  51 struct cpi_sccb {
  52         struct sccb_header header;
  53         struct cpi_evbuf cpi_evbuf;
  54 } __attribute__((packed));
  55 
  56 static struct sclp_register sclp_cpi_event = {
  57         .send_mask = EVTYP_CTLPROGIDENT_MASK,
  58 };
  59 
  60 static char system_name[CPI_LENGTH_NAME + 1];
  61 static char sysplex_name[CPI_LENGTH_NAME + 1];
  62 static char system_type[CPI_LENGTH_NAME + 1];
  63 static u64 system_level;
  64 
  65 static 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 
  72 static void cpi_callback(struct sclp_req *req, void *data)
  73 {
  74         struct completion *completion = data;
  75 
  76         complete(completion);
  77 }
  78 
  79 static 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 = EVTYP_CTLPROGIDENT;
  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 
 120 static void cpi_free_req(struct sclp_req *req)
 121 {
 122         free_page((unsigned long) req->sccb);
 123         kfree(req);
 124 }
 125 
 126 static 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_warn("request failed (status=0x%02x)\n", req->status);
 159                 rc = -EIO;
 160                 goto out_free_req;
 161         }
 162 
 163         response = ((struct cpi_sccb *) req->sccb)->header.response_code;
 164         if (response != 0x0020) {
 165                 pr_warn("request failed with response code 0x%x\n", response);
 166                 rc = -EIO;
 167         }
 168 
 169 out_free_req:
 170         cpi_free_req(req);
 171 
 172 out_unregister:
 173         sclp_unregister(&sclp_cpi_event);
 174 
 175 out:
 176         return rc;
 177 }
 178 
 179 static int check_string(const char *attr, const char *str)
 180 {
 181         size_t len;
 182         size_t i;
 183 
 184         len = strlen(str);
 185 
 186         if ((len > 0) && (str[len - 1] == '\n'))
 187                 len--;
 188 
 189         if (len > CPI_LENGTH_NAME)
 190                 return -EINVAL;
 191 
 192         for (i = 0; i < len ; i++) {
 193                 if (isalpha(str[i]) || isdigit(str[i]) ||
 194                     strchr("$@# ", str[i]))
 195                         continue;
 196                 return -EINVAL;
 197         }
 198 
 199         return 0;
 200 }
 201 
 202 static void set_string(char *attr, const char *value)
 203 {
 204         size_t len;
 205         size_t i;
 206 
 207         len = strlen(value);
 208 
 209         if ((len > 0) && (value[len - 1] == '\n'))
 210                 len--;
 211 
 212         for (i = 0; i < CPI_LENGTH_NAME; i++) {
 213                 if (i < len)
 214                         attr[i] = toupper(value[i]);
 215                 else
 216                         attr[i] = ' ';
 217         }
 218 }
 219 
 220 static ssize_t system_name_show(struct kobject *kobj,
 221                                 struct kobj_attribute *attr, char *page)
 222 {
 223         int rc;
 224 
 225         mutex_lock(&sclp_cpi_mutex);
 226         rc = snprintf(page, PAGE_SIZE, "%s\n", system_name);
 227         mutex_unlock(&sclp_cpi_mutex);
 228         return rc;
 229 }
 230 
 231 static ssize_t system_name_store(struct kobject *kobj,
 232                                  struct kobj_attribute *attr,
 233                                  const char *buf,
 234         size_t len)
 235 {
 236         int rc;
 237 
 238         rc = check_string("system_name", buf);
 239         if (rc)
 240                 return rc;
 241 
 242         mutex_lock(&sclp_cpi_mutex);
 243         set_string(system_name, buf);
 244         mutex_unlock(&sclp_cpi_mutex);
 245 
 246         return len;
 247 }
 248 
 249 static struct kobj_attribute system_name_attr =
 250         __ATTR(system_name, 0644, system_name_show, system_name_store);
 251 
 252 static ssize_t sysplex_name_show(struct kobject *kobj,
 253                                  struct kobj_attribute *attr, char *page)
 254 {
 255         int rc;
 256 
 257         mutex_lock(&sclp_cpi_mutex);
 258         rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
 259         mutex_unlock(&sclp_cpi_mutex);
 260         return rc;
 261 }
 262 
 263 static ssize_t sysplex_name_store(struct kobject *kobj,
 264                                   struct kobj_attribute *attr,
 265                                   const char *buf,
 266         size_t len)
 267 {
 268         int rc;
 269 
 270         rc = check_string("sysplex_name", buf);
 271         if (rc)
 272                 return rc;
 273 
 274         mutex_lock(&sclp_cpi_mutex);
 275         set_string(sysplex_name, buf);
 276         mutex_unlock(&sclp_cpi_mutex);
 277 
 278         return len;
 279 }
 280 
 281 static struct kobj_attribute sysplex_name_attr =
 282         __ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
 283 
 284 static ssize_t system_type_show(struct kobject *kobj,
 285                                 struct kobj_attribute *attr, char *page)
 286 {
 287         int rc;
 288 
 289         mutex_lock(&sclp_cpi_mutex);
 290         rc = snprintf(page, PAGE_SIZE, "%s\n", system_type);
 291         mutex_unlock(&sclp_cpi_mutex);
 292         return rc;
 293 }
 294 
 295 static ssize_t system_type_store(struct kobject *kobj,
 296                                  struct kobj_attribute *attr,
 297                                  const char *buf,
 298         size_t len)
 299 {
 300         int rc;
 301 
 302         rc = check_string("system_type", buf);
 303         if (rc)
 304                 return rc;
 305 
 306         mutex_lock(&sclp_cpi_mutex);
 307         set_string(system_type, buf);
 308         mutex_unlock(&sclp_cpi_mutex);
 309 
 310         return len;
 311 }
 312 
 313 static struct kobj_attribute system_type_attr =
 314         __ATTR(system_type, 0644, system_type_show, system_type_store);
 315 
 316 static ssize_t system_level_show(struct kobject *kobj,
 317                                  struct kobj_attribute *attr, char *page)
 318 {
 319         unsigned long long level;
 320 
 321         mutex_lock(&sclp_cpi_mutex);
 322         level = system_level;
 323         mutex_unlock(&sclp_cpi_mutex);
 324         return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
 325 }
 326 
 327 static ssize_t system_level_store(struct kobject *kobj,
 328                                   struct kobj_attribute *attr,
 329                                   const char *buf,
 330         size_t len)
 331 {
 332         unsigned long long level;
 333         char *endp;
 334 
 335         level = simple_strtoull(buf, &endp, 16);
 336 
 337         if (endp == buf)
 338                 return -EINVAL;
 339         if (*endp == '\n')
 340                 endp++;
 341         if (*endp)
 342                 return -EINVAL;
 343 
 344         mutex_lock(&sclp_cpi_mutex);
 345         system_level = level;
 346         mutex_unlock(&sclp_cpi_mutex);
 347         return len;
 348 }
 349 
 350 static struct kobj_attribute system_level_attr =
 351         __ATTR(system_level, 0644, system_level_show, system_level_store);
 352 
 353 static ssize_t set_store(struct kobject *kobj,
 354                          struct kobj_attribute *attr,
 355                          const char *buf, size_t len)
 356 {
 357         int rc;
 358 
 359         mutex_lock(&sclp_cpi_mutex);
 360         rc = cpi_req();
 361         mutex_unlock(&sclp_cpi_mutex);
 362         if (rc)
 363                 return rc;
 364 
 365         return len;
 366 }
 367 
 368 static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
 369 
 370 static struct attribute *cpi_attrs[] = {
 371         &system_name_attr.attr,
 372         &sysplex_name_attr.attr,
 373         &system_type_attr.attr,
 374         &system_level_attr.attr,
 375         &set_attr.attr,
 376         NULL,
 377 };
 378 
 379 static struct attribute_group cpi_attr_group = {
 380         .attrs = cpi_attrs,
 381 };
 382 
 383 static struct kset *cpi_kset;
 384 
 385 int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
 386                       const u64 level)
 387 {
 388         int rc;
 389 
 390         rc = check_string("system_name", system);
 391         if (rc)
 392                 return rc;
 393         rc = check_string("sysplex_name", sysplex);
 394         if (rc)
 395                 return rc;
 396         rc = check_string("system_type", type);
 397         if (rc)
 398                 return rc;
 399 
 400         mutex_lock(&sclp_cpi_mutex);
 401         set_string(system_name, system);
 402         set_string(sysplex_name, sysplex);
 403         set_string(system_type, type);
 404         system_level = level;
 405 
 406         rc = cpi_req();
 407         mutex_unlock(&sclp_cpi_mutex);
 408 
 409         return rc;
 410 }
 411 EXPORT_SYMBOL(sclp_cpi_set_data);
 412 
 413 static int __init cpi_init(void)
 414 {
 415         int rc;
 416 
 417         cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
 418         if (!cpi_kset)
 419                 return -ENOMEM;
 420 
 421         rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
 422         if (rc)
 423                 kset_unregister(cpi_kset);
 424 
 425         return rc;
 426 }
 427 
 428 __initcall(cpi_init);

/* [<][>][^][v][top][bottom][index][help] */