sclp_cpi_sys.c (8793B)
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 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 = 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 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_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 169out_free_req: 170 cpi_free_req(req); 171 172out_unregister: 173 sclp_unregister(&sclp_cpi_event); 174 175out: 176 return rc; 177} 178 179static 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 202static 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 220static 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 231static 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 249static struct kobj_attribute system_name_attr = 250 __ATTR(system_name, 0644, system_name_show, system_name_store); 251 252static 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 263static 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 281static struct kobj_attribute sysplex_name_attr = 282 __ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store); 283 284static 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 295static 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 313static struct kobj_attribute system_type_attr = 314 __ATTR(system_type, 0644, system_type_show, system_type_store); 315 316static 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 327static 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 350static struct kobj_attribute system_level_attr = 351 __ATTR(system_level, 0644, system_level_show, system_level_store); 352 353static 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 368static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store); 369 370static 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 379static struct attribute_group cpi_attr_group = { 380 .attrs = cpi_attrs, 381}; 382 383static struct kset *cpi_kset; 384 385int 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} 411EXPORT_SYMBOL(sclp_cpi_set_data); 412 413static 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);