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