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