aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c462
1 files changed, 383 insertions, 79 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 532542447d66..54b2779b5e2f 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -14,6 +14,7 @@
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/reboot.h> 15#include <linux/reboot.h>
16#include <linux/ctype.h> 16#include <linux/ctype.h>
17#include <linux/fs.h>
17#include <asm/ipl.h> 18#include <asm/ipl.h>
18#include <asm/smp.h> 19#include <asm/smp.h>
19#include <asm/setup.h> 20#include <asm/setup.h>
@@ -22,6 +23,7 @@
22#include <asm/ebcdic.h> 23#include <asm/ebcdic.h>
23#include <asm/reset.h> 24#include <asm/reset.h>
24#include <asm/sclp.h> 25#include <asm/sclp.h>
26#include <asm/setup.h>
25 27
26#define IPL_PARM_BLOCK_VERSION 0 28#define IPL_PARM_BLOCK_VERSION 0
27 29
@@ -121,6 +123,7 @@ enum ipl_method {
121 REIPL_METHOD_FCP_RO_VM, 123 REIPL_METHOD_FCP_RO_VM,
122 REIPL_METHOD_FCP_DUMP, 124 REIPL_METHOD_FCP_DUMP,
123 REIPL_METHOD_NSS, 125 REIPL_METHOD_NSS,
126 REIPL_METHOD_NSS_DIAG,
124 REIPL_METHOD_DEFAULT, 127 REIPL_METHOD_DEFAULT,
125}; 128};
126 129
@@ -134,14 +137,15 @@ enum dump_method {
134 137
135static int diag308_set_works = 0; 138static int diag308_set_works = 0;
136 139
140static struct ipl_parameter_block ipl_block;
141
137static int reipl_capabilities = IPL_TYPE_UNKNOWN; 142static int reipl_capabilities = IPL_TYPE_UNKNOWN;
138 143
139static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; 144static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
140static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; 145static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
141static struct ipl_parameter_block *reipl_block_fcp; 146static struct ipl_parameter_block *reipl_block_fcp;
142static struct ipl_parameter_block *reipl_block_ccw; 147static struct ipl_parameter_block *reipl_block_ccw;
143 148static struct ipl_parameter_block *reipl_block_nss;
144static char reipl_nss_name[NSS_NAME_SIZE + 1];
145 149
146static int dump_capabilities = DUMP_TYPE_NONE; 150static int dump_capabilities = DUMP_TYPE_NONE;
147static enum dump_type dump_type = DUMP_TYPE_NONE; 151static enum dump_type dump_type = DUMP_TYPE_NONE;
@@ -263,6 +267,56 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
263 267
264static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); 268static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
265 269
270/* VM IPL PARM routines */
271static void reipl_get_ascii_vmparm(char *dest,
272 const struct ipl_parameter_block *ipb)
273{
274 int i;
275 int len = 0;
276 char has_lowercase = 0;
277
278 if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
279 (ipb->ipl_info.ccw.vm_parm_len > 0)) {
280
281 len = ipb->ipl_info.ccw.vm_parm_len;
282 memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
283 /* If at least one character is lowercase, we assume mixed
284 * case; otherwise we convert everything to lowercase.
285 */
286 for (i = 0; i < len; i++)
287 if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
288 (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
289 (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
290 has_lowercase = 1;
291 break;
292 }
293 if (!has_lowercase)
294 EBC_TOLOWER(dest, len);
295 EBCASC(dest, len);
296 }
297 dest[len] = 0;
298}
299
300void get_ipl_vmparm(char *dest)
301{
302 if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
303 reipl_get_ascii_vmparm(dest, &ipl_block);
304 else
305 dest[0] = 0;
306}
307
308static ssize_t ipl_vm_parm_show(struct kobject *kobj,
309 struct kobj_attribute *attr, char *page)
310{
311 char parm[DIAG308_VMPARM_SIZE + 1] = {};
312
313 get_ipl_vmparm(parm);
314 return sprintf(page, "%s\n", parm);
315}
316
317static struct kobj_attribute sys_ipl_vm_parm_attr =
318 __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
319
266static ssize_t sys_ipl_device_show(struct kobject *kobj, 320static ssize_t sys_ipl_device_show(struct kobject *kobj,
267 struct kobj_attribute *attr, char *page) 321 struct kobj_attribute *attr, char *page)
268{ 322{
@@ -285,14 +339,8 @@ static struct kobj_attribute sys_ipl_device_attr =
285static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, 339static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
286 char *buf, loff_t off, size_t count) 340 char *buf, loff_t off, size_t count)
287{ 341{
288 unsigned int size = IPL_PARMBLOCK_SIZE; 342 return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START,
289 343 IPL_PARMBLOCK_SIZE);
290 if (off > size)
291 return 0;
292 if (off + count > size)
293 count = size - off;
294 memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
295 return count;
296} 344}
297 345
298static struct bin_attribute ipl_parameter_attr = { 346static struct bin_attribute ipl_parameter_attr = {
@@ -310,12 +358,7 @@ static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *att
310 unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; 358 unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
311 void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; 359 void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
312 360
313 if (off > size) 361 return memory_read_from_buffer(buf, count, &off, scp_data, size);
314 return 0;
315 if (off + count > size)
316 count = size - off;
317 memcpy(buf, scp_data + off, count);
318 return count;
319} 362}
320 363
321static struct bin_attribute ipl_scp_data_attr = { 364static struct bin_attribute ipl_scp_data_attr = {
@@ -370,15 +413,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
370static struct kobj_attribute sys_ipl_ccw_loadparm_attr = 413static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
371 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); 414 __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
372 415
373static struct attribute *ipl_ccw_attrs[] = { 416static struct attribute *ipl_ccw_attrs_vm[] = {
374 &sys_ipl_type_attr.attr, 417 &sys_ipl_type_attr.attr,
375 &sys_ipl_device_attr.attr, 418 &sys_ipl_device_attr.attr,
376 &sys_ipl_ccw_loadparm_attr.attr, 419 &sys_ipl_ccw_loadparm_attr.attr,
420 &sys_ipl_vm_parm_attr.attr,
377 NULL, 421 NULL,
378}; 422};
379 423
380static struct attribute_group ipl_ccw_attr_group = { 424static struct attribute *ipl_ccw_attrs_lpar[] = {
381 .attrs = ipl_ccw_attrs, 425 &sys_ipl_type_attr.attr,
426 &sys_ipl_device_attr.attr,
427 &sys_ipl_ccw_loadparm_attr.attr,
428 NULL,
429};
430
431static struct attribute_group ipl_ccw_attr_group_vm = {
432 .attrs = ipl_ccw_attrs_vm,
433};
434
435static struct attribute_group ipl_ccw_attr_group_lpar = {
436 .attrs = ipl_ccw_attrs_lpar
382}; 437};
383 438
384/* NSS ipl device attributes */ 439/* NSS ipl device attributes */
@@ -388,6 +443,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
388static struct attribute *ipl_nss_attrs[] = { 443static struct attribute *ipl_nss_attrs[] = {
389 &sys_ipl_type_attr.attr, 444 &sys_ipl_type_attr.attr,
390 &sys_ipl_nss_name_attr.attr, 445 &sys_ipl_nss_name_attr.attr,
446 &sys_ipl_ccw_loadparm_attr.attr,
447 &sys_ipl_vm_parm_attr.attr,
391 NULL, 448 NULL,
392}; 449};
393 450
@@ -450,7 +507,12 @@ static int __init ipl_init(void)
450 } 507 }
451 switch (ipl_info.type) { 508 switch (ipl_info.type) {
452 case IPL_TYPE_CCW: 509 case IPL_TYPE_CCW:
453 rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); 510 if (MACHINE_IS_VM)
511 rc = sysfs_create_group(&ipl_kset->kobj,
512 &ipl_ccw_attr_group_vm);
513 else
514 rc = sysfs_create_group(&ipl_kset->kobj,
515 &ipl_ccw_attr_group_lpar);
454 break; 516 break;
455 case IPL_TYPE_FCP: 517 case IPL_TYPE_FCP:
456 case IPL_TYPE_FCP_DUMP: 518 case IPL_TYPE_FCP_DUMP:
@@ -481,6 +543,83 @@ static struct shutdown_action __refdata ipl_action = {
481 * reipl shutdown action: Reboot Linux on shutdown. 543 * reipl shutdown action: Reboot Linux on shutdown.
482 */ 544 */
483 545
546/* VM IPL PARM attributes */
547static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
548 char *page)
549{
550 char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
551
552 reipl_get_ascii_vmparm(vmparm, ipb);
553 return sprintf(page, "%s\n", vmparm);
554}
555
556static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
557 size_t vmparm_max,
558 const char *buf, size_t len)
559{
560 int i, ip_len;
561
562 /* ignore trailing newline */
563 ip_len = len;
564 if ((len > 0) && (buf[len - 1] == '\n'))
565 ip_len--;
566
567 if (ip_len > vmparm_max)
568 return -EINVAL;
569
570 /* parm is used to store kernel options, check for common chars */
571 for (i = 0; i < ip_len; i++)
572 if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
573 return -EINVAL;
574
575 memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
576 ipb->ipl_info.ccw.vm_parm_len = ip_len;
577 if (ip_len > 0) {
578 ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
579 memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len);
580 ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len);
581 } else {
582 ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID;
583 }
584
585 return len;
586}
587
588/* NSS wrapper */
589static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
590 struct kobj_attribute *attr, char *page)
591{
592 return reipl_generic_vmparm_show(reipl_block_nss, page);
593}
594
595static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
596 struct kobj_attribute *attr,
597 const char *buf, size_t len)
598{
599 return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
600}
601
602/* CCW wrapper */
603static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
604 struct kobj_attribute *attr, char *page)
605{
606 return reipl_generic_vmparm_show(reipl_block_ccw, page);
607}
608
609static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
610 struct kobj_attribute *attr,
611 const char *buf, size_t len)
612{
613 return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
614}
615
616static struct kobj_attribute sys_reipl_nss_vmparm_attr =
617 __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
618 reipl_nss_vmparm_store);
619static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
620 __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
621 reipl_ccw_vmparm_store);
622
484/* FCP reipl device attributes */ 623/* FCP reipl device attributes */
485 624
486DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", 625DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
@@ -513,27 +652,26 @@ static struct attribute_group reipl_fcp_attr_group = {
513DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 652DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
514 reipl_block_ccw->ipl_info.ccw.devno); 653 reipl_block_ccw->ipl_info.ccw.devno);
515 654
516static void reipl_get_ascii_loadparm(char *loadparm) 655static void reipl_get_ascii_loadparm(char *loadparm,
656 struct ipl_parameter_block *ibp)
517{ 657{
518 memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, 658 memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN);
519 LOADPARM_LEN);
520 EBCASC(loadparm, LOADPARM_LEN); 659 EBCASC(loadparm, LOADPARM_LEN);
521 loadparm[LOADPARM_LEN] = 0; 660 loadparm[LOADPARM_LEN] = 0;
522 strstrip(loadparm); 661 strstrip(loadparm);
523} 662}
524 663
525static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, 664static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
526 struct kobj_attribute *attr, char *page) 665 char *page)
527{ 666{
528 char buf[LOADPARM_LEN + 1]; 667 char buf[LOADPARM_LEN + 1];
529 668
530 reipl_get_ascii_loadparm(buf); 669 reipl_get_ascii_loadparm(buf, ipb);
531 return sprintf(page, "%s\n", buf); 670 return sprintf(page, "%s\n", buf);
532} 671}
533 672
534static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, 673static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
535 struct kobj_attribute *attr, 674 const char *buf, size_t len)
536 const char *buf, size_t len)
537{ 675{
538 int i, lp_len; 676 int i, lp_len;
539 677
@@ -552,35 +690,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
552 return -EINVAL; 690 return -EINVAL;
553 } 691 }
554 /* initialize loadparm with blanks */ 692 /* initialize loadparm with blanks */
555 memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); 693 memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN);
556 /* copy and convert to ebcdic */ 694 /* copy and convert to ebcdic */
557 memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); 695 memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len);
558 ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); 696 ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN);
559 return len; 697 return len;
560} 698}
561 699
700/* NSS wrapper */
701static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
702 struct kobj_attribute *attr, char *page)
703{
704 return reipl_generic_loadparm_show(reipl_block_nss, page);
705}
706
707static ssize_t reipl_nss_loadparm_store(struct kobject *kobj,
708 struct kobj_attribute *attr,
709 const char *buf, size_t len)
710{
711 return reipl_generic_loadparm_store(reipl_block_nss, buf, len);
712}
713
714/* CCW wrapper */
715static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
716 struct kobj_attribute *attr, char *page)
717{
718 return reipl_generic_loadparm_show(reipl_block_ccw, page);
719}
720
721static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
722 struct kobj_attribute *attr,
723 const char *buf, size_t len)
724{
725 return reipl_generic_loadparm_store(reipl_block_ccw, buf, len);
726}
727
562static struct kobj_attribute sys_reipl_ccw_loadparm_attr = 728static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
563 __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, 729 __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
564 reipl_ccw_loadparm_store); 730 reipl_ccw_loadparm_store);
565 731
566static struct attribute *reipl_ccw_attrs[] = { 732static struct attribute *reipl_ccw_attrs_vm[] = {
567 &sys_reipl_ccw_device_attr.attr, 733 &sys_reipl_ccw_device_attr.attr,
568 &sys_reipl_ccw_loadparm_attr.attr, 734 &sys_reipl_ccw_loadparm_attr.attr,
735 &sys_reipl_ccw_vmparm_attr.attr,
569 NULL, 736 NULL,
570}; 737};
571 738
572static struct attribute_group reipl_ccw_attr_group = { 739static struct attribute *reipl_ccw_attrs_lpar[] = {
740 &sys_reipl_ccw_device_attr.attr,
741 &sys_reipl_ccw_loadparm_attr.attr,
742 NULL,
743};
744
745static struct attribute_group reipl_ccw_attr_group_vm = {
746 .name = IPL_CCW_STR,
747 .attrs = reipl_ccw_attrs_vm,
748};
749
750static struct attribute_group reipl_ccw_attr_group_lpar = {
573 .name = IPL_CCW_STR, 751 .name = IPL_CCW_STR,
574 .attrs = reipl_ccw_attrs, 752 .attrs = reipl_ccw_attrs_lpar,
575}; 753};
576 754
577 755
578/* NSS reipl device attributes */ 756/* NSS reipl device attributes */
757static void reipl_get_ascii_nss_name(char *dst,
758 struct ipl_parameter_block *ipb)
759{
760 memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
761 EBCASC(dst, NSS_NAME_SIZE);
762 dst[NSS_NAME_SIZE] = 0;
763}
764
765static ssize_t reipl_nss_name_show(struct kobject *kobj,
766 struct kobj_attribute *attr, char *page)
767{
768 char nss_name[NSS_NAME_SIZE + 1] = {};
579 769
580DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); 770 reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
771 return sprintf(page, "%s\n", nss_name);
772}
773
774static ssize_t reipl_nss_name_store(struct kobject *kobj,
775 struct kobj_attribute *attr,
776 const char *buf, size_t len)
777{
778 int nss_len;
779
780 /* ignore trailing newline */
781 nss_len = len;
782 if ((len > 0) && (buf[len - 1] == '\n'))
783 nss_len--;
784
785 if (nss_len > NSS_NAME_SIZE)
786 return -EINVAL;
787
788 memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE);
789 if (nss_len > 0) {
790 reipl_block_nss->ipl_info.ccw.vm_flags |=
791 DIAG308_VM_FLAGS_NSS_VALID;
792 memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len);
793 ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
794 EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
795 } else {
796 reipl_block_nss->ipl_info.ccw.vm_flags &=
797 ~DIAG308_VM_FLAGS_NSS_VALID;
798 }
799
800 return len;
801}
802
803static struct kobj_attribute sys_reipl_nss_name_attr =
804 __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
805 reipl_nss_name_store);
806
807static struct kobj_attribute sys_reipl_nss_loadparm_attr =
808 __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
809 reipl_nss_loadparm_store);
581 810
582static struct attribute *reipl_nss_attrs[] = { 811static struct attribute *reipl_nss_attrs[] = {
583 &sys_reipl_nss_name_attr.attr, 812 &sys_reipl_nss_name_attr.attr,
813 &sys_reipl_nss_loadparm_attr.attr,
814 &sys_reipl_nss_vmparm_attr.attr,
584 NULL, 815 NULL,
585}; 816};
586 817
@@ -617,7 +848,10 @@ static int reipl_set_type(enum ipl_type type)
617 reipl_method = REIPL_METHOD_FCP_DUMP; 848 reipl_method = REIPL_METHOD_FCP_DUMP;
618 break; 849 break;
619 case IPL_TYPE_NSS: 850 case IPL_TYPE_NSS:
620 reipl_method = REIPL_METHOD_NSS; 851 if (diag308_set_works)
852 reipl_method = REIPL_METHOD_NSS_DIAG;
853 else
854 reipl_method = REIPL_METHOD_NSS;
621 break; 855 break;
622 case IPL_TYPE_UNKNOWN: 856 case IPL_TYPE_UNKNOWN:
623 reipl_method = REIPL_METHOD_DEFAULT; 857 reipl_method = REIPL_METHOD_DEFAULT;
@@ -655,11 +889,38 @@ static struct kobj_attribute reipl_type_attr =
655 889
656static struct kset *reipl_kset; 890static struct kset *reipl_kset;
657 891
892static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
893 const enum ipl_method m)
894{
895 char loadparm[LOADPARM_LEN + 1] = {};
896 char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
897 char nss_name[NSS_NAME_SIZE + 1] = {};
898 size_t pos = 0;
899
900 reipl_get_ascii_loadparm(loadparm, ipb);
901 reipl_get_ascii_nss_name(nss_name, ipb);
902 reipl_get_ascii_vmparm(vmparm, ipb);
903
904 switch (m) {
905 case REIPL_METHOD_CCW_VM:
906 pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno);
907 break;
908 case REIPL_METHOD_NSS:
909 pos = sprintf(dst, "IPL %s", nss_name);
910 break;
911 default:
912 break;
913 }
914 if (strlen(loadparm) > 0)
915 pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm);
916 if (strlen(vmparm) > 0)
917 sprintf(dst + pos, " PARM %s", vmparm);
918}
919
658static void reipl_run(struct shutdown_trigger *trigger) 920static void reipl_run(struct shutdown_trigger *trigger)
659{ 921{
660 struct ccw_dev_id devid; 922 struct ccw_dev_id devid;
661 static char buf[100]; 923 static char buf[128];
662 char loadparm[LOADPARM_LEN + 1];
663 924
664 switch (reipl_method) { 925 switch (reipl_method) {
665 case REIPL_METHOD_CCW_CIO: 926 case REIPL_METHOD_CCW_CIO:
@@ -668,13 +929,7 @@ static void reipl_run(struct shutdown_trigger *trigger)
668 reipl_ccw_dev(&devid); 929 reipl_ccw_dev(&devid);
669 break; 930 break;
670 case REIPL_METHOD_CCW_VM: 931 case REIPL_METHOD_CCW_VM:
671 reipl_get_ascii_loadparm(loadparm); 932 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); 933 __cpcmd(buf, NULL, 0, NULL);
679 break; 934 break;
680 case REIPL_METHOD_CCW_DIAG: 935 case REIPL_METHOD_CCW_DIAG:
@@ -691,8 +946,12 @@ static void reipl_run(struct shutdown_trigger *trigger)
691 case REIPL_METHOD_FCP_RO_VM: 946 case REIPL_METHOD_FCP_RO_VM:
692 __cpcmd("IPL", NULL, 0, NULL); 947 __cpcmd("IPL", NULL, 0, NULL);
693 break; 948 break;
949 case REIPL_METHOD_NSS_DIAG:
950 diag308(DIAG308_SET, reipl_block_nss);
951 diag308(DIAG308_IPL, NULL);
952 break;
694 case REIPL_METHOD_NSS: 953 case REIPL_METHOD_NSS:
695 sprintf(buf, "IPL %s", reipl_nss_name); 954 get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS);
696 __cpcmd(buf, NULL, 0, NULL); 955 __cpcmd(buf, NULL, 0, NULL);
697 break; 956 break;
698 case REIPL_METHOD_DEFAULT: 957 case REIPL_METHOD_DEFAULT:
@@ -707,16 +966,36 @@ static void reipl_run(struct shutdown_trigger *trigger)
707 disabled_wait((unsigned long) __builtin_return_address(0)); 966 disabled_wait((unsigned long) __builtin_return_address(0));
708} 967}
709 968
710static void __init reipl_probe(void) 969static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
711{ 970{
712 void *buffer; 971 ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
972 ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
973 ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
974 ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW;
975}
713 976
714 buffer = (void *) get_zeroed_page(GFP_KERNEL); 977static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
715 if (!buffer) 978{
716 return; 979 /* LOADPARM */
717 if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) 980 /* check if read scp info worked and set loadparm */
718 diag308_set_works = 1; 981 if (sclp_ipl_info.is_valid)
719 free_page((unsigned long)buffer); 982 memcpy(ipb->ipl_info.ccw.load_parm,
983 &sclp_ipl_info.loadparm, LOADPARM_LEN);
984 else
985 /* read scp info failed: set empty loadparm (EBCDIC blanks) */
986 memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN);
987 ipb->hdr.flags = DIAG308_FLAGS_LP_VALID;
988
989 /* VM PARM */
990 if (MACHINE_IS_VM && diag308_set_works &&
991 (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) {
992
993 ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
994 ipb->ipl_info.ccw.vm_parm_len =
995 ipl_block.ipl_info.ccw.vm_parm_len;
996 memcpy(ipb->ipl_info.ccw.vm_parm,
997 ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE);
998 }
720} 999}
721 1000
722static int __init reipl_nss_init(void) 1001static int __init reipl_nss_init(void)
@@ -725,10 +1004,31 @@ static int __init reipl_nss_init(void)
725 1004
726 if (!MACHINE_IS_VM) 1005 if (!MACHINE_IS_VM)
727 return 0; 1006 return 0;
1007
1008 reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
1009 if (!reipl_block_nss)
1010 return -ENOMEM;
1011
1012 if (!diag308_set_works)
1013 sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO;
1014
728 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); 1015 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
729 if (rc) 1016 if (rc)
730 return rc; 1017 return rc;
731 strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); 1018
1019 reipl_block_ccw_init(reipl_block_nss);
1020 if (ipl_info.type == IPL_TYPE_NSS) {
1021 memset(reipl_block_nss->ipl_info.ccw.nss_name,
1022 ' ', NSS_NAME_SIZE);
1023 memcpy(reipl_block_nss->ipl_info.ccw.nss_name,
1024 kernel_nss_name, strlen(kernel_nss_name));
1025 ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
1026 reipl_block_nss->ipl_info.ccw.vm_flags |=
1027 DIAG308_VM_FLAGS_NSS_VALID;
1028
1029 reipl_block_ccw_fill_parms(reipl_block_nss);
1030 }
1031
732 reipl_capabilities |= IPL_TYPE_NSS; 1032 reipl_capabilities |= IPL_TYPE_NSS;
733 return 0; 1033 return 0;
734} 1034}
@@ -740,28 +1040,27 @@ static int __init reipl_ccw_init(void)
740 reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); 1040 reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
741 if (!reipl_block_ccw) 1041 if (!reipl_block_ccw)
742 return -ENOMEM; 1042 return -ENOMEM;
743 rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); 1043
744 if (rc) { 1044 if (MACHINE_IS_VM) {
745 free_page((unsigned long)reipl_block_ccw); 1045 if (!diag308_set_works)
746 return rc; 1046 sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO;
1047 rc = sysfs_create_group(&reipl_kset->kobj,
1048 &reipl_ccw_attr_group_vm);
1049 } else {
1050 if(!diag308_set_works)
1051 sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
1052 rc = sysfs_create_group(&reipl_kset->kobj,
1053 &reipl_ccw_attr_group_lpar);
747 } 1054 }
748 reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; 1055 if (rc)
749 reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; 1056 return rc;
750 reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; 1057
751 reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; 1058 reipl_block_ccw_init(reipl_block_ccw);
752 reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID; 1059 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; 1060 reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
1061 reipl_block_ccw_fill_parms(reipl_block_ccw);
1062 }
1063
765 reipl_capabilities |= IPL_TYPE_CCW; 1064 reipl_capabilities |= IPL_TYPE_CCW;
766 return 0; 1065 return 0;
767} 1066}
@@ -1298,7 +1597,6 @@ static void __init shutdown_actions_init(void)
1298 1597
1299static int __init s390_ipl_init(void) 1598static int __init s390_ipl_init(void)
1300{ 1599{
1301 reipl_probe();
1302 sclp_get_ipl_info(&sclp_ipl_info); 1600 sclp_get_ipl_info(&sclp_ipl_info);
1303 shutdown_actions_init(); 1601 shutdown_actions_init();
1304 shutdown_triggers_init(); 1602 shutdown_triggers_init();
@@ -1405,6 +1703,12 @@ void __init setup_ipl(void)
1405 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 1703 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
1406} 1704}
1407 1705
1706void __init ipl_update_parameters(void)
1707{
1708 if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK)
1709 diag308_set_works = 1;
1710}
1711
1408void __init ipl_save_parameters(void) 1712void __init ipl_save_parameters(void)
1409{ 1713{
1410 struct cio_iplinfo iplinfo; 1714 struct cio_iplinfo iplinfo;