aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2008-07-14 03:59:09 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:14 -0400
commita0443fbb467af5e5930b9b059b52190605f70059 (patch)
treef8e14901a87201539f1f6124c4c0fd018da712eb /arch/s390/kernel
parentfe1372306149d8c8a68d43765e7caea2377003b6 (diff)
[S390] Extra Kernel Parameters via VMPARM
Now it is possible to specify additional kernel parameters on the IPL command line using the IPL PARM option. If the Linux system is already running, the new reipl sysfs attribute 'parm' can be used to change kernel parameters for the next reboot. Examples: IPL C PARM dasd=1234 root=/dev/dasda1 IPL 1234 PARM savesys=mylnxnss echo "init=/bin/bash" > /sys/firmware/reipl/ccw/parm Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/early.c80
-rw-r--r--arch/s390/kernel/ipl.c444
-rw-r--r--arch/s390/kernel/setup.c17
3 files changed, 458 insertions, 83 deletions
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index b2226e41f067..e22473993dc9 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -14,6 +14,7 @@
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/pfn.h> 15#include <linux/pfn.h>
16#include <linux/uaccess.h> 16#include <linux/uaccess.h>
17#include <asm/ebcdic.h>
17#include <asm/ipl.h> 18#include <asm/ipl.h>
18#include <asm/lowcore.h> 19#include <asm/lowcore.h>
19#include <asm/processor.h> 20#include <asm/processor.h>
@@ -26,12 +27,40 @@
26/* 27/*
27 * Create a Kernel NSS if the SAVESYS= parameter is defined 28 * Create a Kernel NSS if the SAVESYS= parameter is defined
28 */ 29 */
29#define DEFSYS_CMD_SIZE 96 30#define DEFSYS_CMD_SIZE 128
30#define SAVESYS_CMD_SIZE 32 31#define SAVESYS_CMD_SIZE 32
31 32
32char kernel_nss_name[NSS_NAME_SIZE + 1]; 33char kernel_nss_name[NSS_NAME_SIZE + 1];
33 34
35static void __init setup_boot_command_line(void);
36
37
34#ifdef CONFIG_SHARED_KERNEL 38#ifdef CONFIG_SHARED_KERNEL
39int __init savesys_ipl_nss(char *cmd, const int cmdlen);
40
41asm(
42 " .section .init.text,\"ax\",@progbits\n"
43 " .align 4\n"
44 " .type savesys_ipl_nss, @function\n"
45 "savesys_ipl_nss:\n"
46#ifdef CONFIG_64BIT
47 " stmg 6,15,48(15)\n"
48 " lgr 14,3\n"
49 " sam31\n"
50 " diag 2,14,0x8\n"
51 " sam64\n"
52 " lgr 2,14\n"
53 " lmg 6,15,48(15)\n"
54#else
55 " stm 6,15,24(15)\n"
56 " lr 14,3\n"
57 " diag 2,14,0x8\n"
58 " lr 2,14\n"
59 " lm 6,15,24(15)\n"
60#endif
61 " br 14\n"
62 " .size savesys_ipl_nss, .-savesys_ipl_nss\n");
63
35static noinline __init void create_kernel_nss(void) 64static noinline __init void create_kernel_nss(void)
36{ 65{
37 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; 66 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
@@ -39,6 +68,7 @@ static noinline __init void create_kernel_nss(void)
39 unsigned int sinitrd_pfn, einitrd_pfn; 68 unsigned int sinitrd_pfn, einitrd_pfn;
40#endif 69#endif
41 int response; 70 int response;
71 size_t len;
42 char *savesys_ptr; 72 char *savesys_ptr;
43 char upper_command_line[COMMAND_LINE_SIZE]; 73 char upper_command_line[COMMAND_LINE_SIZE];
44 char defsys_cmd[DEFSYS_CMD_SIZE]; 74 char defsys_cmd[DEFSYS_CMD_SIZE];
@@ -49,8 +79,8 @@ static noinline __init void create_kernel_nss(void)
49 return; 79 return;
50 80
51 /* Convert COMMAND_LINE to upper case */ 81 /* Convert COMMAND_LINE to upper case */
52 for (i = 0; i < strlen(COMMAND_LINE); i++) 82 for (i = 0; i < strlen(boot_command_line); i++)
53 upper_command_line[i] = toupper(COMMAND_LINE[i]); 83 upper_command_line[i] = toupper(boot_command_line[i]);
54 84
55 savesys_ptr = strstr(upper_command_line, "SAVESYS="); 85 savesys_ptr = strstr(upper_command_line, "SAVESYS=");
56 86
@@ -83,7 +113,8 @@ static noinline __init void create_kernel_nss(void)
83 } 113 }
84#endif 114#endif
85 115
86 sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); 116 sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
117 defsys_cmd, min_size);
87 sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", 118 sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
88 kernel_nss_name, kernel_nss_name); 119 kernel_nss_name, kernel_nss_name);
89 120
@@ -94,13 +125,24 @@ static noinline __init void create_kernel_nss(void)
94 return; 125 return;
95 } 126 }
96 127
97 __cpcmd(savesys_cmd, NULL, 0, &response); 128 len = strlen(savesys_cmd);
129 ASCEBC(savesys_cmd, len);
130 response = savesys_ipl_nss(savesys_cmd, len);
98 131
99 if (response != strlen(savesys_cmd)) { 132 /* On success: response is equal to the command size,
133 * max SAVESYS_CMD_SIZE
134 * On error: response contains the numeric portion of cp error message.
135 * for SAVESYS it will be >= 263
136 */
137 if (response > SAVESYS_CMD_SIZE) {
100 kernel_nss_name[0] = '\0'; 138 kernel_nss_name[0] = '\0';
101 return; 139 return;
102 } 140 }
103 141
142 /* re-setup boot command line with new ipl vm parms */
143 ipl_update_parameters();
144 setup_boot_command_line();
145
104 ipl_flags = IPL_NSS_VALID; 146 ipl_flags = IPL_NSS_VALID;
105} 147}
106 148
@@ -397,6 +439,26 @@ static __init void rescue_initrd(void)
397#endif 439#endif
398} 440}
399 441
442/* Set up boot command line */
443static void __init setup_boot_command_line(void)
444{
445 char *parm = NULL;
446
447 /* copy arch command line */
448 strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
449 boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
450
451 /* append IPL PARM data to the boot command line */
452 if (MACHINE_IS_VM) {
453 parm = boot_command_line + strlen(boot_command_line);
454 *parm++ = ' ';
455 get_ipl_vmparm(parm);
456 if (parm[0] == '=')
457 memmove(boot_command_line, parm + 1, strlen(parm));
458 }
459}
460
461
400/* 462/*
401 * Save ipl parameters, clear bss memory, initialize storage keys 463 * Save ipl parameters, clear bss memory, initialize storage keys
402 * and create a kernel NSS at startup if the SAVESYS= parm is defined 464 * and create a kernel NSS at startup if the SAVESYS= parm is defined
@@ -411,10 +473,12 @@ void __init startup_init(void)
411 init_kernel_storage_key(); 473 init_kernel_storage_key();
412 lockdep_init(); 474 lockdep_init();
413 lockdep_off(); 475 lockdep_off();
414 detect_machine_type();
415 create_kernel_nss();
416 sort_main_extable(); 476 sort_main_extable();
417 setup_lowcore_early(); 477 setup_lowcore_early();
478 detect_machine_type();
479 ipl_update_parameters();
480 setup_boot_command_line();
481 create_kernel_nss();
418 detect_mvpg(); 482 detect_mvpg();
419 detect_ieee(); 483 detect_ieee();
420 detect_csp(); 484 detect_csp();
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 532542447d66..9f6dfd306abb 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -22,6 +22,7 @@
22#include <asm/ebcdic.h> 22#include <asm/ebcdic.h>
23#include <asm/reset.h> 23#include <asm/reset.h>
24#include <asm/sclp.h> 24#include <asm/sclp.h>
25#include <asm/setup.h>
25 26
26#define IPL_PARM_BLOCK_VERSION 0 27#define IPL_PARM_BLOCK_VERSION 0
27 28
@@ -121,6 +122,7 @@ enum ipl_method {
121 REIPL_METHOD_FCP_RO_VM, 122 REIPL_METHOD_FCP_RO_VM,
122 REIPL_METHOD_FCP_DUMP, 123 REIPL_METHOD_FCP_DUMP,
123 REIPL_METHOD_NSS, 124 REIPL_METHOD_NSS,
125 REIPL_METHOD_NSS_DIAG,
124 REIPL_METHOD_DEFAULT, 126 REIPL_METHOD_DEFAULT,
125}; 127};
126 128
@@ -134,14 +136,15 @@ enum dump_method {
134 136
135static int diag308_set_works = 0; 137static int diag308_set_works = 0;
136 138
139static struct ipl_parameter_block ipl_block;
140
137static int reipl_capabilities = IPL_TYPE_UNKNOWN; 141static int reipl_capabilities = IPL_TYPE_UNKNOWN;
138 142
139static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; 143static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
140static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; 144static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
141static struct ipl_parameter_block *reipl_block_fcp; 145static struct ipl_parameter_block *reipl_block_fcp;
142static struct ipl_parameter_block *reipl_block_ccw; 146static struct ipl_parameter_block *reipl_block_ccw;
143 147static struct ipl_parameter_block *reipl_block_nss;
144static char reipl_nss_name[NSS_NAME_SIZE + 1];
145 148
146static int dump_capabilities = DUMP_TYPE_NONE; 149static int dump_capabilities = DUMP_TYPE_NONE;
147static enum dump_type dump_type = DUMP_TYPE_NONE; 150static enum dump_type dump_type = DUMP_TYPE_NONE;
@@ -263,6 +266,56 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
263 266
264static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); 267static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
265 268
269/* VM IPL PARM routines */
270static void reipl_get_ascii_vmparm(char *dest,
271 const struct ipl_parameter_block *ipb)
272{
273 int i;
274 int len = 0;
275 char has_lowercase = 0;
276
277 if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
278 (ipb->ipl_info.ccw.vm_parm_len > 0)) {
279
280 len = ipb->ipl_info.ccw.vm_parm_len;
281 memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
282 /* If at least one character is lowercase, we assume mixed
283 * case; otherwise we convert everything to lowercase.
284 */
285 for (i = 0; i < len; i++)
286 if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
287 (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
288 (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
289 has_lowercase = 1;
290 break;
291 }
292 if (!has_lowercase)
293 EBC_TOLOWER(dest, len);
294 EBCASC(dest, len);
295 }
296 dest[len] = 0;
297}
298
299void get_ipl_vmparm(char *dest)
300{
301 if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
302 reipl_get_ascii_vmparm(dest, &ipl_block);
303 else
304 dest[0] = 0;
305}
306
307static ssize_t ipl_vm_parm_show(struct kobject *kobj,
308 struct kobj_attribute *attr, char *page)
309{
310 char parm[DIAG308_VMPARM_SIZE + 1] = {};
311
312 get_ipl_vmparm(parm);
313 return sprintf(page, "%s\n", parm);
314}
315
316static struct kobj_attribute sys_ipl_vm_parm_attr =
317 __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
318
266static ssize_t sys_ipl_device_show(struct kobject *kobj, 319static ssize_t sys_ipl_device_show(struct kobject *kobj,
267 struct kobj_attribute *attr, char *page) 320 struct kobj_attribute *attr, char *page)
268{ 321{
@@ -370,15 +423,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
370static struct kobj_attribute sys_ipl_ccw_loadparm_attr = 423static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
371 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); 424 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
372 425
373static struct attribute *ipl_ccw_attrs[] = { 426static struct attribute *ipl_ccw_attrs_vm[] = {
427 &sys_ipl_type_attr.attr,
428 &sys_ipl_device_attr.attr,
429 &sys_ipl_ccw_loadparm_attr.attr,
430 &sys_ipl_vm_parm_attr.attr,
431 NULL,
432};
433
434static struct attribute *ipl_ccw_attrs_lpar[] = {
374 &sys_ipl_type_attr.attr, 435 &sys_ipl_type_attr.attr,
375 &sys_ipl_device_attr.attr, 436 &sys_ipl_device_attr.attr,
376 &sys_ipl_ccw_loadparm_attr.attr, 437 &sys_ipl_ccw_loadparm_attr.attr,
377 NULL, 438 NULL,
378}; 439};
379 440
380static struct attribute_group ipl_ccw_attr_group = { 441static struct attribute_group ipl_ccw_attr_group_vm = {
381 .attrs = ipl_ccw_attrs, 442 .attrs = ipl_ccw_attrs_vm,
443};
444
445static struct attribute_group ipl_ccw_attr_group_lpar = {
446 .attrs = ipl_ccw_attrs_lpar
382}; 447};
383 448
384/* NSS ipl device attributes */ 449/* NSS ipl device attributes */
@@ -388,6 +453,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
388static struct attribute *ipl_nss_attrs[] = { 453static struct attribute *ipl_nss_attrs[] = {
389 &sys_ipl_type_attr.attr, 454 &sys_ipl_type_attr.attr,
390 &sys_ipl_nss_name_attr.attr, 455 &sys_ipl_nss_name_attr.attr,
456 &sys_ipl_ccw_loadparm_attr.attr,
457 &sys_ipl_vm_parm_attr.attr,
391 NULL, 458 NULL,
392}; 459};
393 460
@@ -450,7 +517,12 @@ static int __init ipl_init(void)
450 } 517 }
451 switch (ipl_info.type) { 518 switch (ipl_info.type) {
452 case IPL_TYPE_CCW: 519 case IPL_TYPE_CCW:
453 rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); 520 if (MACHINE_IS_VM)
521 rc = sysfs_create_group(&ipl_kset->kobj,
522 &ipl_ccw_attr_group_vm);
523 else
524 rc = sysfs_create_group(&ipl_kset->kobj,
525 &ipl_ccw_attr_group_lpar);
454 break; 526 break;
455 case IPL_TYPE_FCP: 527 case IPL_TYPE_FCP:
456 case IPL_TYPE_FCP_DUMP: 528 case IPL_TYPE_FCP_DUMP:
@@ -481,6 +553,83 @@ static struct shutdown_action __refdata ipl_action = {
481 * reipl shutdown action: Reboot Linux on shutdown. 553 * reipl shutdown action: Reboot Linux on shutdown.
482 */ 554 */
483 555
556/* VM IPL PARM attributes */
557static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
558 char *page)
559{
560 char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
561
562 reipl_get_ascii_vmparm(vmparm, ipb);
563 return sprintf(page, "%s\n", vmparm);
564}
565
566static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
567 size_t vmparm_max,
568 const char *buf, size_t len)
569{
570 int i, ip_len;
571
572 /* ignore trailing newline */
573 ip_len = len;
574 if ((len > 0) && (buf[len - 1] == '\n'))
575 ip_len--;
576
577 if (ip_len > vmparm_max)
578 return -EINVAL;
579
580 /* parm is used to store kernel options, check for common chars */
581 for (i = 0; i < ip_len; i++)
582 if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
583 return -EINVAL;
584
585 memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
586 ipb->ipl_info.ccw.vm_parm_len = ip_len;
587 if (ip_len > 0) {
588 ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
589 memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len);
590 ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len);
591 } else {
592 ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID;
593 }
594
595 return len;
596}
597
598/* NSS wrapper */
599static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
600 struct kobj_attribute *attr, char *page)
601{
602 return reipl_generic_vmparm_show(reipl_block_nss, page);
603}
604
605static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
606 struct kobj_attribute *attr,
607 const char *buf, size_t len)
608{
609 return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
610}
611
612/* CCW wrapper */
613static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
614 struct kobj_attribute *attr, char *page)
615{
616 return reipl_generic_vmparm_show(reipl_block_ccw, page);
617}
618
619static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
620 struct kobj_attribute *attr,
621 const char *buf, size_t len)
622{
623 return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
624}
625
626static struct kobj_attribute sys_reipl_nss_vmparm_attr =
627 __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
628 reipl_nss_vmparm_store);
629static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
630 __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
631 reipl_ccw_vmparm_store);
632
484/* FCP reipl device attributes */ 633/* FCP reipl device attributes */
485 634
486DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", 635DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
@@ -513,27 +662,26 @@ static struct attribute_group reipl_fcp_attr_group = {
513DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 662DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
514 reipl_block_ccw->ipl_info.ccw.devno); 663 reipl_block_ccw->ipl_info.ccw.devno);
515 664
516static void reipl_get_ascii_loadparm(char *loadparm) 665static void reipl_get_ascii_loadparm(char *loadparm,
666 struct ipl_parameter_block *ibp)
517{ 667{
518 memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, 668 memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN);
519 LOADPARM_LEN);
520 EBCASC(loadparm, LOADPARM_LEN); 669 EBCASC(loadparm, LOADPARM_LEN);
521 loadparm[LOADPARM_LEN] = 0; 670 loadparm[LOADPARM_LEN] = 0;
522 strstrip(loadparm); 671 strstrip(loadparm);
523} 672}
524 673
525static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, 674static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
526 struct kobj_attribute *attr, char *page) 675 char *page)
527{ 676{
528 char buf[LOADPARM_LEN + 1]; 677 char buf[LOADPARM_LEN + 1];
529 678
530 reipl_get_ascii_loadparm(buf); 679 reipl_get_ascii_loadparm(buf, ipb);
531 return sprintf(page, "%s\n", buf); 680 return sprintf(page, "%s\n", buf);
532} 681}
533 682
534static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, 683static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
535 struct kobj_attribute *attr, 684 const char *buf, size_t len)
536 const char *buf, size_t len)
537{ 685{
538 int i, lp_len; 686 int i, lp_len;
539 687
@@ -552,35 +700,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
552 return -EINVAL; 700 return -EINVAL;
553 } 701 }
554 /* initialize loadparm with blanks */ 702 /* initialize loadparm with blanks */
555 memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); 703 memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN);
556 /* copy and convert to ebcdic */ 704 /* copy and convert to ebcdic */
557 memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); 705 memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len);
558 ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); 706 ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN);
559 return len; 707 return len;
560} 708}
561 709
710/* NSS wrapper */
711static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
712 struct kobj_attribute *attr, char *page)
713{
714 return reipl_generic_loadparm_show(reipl_block_nss, page);
715}
716
717static ssize_t reipl_nss_loadparm_store(struct kobject *kobj,
718 struct kobj_attribute *attr,
719 const char *buf, size_t len)
720{
721 return reipl_generic_loadparm_store(reipl_block_nss, buf, len);
722}
723
724/* CCW wrapper */
725static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
726 struct kobj_attribute *attr, char *page)
727{
728 return reipl_generic_loadparm_show(reipl_block_ccw, page);
729}
730
731static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
732 struct kobj_attribute *attr,
733 const char *buf, size_t len)
734{
735 return reipl_generic_loadparm_store(reipl_block_ccw, buf, len);
736}
737
562static struct kobj_attribute sys_reipl_ccw_loadparm_attr = 738static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
563 __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, 739 __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
564 reipl_ccw_loadparm_store); 740 reipl_ccw_loadparm_store);
741
742static struct attribute *reipl_ccw_attrs_vm[] = {
743 &sys_reipl_ccw_device_attr.attr,
744 &sys_reipl_ccw_loadparm_attr.attr,
745 &sys_reipl_ccw_vmparm_attr.attr,
746 NULL,
747};
565 748
566static struct attribute *reipl_ccw_attrs[] = { 749static struct attribute *reipl_ccw_attrs_lpar[] = {
567 &sys_reipl_ccw_device_attr.attr, 750 &sys_reipl_ccw_device_attr.attr,
568 &sys_reipl_ccw_loadparm_attr.attr, 751 &sys_reipl_ccw_loadparm_attr.attr,
569 NULL, 752 NULL,
570}; 753};
571 754
572static struct attribute_group reipl_ccw_attr_group = { 755static struct attribute_group reipl_ccw_attr_group_vm = {
573 .name = IPL_CCW_STR, 756 .name = IPL_CCW_STR,
574 .attrs = reipl_ccw_attrs, 757 .attrs = reipl_ccw_attrs_vm,
758};
759
760static struct attribute_group reipl_ccw_attr_group_lpar = {
761 .name = IPL_CCW_STR,
762 .attrs = reipl_ccw_attrs_lpar,
575}; 763};
576 764
577 765
578/* NSS reipl device attributes */ 766/* NSS reipl device attributes */
767static void reipl_get_ascii_nss_name(char *dst,
768 struct ipl_parameter_block *ipb)
769{
770 memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
771 EBCASC(dst, NSS_NAME_SIZE);
772 dst[NSS_NAME_SIZE] = 0;
773}
774
775static ssize_t reipl_nss_name_show(struct kobject *kobj,
776 struct kobj_attribute *attr, char *page)
777{
778 char nss_name[NSS_NAME_SIZE + 1] = {};
779
780 reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
781 return sprintf(page, "%s\n", nss_name);
782}
783
784static ssize_t reipl_nss_name_store(struct kobject *kobj,
785 struct kobj_attribute *attr,
786 const char *buf, size_t len)
787{
788 int nss_len;
789
790 /* ignore trailing newline */
791 nss_len = len;
792 if ((len > 0) && (buf[len - 1] == '\n'))
793 nss_len--;
579 794
580DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); 795 if (nss_len > NSS_NAME_SIZE)
796 return -EINVAL;
797
798 memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE);
799 if (nss_len > 0) {
800 reipl_block_nss->ipl_info.ccw.vm_flags |=
801 DIAG308_VM_FLAGS_NSS_VALID;
802 memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len);
803 ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
804 EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
805 } else {
806 reipl_block_nss->ipl_info.ccw.vm_flags &=
807 ~DIAG308_VM_FLAGS_NSS_VALID;
808 }
809
810 return len;
811}
812
813static struct kobj_attribute sys_reipl_nss_name_attr =
814 __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
815 reipl_nss_name_store);
816
817static struct kobj_attribute sys_reipl_nss_loadparm_attr =
818 __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
819 reipl_nss_loadparm_store);
581 820
582static struct attribute *reipl_nss_attrs[] = { 821static struct attribute *reipl_nss_attrs[] = {
583 &sys_reipl_nss_name_attr.attr, 822 &sys_reipl_nss_name_attr.attr,
823 &sys_reipl_nss_loadparm_attr.attr,
824 &sys_reipl_nss_vmparm_attr.attr,
584 NULL, 825 NULL,
585}; 826};
586 827
@@ -617,7 +858,10 @@ static int reipl_set_type(enum ipl_type type)
617 reipl_method = REIPL_METHOD_FCP_DUMP; 858 reipl_method = REIPL_METHOD_FCP_DUMP;
618 break; 859 break;
619 case IPL_TYPE_NSS: 860 case IPL_TYPE_NSS:
620 reipl_method = REIPL_METHOD_NSS; 861 if (diag308_set_works)
862 reipl_method = REIPL_METHOD_NSS_DIAG;
863 else
864 reipl_method = REIPL_METHOD_NSS;
621 break; 865 break;
622 case IPL_TYPE_UNKNOWN: 866 case IPL_TYPE_UNKNOWN:
623 reipl_method = REIPL_METHOD_DEFAULT; 867 reipl_method = REIPL_METHOD_DEFAULT;
@@ -655,11 +899,38 @@ static struct kobj_attribute reipl_type_attr =
655 899
656static struct kset *reipl_kset; 900static struct kset *reipl_kset;
657 901
902static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
903 const enum ipl_method m)
904{
905 char loadparm[LOADPARM_LEN + 1] = {};
906 char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
907 char nss_name[NSS_NAME_SIZE + 1] = {};
908 size_t pos = 0;
909
910 reipl_get_ascii_loadparm(loadparm, ipb);
911 reipl_get_ascii_nss_name(nss_name, ipb);
912 reipl_get_ascii_vmparm(vmparm, ipb);
913
914 switch (m) {
915 case REIPL_METHOD_CCW_VM:
916 pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno);
917 break;
918 case REIPL_METHOD_NSS:
919 pos = sprintf(dst, "IPL %s", nss_name);
920 break;
921 default:
922 break;
923 }
924 if (strlen(loadparm) > 0)
925 pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm);
926 if (strlen(vmparm) > 0)
927 sprintf(dst + pos, " PARM %s", vmparm);
928}
929
658static void reipl_run(struct shutdown_trigger *trigger) 930static void reipl_run(struct shutdown_trigger *trigger)
659{ 931{
660 struct ccw_dev_id devid; 932 struct ccw_dev_id devid;
661 static char buf[100]; 933 static char buf[128];
662 char loadparm[LOADPARM_LEN + 1];
663 934
664 switch (reipl_method) { 935 switch (reipl_method) {
665 case REIPL_METHOD_CCW_CIO: 936 case REIPL_METHOD_CCW_CIO:
@@ -668,13 +939,7 @@ static void reipl_run(struct shutdown_trigger *trigger)
668 reipl_ccw_dev(&devid); 939 reipl_ccw_dev(&devid);
669 break; 940 break;
670 case REIPL_METHOD_CCW_VM: 941 case REIPL_METHOD_CCW_VM:
671 reipl_get_ascii_loadparm(loadparm); 942 get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM);
672 if (strlen(loadparm) == 0)
673 sprintf(buf, "IPL %X CLEAR",
674 reipl_block_ccw->ipl_info.ccw.devno);
675 else
676 sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
677 reipl_block_ccw->ipl_info.ccw.devno, loadparm);
678 __cpcmd(buf, NULL, 0, NULL); 943 __cpcmd(buf, NULL, 0, NULL);
679 break; 944 break;
680 case REIPL_METHOD_CCW_DIAG: 945 case REIPL_METHOD_CCW_DIAG:
@@ -691,8 +956,12 @@ static void reipl_run(struct shutdown_trigger *trigger)
691 case REIPL_METHOD_FCP_RO_VM: 956 case REIPL_METHOD_FCP_RO_VM:
692 __cpcmd("IPL", NULL, 0, NULL); 957 __cpcmd("IPL", NULL, 0, NULL);
693 break; 958 break;
959 case REIPL_METHOD_NSS_DIAG:
960 diag308(DIAG308_SET, reipl_block_nss);
961 diag308(DIAG308_IPL, NULL);
962 break;
694 case REIPL_METHOD_NSS: 963 case REIPL_METHOD_NSS:
695 sprintf(buf, "IPL %s", reipl_nss_name); 964 get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS);
696 __cpcmd(buf, NULL, 0, NULL); 965 __cpcmd(buf, NULL, 0, NULL);
697 break; 966 break;
698 case REIPL_METHOD_DEFAULT: 967 case REIPL_METHOD_DEFAULT:
@@ -707,16 +976,36 @@ static void reipl_run(struct shutdown_trigger *trigger)
707 disabled_wait((unsigned long) __builtin_return_address(0)); 976 disabled_wait((unsigned long) __builtin_return_address(0));
708} 977}
709 978
710static void __init reipl_probe(void) 979static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
711{ 980{
712 void *buffer; 981 ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
982 ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
983 ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
984 ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW;
985}
713 986
714 buffer = (void *) get_zeroed_page(GFP_KERNEL); 987static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
715 if (!buffer) 988{
716 return; 989 /* LOADPARM */
717 if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) 990 /* check if read scp info worked and set loadparm */
718 diag308_set_works = 1; 991 if (sclp_ipl_info.is_valid)
719 free_page((unsigned long)buffer); 992 memcpy(ipb->ipl_info.ccw.load_parm,
993 &sclp_ipl_info.loadparm, LOADPARM_LEN);
994 else
995 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
996 memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN);
997 ipb->hdr.flags = DIAG308_FLAGS_LP_VALID;
998
999 /* VM PARM */
1000 if (MACHINE_IS_VM && diag308_set_works &&
1001 (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) {
1002
1003 ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
1004 ipb->ipl_info.ccw.vm_parm_len =
1005 ipl_block.ipl_info.ccw.vm_parm_len;
1006 memcpy(ipb->ipl_info.ccw.vm_parm,
1007 ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE);
1008 }
720} 1009}
721 1010
722static int __init reipl_nss_init(void) 1011static int __init reipl_nss_init(void)
@@ -725,10 +1014,31 @@ static int __init reipl_nss_init(void)
725 1014
726 if (!MACHINE_IS_VM) 1015 if (!MACHINE_IS_VM)
727 return 0; 1016 return 0;
1017
1018 reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
1019 if (!reipl_block_nss)
1020 return -ENOMEM;
1021
1022 if (!diag308_set_works)
1023 sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO;
1024
728 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); 1025 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
729 if (rc) 1026 if (rc)
730 return rc; 1027 return rc;
731 strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); 1028
1029 reipl_block_ccw_init(reipl_block_nss);
1030 if (ipl_info.type == IPL_TYPE_NSS) {
1031 memset(reipl_block_nss->ipl_info.ccw.nss_name,
1032 ' ', NSS_NAME_SIZE);
1033 memcpy(reipl_block_nss->ipl_info.ccw.nss_name,
1034 kernel_nss_name, strlen(kernel_nss_name));
1035 ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
1036 reipl_block_nss->ipl_info.ccw.vm_flags |=
1037 DIAG308_VM_FLAGS_NSS_VALID;
1038
1039 reipl_block_ccw_fill_parms(reipl_block_nss);
1040 }
1041
732 reipl_capabilities |= IPL_TYPE_NSS; 1042 reipl_capabilities |= IPL_TYPE_NSS;
733 return 0; 1043 return 0;
734} 1044}
@@ -740,28 +1050,27 @@ static int __init reipl_ccw_init(void)
740 reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); 1050 reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
741 if (!reipl_block_ccw) 1051 if (!reipl_block_ccw)
742 return -ENOMEM; 1052 return -ENOMEM;
743 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); 1053
744 if (rc) { 1054 if (MACHINE_IS_VM) {
745 free_page((unsigned long)reipl_block_ccw); 1055 if (!diag308_set_works)
746 return rc; 1056 sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO;
1057 rc = sysfs_create_group(&reipl_kset->kobj,
1058 &reipl_ccw_attr_group_vm);
1059 } else {
1060 if(!diag308_set_works)
1061 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
1062 rc = sysfs_create_group(&reipl_kset->kobj,
1063 &reipl_ccw_attr_group_lpar);
747 } 1064 }
748 reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; 1065 if (rc)
749 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; 1066 return rc;
750 reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; 1067
751 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; 1068 reipl_block_ccw_init(reipl_block_ccw);
752 reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID; 1069 if (ipl_info.type == IPL_TYPE_CCW) {
753 /* check if read scp info worked and set loadparm */
754 if (sclp_ipl_info.is_valid)
755 memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
756 &sclp_ipl_info.loadparm, LOADPARM_LEN);
757 else
758 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
759 memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
760 LOADPARM_LEN);
761 if (!MACHINE_IS_VM && !diag308_set_works)
762 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
763 if (ipl_info.type == IPL_TYPE_CCW)
764 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; 1070 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
1071 reipl_block_ccw_fill_parms(reipl_block_ccw);
1072 }
1073
765 reipl_capabilities |= IPL_TYPE_CCW; 1074 reipl_capabilities |= IPL_TYPE_CCW;
766 return 0; 1075 return 0;
767} 1076}
@@ -1298,7 +1607,6 @@ static void __init shutdown_actions_init(void)
1298 1607
1299static int __init s390_ipl_init(void) 1608static int __init s390_ipl_init(void)
1300{ 1609{
1301 reipl_probe();
1302 sclp_get_ipl_info(&sclp_ipl_info); 1610 sclp_get_ipl_info(&sclp_ipl_info);
1303 shutdown_actions_init(); 1611 shutdown_actions_init();
1304 shutdown_triggers_init(); 1612 shutdown_triggers_init();
@@ -1405,6 +1713,12 @@ void __init setup_ipl(void)
1405 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 1713 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
1406} 1714}
1407 1715
1716void __init ipl_update_parameters(void)
1717{
1718 if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK)
1719 diag308_set_works = 1;
1720}
1721
1408void __init ipl_save_parameters(void) 1722void __init ipl_save_parameters(void)
1409{ 1723{
1410 struct cio_iplinfo iplinfo; 1724 struct cio_iplinfo iplinfo;
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index b91caadf974d..e3b4cdbae34e 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -221,18 +221,17 @@ static void __init conmode_default(void)
221#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) 221#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
222static void __init setup_zfcpdump(unsigned int console_devno) 222static void __init setup_zfcpdump(unsigned int console_devno)
223{ 223{
224 static char str[64]; 224 static char str[41];
225 225
226 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 226 if (ipl_info.type != IPL_TYPE_FCP_DUMP)
227 return; 227 return;
228 if (console_devno != -1) 228 if (console_devno != -1)
229 sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x", 229 sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x",
230 ipl_info.data.fcp.dev_id.devno, console_devno); 230 ipl_info.data.fcp.dev_id.devno, console_devno);
231 else 231 else
232 sprintf(str, "cio_ignore=all,!0.0.%04x", 232 sprintf(str, " cio_ignore=all,!0.0.%04x",
233 ipl_info.data.fcp.dev_id.devno); 233 ipl_info.data.fcp.dev_id.devno);
234 strcat(COMMAND_LINE, " "); 234 strcat(boot_command_line, str);
235 strcat(COMMAND_LINE, str);
236 console_loglevel = 2; 235 console_loglevel = 2;
237} 236}
238#else 237#else
@@ -778,11 +777,9 @@ setup_arch(char **cmdline_p)
778 printk("We are running native (64 bit mode)\n"); 777 printk("We are running native (64 bit mode)\n");
779#endif /* CONFIG_64BIT */ 778#endif /* CONFIG_64BIT */
780 779
781 /* Save unparsed command line copy for /proc/cmdline */ 780 /* Have one command line that is parsed and saved in /proc/cmdline */
782 strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); 781 /* boot_command_line has been already set up in early.c */
783 782 *cmdline_p = boot_command_line;
784 *cmdline_p = COMMAND_LINE;
785 *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0';
786 783
787 ROOT_DEV = Root_RAM0; 784 ROOT_DEV = Root_RAM0;
788 785