Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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