aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/kernel/ipl.c931
-rw-r--r--arch/s390/kernel/setup.c103
-rw-r--r--arch/s390/kernel/smp.c27
-rw-r--r--include/asm-s390/ipl.h4
4 files changed, 603 insertions, 462 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index b97694fa62ec..d73aff63725f 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2,7 +2,7 @@
2 * arch/s390/kernel/ipl.c 2 * arch/s390/kernel/ipl.c
3 * ipl/reipl/dump support for Linux on s390. 3 * ipl/reipl/dump support for Linux on s390.
4 * 4 *
5 * Copyright (C) IBM Corp. 2005,2006 5 * Copyright IBM Corp. 2005,2007
6 * Author(s): Michael Holzheu <holzheu@de.ibm.com> 6 * Author(s): Michael Holzheu <holzheu@de.ibm.com>
7 * Heiko Carstens <heiko.carstens@de.ibm.com> 7 * Heiko Carstens <heiko.carstens@de.ibm.com>
8 * Volker Sameske <sameske@de.ibm.com> 8 * Volker Sameske <sameske@de.ibm.com>
@@ -31,6 +31,43 @@
31#define IPL_FCP_DUMP_STR "fcp_dump" 31#define IPL_FCP_DUMP_STR "fcp_dump"
32#define IPL_NSS_STR "nss" 32#define IPL_NSS_STR "nss"
33 33
34#define DUMP_CCW_STR "ccw"
35#define DUMP_FCP_STR "fcp"
36#define DUMP_NONE_STR "none"
37
38/*
39 * Four shutdown trigger types are supported:
40 * - panic
41 * - halt
42 * - power off
43 * - reipl
44 */
45#define ON_PANIC_STR "on_panic"
46#define ON_HALT_STR "on_halt"
47#define ON_POFF_STR "on_poff"
48#define ON_REIPL_STR "on_reboot"
49
50struct shutdown_action;
51struct shutdown_trigger {
52 char *name;
53 struct shutdown_action *action;
54};
55
56/*
57 * Five shutdown action types are supported:
58 */
59#define SHUTDOWN_ACTION_IPL_STR "ipl"
60#define SHUTDOWN_ACTION_REIPL_STR "reipl"
61#define SHUTDOWN_ACTION_DUMP_STR "dump"
62#define SHUTDOWN_ACTION_VMCMD_STR "vmcmd"
63#define SHUTDOWN_ACTION_STOP_STR "stop"
64
65struct shutdown_action {
66 char *name;
67 void (*fn) (struct shutdown_trigger *trigger);
68 int (*init) (void);
69};
70
34static char *ipl_type_str(enum ipl_type type) 71static char *ipl_type_str(enum ipl_type type)
35{ 72{
36 switch (type) { 73 switch (type) {
@@ -54,10 +91,6 @@ enum dump_type {
54 DUMP_TYPE_FCP = 4, 91 DUMP_TYPE_FCP = 4,
55}; 92};
56 93
57#define DUMP_NONE_STR "none"
58#define DUMP_CCW_STR "ccw"
59#define DUMP_FCP_STR "fcp"
60
61static char *dump_type_str(enum dump_type type) 94static char *dump_type_str(enum dump_type type)
62{ 95{
63 switch (type) { 96 switch (type) {
@@ -99,30 +132,6 @@ enum dump_method {
99 DUMP_METHOD_FCP_DIAG, 132 DUMP_METHOD_FCP_DIAG,
100}; 133};
101 134
102enum shutdown_action {
103 SHUTDOWN_REIPL,
104 SHUTDOWN_DUMP,
105 SHUTDOWN_STOP,
106};
107
108#define SHUTDOWN_REIPL_STR "reipl"
109#define SHUTDOWN_DUMP_STR "dump"
110#define SHUTDOWN_STOP_STR "stop"
111
112static char *shutdown_action_str(enum shutdown_action action)
113{
114 switch (action) {
115 case SHUTDOWN_REIPL:
116 return SHUTDOWN_REIPL_STR;
117 case SHUTDOWN_DUMP:
118 return SHUTDOWN_DUMP_STR;
119 case SHUTDOWN_STOP:
120 return SHUTDOWN_STOP_STR;
121 default:
122 return NULL;
123 }
124}
125
126static int diag308_set_works = 0; 135static int diag308_set_works = 0;
127 136
128static int reipl_capabilities = IPL_TYPE_UNKNOWN; 137static int reipl_capabilities = IPL_TYPE_UNKNOWN;
@@ -140,8 +149,6 @@ static enum dump_method dump_method = DUMP_METHOD_NONE;
140static struct ipl_parameter_block *dump_block_fcp; 149static struct ipl_parameter_block *dump_block_fcp;
141static struct ipl_parameter_block *dump_block_ccw; 150static struct ipl_parameter_block *dump_block_ccw;
142 151
143static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
144
145static struct sclp_ipl_info sclp_ipl_info; 152static struct sclp_ipl_info sclp_ipl_info;
146 153
147int diag308(unsigned long subcode, void *addr) 154int diag308(unsigned long subcode, void *addr)
@@ -205,8 +212,8 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
205 struct kobj_attribute *attr, \ 212 struct kobj_attribute *attr, \
206 const char *buf, size_t len) \ 213 const char *buf, size_t len) \
207{ \ 214{ \
208 if (sscanf(buf, _fmt_in, _value) != 1) \ 215 strncpy(_value, buf, sizeof(_value) - 1); \
209 return -EINVAL; \ 216 strstrip(_value); \
210 return len; \ 217 return len; \
211} \ 218} \
212static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ 219static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
@@ -245,33 +252,6 @@ static __init enum ipl_type get_ipl_type(void)
245 return IPL_TYPE_FCP; 252 return IPL_TYPE_FCP;
246} 253}
247 254
248void __init setup_ipl_info(void)
249{
250 ipl_info.type = get_ipl_type();
251 switch (ipl_info.type) {
252 case IPL_TYPE_CCW:
253 ipl_info.data.ccw.dev_id.devno = ipl_devno;
254 ipl_info.data.ccw.dev_id.ssid = 0;
255 break;
256 case IPL_TYPE_FCP:
257 case IPL_TYPE_FCP_DUMP:
258 ipl_info.data.fcp.dev_id.devno =
259 IPL_PARMBLOCK_START->ipl_info.fcp.devno;
260 ipl_info.data.fcp.dev_id.ssid = 0;
261 ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
262 ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
263 break;
264 case IPL_TYPE_NSS:
265 strncpy(ipl_info.data.nss.name, kernel_nss_name,
266 sizeof(ipl_info.data.nss.name));
267 break;
268 case IPL_TYPE_UNKNOWN:
269 default:
270 /* We have no info to copy */
271 break;
272 }
273}
274
275struct ipl_info ipl_info; 255struct ipl_info ipl_info;
276EXPORT_SYMBOL_GPL(ipl_info); 256EXPORT_SYMBOL_GPL(ipl_info);
277 257
@@ -428,8 +408,74 @@ static struct attribute_group ipl_unknown_attr_group = {
428 408
429static struct kset *ipl_kset; 409static struct kset *ipl_kset;
430 410
411static int __init ipl_register_fcp_files(void)
412{
413 int rc;
414
415 rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
416 if (rc)
417 goto out;
418 rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
419 if (rc)
420 goto out_ipl_parm;
421 rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
422 if (!rc)
423 goto out;
424
425 sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
426
427out_ipl_parm:
428 sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
429out:
430 return rc;
431}
432
433static void ipl_run(struct shutdown_trigger *trigger)
434{
435 diag308(DIAG308_IPL, NULL);
436 if (MACHINE_IS_VM)
437 __cpcmd("IPL", NULL, 0, NULL);
438 else if (ipl_info.type == IPL_TYPE_CCW)
439 reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
440}
441
442static int ipl_init(void)
443{
444 int rc;
445
446 ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
447 if (!ipl_kset) {
448 rc = -ENOMEM;
449 goto out;
450 }
451 switch (ipl_info.type) {
452 case IPL_TYPE_CCW:
453 rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
454 break;
455 case IPL_TYPE_FCP:
456 case IPL_TYPE_FCP_DUMP:
457 rc = ipl_register_fcp_files();
458 break;
459 case IPL_TYPE_NSS:
460 rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
461 break;
462 default:
463 rc = sysfs_create_group(&ipl_kset->kobj,
464 &ipl_unknown_attr_group);
465 break;
466 }
467out:
468 if (rc)
469 panic("ipl_init failed: rc = %i\n", rc);
470
471 return 0;
472}
473
474static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
475 ipl_init};
476
431/* 477/*
432 * reipl section 478 * reipl shutdown action: Reboot Linux on shutdown.
433 */ 479 */
434 480
435/* FCP reipl device attributes */ 481/* FCP reipl device attributes */
@@ -600,143 +646,11 @@ static ssize_t reipl_type_store(struct kobject *kobj,
600} 646}
601 647
602static struct kobj_attribute reipl_type_attr = 648static struct kobj_attribute reipl_type_attr =
603 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); 649 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
604 650
605static struct kset *reipl_kset; 651static struct kset *reipl_kset;
606 652
607/* 653void reipl_run(struct shutdown_trigger *trigger)
608 * dump section
609 */
610
611/* FCP dump device attributes */
612
613DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
614 dump_block_fcp->ipl_info.fcp.wwpn);
615DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
616 dump_block_fcp->ipl_info.fcp.lun);
617DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
618 dump_block_fcp->ipl_info.fcp.bootprog);
619DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
620 dump_block_fcp->ipl_info.fcp.br_lba);
621DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
622 dump_block_fcp->ipl_info.fcp.devno);
623
624static struct attribute *dump_fcp_attrs[] = {
625 &sys_dump_fcp_device_attr.attr,
626 &sys_dump_fcp_wwpn_attr.attr,
627 &sys_dump_fcp_lun_attr.attr,
628 &sys_dump_fcp_bootprog_attr.attr,
629 &sys_dump_fcp_br_lba_attr.attr,
630 NULL,
631};
632
633static struct attribute_group dump_fcp_attr_group = {
634 .name = IPL_FCP_STR,
635 .attrs = dump_fcp_attrs,
636};
637
638/* CCW dump device attributes */
639
640DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
641 dump_block_ccw->ipl_info.ccw.devno);
642
643static struct attribute *dump_ccw_attrs[] = {
644 &sys_dump_ccw_device_attr.attr,
645 NULL,
646};
647
648static struct attribute_group dump_ccw_attr_group = {
649 .name = IPL_CCW_STR,
650 .attrs = dump_ccw_attrs,
651};
652
653/* dump type */
654
655static int dump_set_type(enum dump_type type)
656{
657 if (!(dump_capabilities & type))
658 return -EINVAL;
659 switch(type) {
660 case DUMP_TYPE_CCW:
661 if (MACHINE_IS_VM)
662 dump_method = DUMP_METHOD_CCW_VM;
663 else if (diag308_set_works)
664 dump_method = DUMP_METHOD_CCW_DIAG;
665 else
666 dump_method = DUMP_METHOD_CCW_CIO;
667 break;
668 case DUMP_TYPE_FCP:
669 dump_method = DUMP_METHOD_FCP_DIAG;
670 break;
671 default:
672 dump_method = DUMP_METHOD_NONE;
673 }
674 dump_type = type;
675 return 0;
676}
677
678static ssize_t dump_type_show(struct kobject *kobj,
679 struct kobj_attribute *attr, char *page)
680{
681 return sprintf(page, "%s\n", dump_type_str(dump_type));
682}
683
684static ssize_t dump_type_store(struct kobject *kobj,
685 struct kobj_attribute *attr,
686 const char *buf, size_t len)
687{
688 int rc = -EINVAL;
689
690 if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
691 rc = dump_set_type(DUMP_TYPE_NONE);
692 else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
693 rc = dump_set_type(DUMP_TYPE_CCW);
694 else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
695 rc = dump_set_type(DUMP_TYPE_FCP);
696 return (rc != 0) ? rc : len;
697}
698
699static struct kobj_attribute dump_type_attr =
700 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
701
702static struct kset *dump_kset;
703
704/*
705 * Shutdown actions section
706 */
707
708static struct kset *shutdown_actions_kset;
709
710/* on panic */
711
712static ssize_t on_panic_show(struct kobject *kobj,
713 struct kobj_attribute *attr, char *page)
714{
715 return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
716}
717
718static ssize_t on_panic_store(struct kobject *kobj,
719 struct kobj_attribute *attr,
720 const char *buf, size_t len)
721{
722 if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
723 on_panic_action = SHUTDOWN_REIPL;
724 else if (strncmp(buf, SHUTDOWN_DUMP_STR,
725 strlen(SHUTDOWN_DUMP_STR)) == 0)
726 on_panic_action = SHUTDOWN_DUMP;
727 else if (strncmp(buf, SHUTDOWN_STOP_STR,
728 strlen(SHUTDOWN_STOP_STR)) == 0)
729 on_panic_action = SHUTDOWN_STOP;
730 else
731 return -EINVAL;
732
733 return len;
734}
735
736static struct kobj_attribute on_panic_attr =
737 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
738
739void do_reipl(void)
740{ 654{
741 struct ccw_dev_id devid; 655 struct ccw_dev_id devid;
742 static char buf[100]; 656 static char buf[100];
@@ -787,98 +701,6 @@ void do_reipl(void)
787 default: 701 default:
788 break; 702 break;
789 } 703 }
790 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
791}
792
793static void do_dump(void)
794{
795 struct ccw_dev_id devid;
796 static char buf[100];
797
798 switch (dump_method) {
799 case DUMP_METHOD_CCW_CIO:
800 smp_send_stop();
801 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
802 devid.ssid = 0;
803 reipl_ccw_dev(&devid);
804 break;
805 case DUMP_METHOD_CCW_VM:
806 smp_send_stop();
807 sprintf(buf, "STORE STATUS");
808 __cpcmd(buf, NULL, 0, NULL);
809 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
810 __cpcmd(buf, NULL, 0, NULL);
811 break;
812 case DUMP_METHOD_CCW_DIAG:
813 diag308(DIAG308_SET, dump_block_ccw);
814 diag308(DIAG308_DUMP, NULL);
815 break;
816 case DUMP_METHOD_FCP_DIAG:
817 diag308(DIAG308_SET, dump_block_fcp);
818 diag308(DIAG308_DUMP, NULL);
819 break;
820 case DUMP_METHOD_NONE:
821 default:
822 return;
823 }
824 printk(KERN_EMERG "Dump failed!\n");
825}
826
827/* init functions */
828
829static int __init ipl_register_fcp_files(void)
830{
831 int rc;
832
833 rc = sysfs_create_group(&ipl_kset->kobj,
834 &ipl_fcp_attr_group);
835 if (rc)
836 goto out;
837 rc = sysfs_create_bin_file(&ipl_kset->kobj,
838 &ipl_parameter_attr);
839 if (rc)
840 goto out_ipl_parm;
841 rc = sysfs_create_bin_file(&ipl_kset->kobj,
842 &ipl_scp_data_attr);
843 if (!rc)
844 goto out;
845
846 sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
847
848out_ipl_parm:
849 sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
850out:
851 return rc;
852}
853
854static int __init ipl_init(void)
855{
856 int rc;
857
858 ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
859 if (!ipl_kset)
860 return -ENOMEM;
861 switch (ipl_info.type) {
862 case IPL_TYPE_CCW:
863 rc = sysfs_create_group(&ipl_kset->kobj,
864 &ipl_ccw_attr_group);
865 break;
866 case IPL_TYPE_FCP:
867 case IPL_TYPE_FCP_DUMP:
868 rc = ipl_register_fcp_files();
869 break;
870 case IPL_TYPE_NSS:
871 rc = sysfs_create_group(&ipl_kset->kobj,
872 &ipl_nss_attr_group);
873 break;
874 default:
875 rc = sysfs_create_group(&ipl_kset->kobj,
876 &ipl_unknown_attr_group);
877 break;
878 }
879 if (rc)
880 kset_unregister(ipl_kset);
881 return rc;
882} 704}
883 705
884static void __init reipl_probe(void) 706static void __init reipl_probe(void)
@@ -970,7 +792,7 @@ static int __init reipl_fcp_init(void)
970 return 0; 792 return 0;
971} 793}
972 794
973static int __init reipl_init(void) 795static int reipl_init(void)
974{ 796{
975 int rc; 797 int rc;
976 798
@@ -997,6 +819,138 @@ static int __init reipl_init(void)
997 return 0; 819 return 0;
998} 820}
999 821
822static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
823 reipl_run, reipl_init};
824
825/*
826 * dump shutdown action: Dump Linux on shutdown.
827 */
828
829/* FCP dump device attributes */
830
831DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
832 dump_block_fcp->ipl_info.fcp.wwpn);
833DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
834 dump_block_fcp->ipl_info.fcp.lun);
835DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
836 dump_block_fcp->ipl_info.fcp.bootprog);
837DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
838 dump_block_fcp->ipl_info.fcp.br_lba);
839DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
840 dump_block_fcp->ipl_info.fcp.devno);
841
842static struct attribute *dump_fcp_attrs[] = {
843 &sys_dump_fcp_device_attr.attr,
844 &sys_dump_fcp_wwpn_attr.attr,
845 &sys_dump_fcp_lun_attr.attr,
846 &sys_dump_fcp_bootprog_attr.attr,
847 &sys_dump_fcp_br_lba_attr.attr,
848 NULL,
849};
850
851static struct attribute_group dump_fcp_attr_group = {
852 .name = IPL_FCP_STR,
853 .attrs = dump_fcp_attrs,
854};
855
856/* CCW dump device attributes */
857
858DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
859 dump_block_ccw->ipl_info.ccw.devno);
860
861static struct attribute *dump_ccw_attrs[] = {
862 &sys_dump_ccw_device_attr.attr,
863 NULL,
864};
865
866static struct attribute_group dump_ccw_attr_group = {
867 .name = IPL_CCW_STR,
868 .attrs = dump_ccw_attrs,
869};
870
871/* dump type */
872
873static int dump_set_type(enum dump_type type)
874{
875 if (!(dump_capabilities & type))
876 return -EINVAL;
877 switch (type) {
878 case DUMP_TYPE_CCW:
879 if (MACHINE_IS_VM)
880 dump_method = DUMP_METHOD_CCW_VM;
881 else
882 dump_method = DUMP_METHOD_CCW_CIO;
883 break;
884 case DUMP_TYPE_FCP:
885 dump_method = DUMP_METHOD_FCP_DIAG;
886 break;
887 default:
888 dump_method = DUMP_METHOD_NONE;
889 }
890 dump_type = type;
891 return 0;
892}
893
894static ssize_t dump_type_show(struct kobject *kobj,
895 struct kobj_attribute *attr, char *page)
896{
897 return sprintf(page, "%s\n", dump_type_str(dump_type));
898}
899
900static ssize_t dump_type_store(struct kobject *kobj,
901 struct kobj_attribute *attr,
902 const char *buf, size_t len)
903{
904 int rc = -EINVAL;
905
906 if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
907 rc = dump_set_type(DUMP_TYPE_NONE);
908 else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
909 rc = dump_set_type(DUMP_TYPE_CCW);
910 else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
911 rc = dump_set_type(DUMP_TYPE_FCP);
912 return (rc != 0) ? rc : len;
913}
914
915static struct kobj_attribute dump_type_attr =
916 __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
917
918static struct kset *dump_kset;
919
920static void dump_run(struct shutdown_trigger *trigger)
921{
922 struct ccw_dev_id devid;
923 static char buf[100];
924
925 switch (dump_method) {
926 case DUMP_METHOD_CCW_CIO:
927 smp_send_stop();
928 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
929 devid.ssid = 0;
930 reipl_ccw_dev(&devid);
931 break;
932 case DUMP_METHOD_CCW_VM:
933 smp_send_stop();
934 sprintf(buf, "STORE STATUS");
935 __cpcmd(buf, NULL, 0, NULL);
936 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
937 __cpcmd(buf, NULL, 0, NULL);
938 break;
939 case DUMP_METHOD_CCW_DIAG:
940 diag308(DIAG308_SET, dump_block_ccw);
941 diag308(DIAG308_DUMP, NULL);
942 break;
943 case DUMP_METHOD_FCP_DIAG:
944 diag308(DIAG308_SET, dump_block_fcp);
945 diag308(DIAG308_DUMP, NULL);
946 break;
947 case DUMP_METHOD_NONE:
948 default:
949 return;
950 }
951 printk(KERN_EMERG "Dump failed!\n");
952}
953
1000static int __init dump_ccw_init(void) 954static int __init dump_ccw_init(void)
1001{ 955{
1002 int rc; 956 int rc;
@@ -1042,31 +996,14 @@ static int __init dump_fcp_init(void)
1042 return 0; 996 return 0;
1043} 997}
1044 998
1045#define SHUTDOWN_ON_PANIC_PRIO 0 999static int dump_init(void)
1046
1047static int shutdown_on_panic_notify(struct notifier_block *self,
1048 unsigned long event, void *data)
1049{
1050 if (on_panic_action == SHUTDOWN_DUMP)
1051 do_dump();
1052 else if (on_panic_action == SHUTDOWN_REIPL)
1053 do_reipl();
1054 return NOTIFY_OK;
1055}
1056
1057static struct notifier_block shutdown_on_panic_nb = {
1058 .notifier_call = shutdown_on_panic_notify,
1059 .priority = SHUTDOWN_ON_PANIC_PRIO
1060};
1061
1062static int __init dump_init(void)
1063{ 1000{
1064 int rc; 1001 int rc;
1065 1002
1066 dump_kset = kset_create_and_add("dump", NULL, firmware_kobj); 1003 dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
1067 if (!dump_kset) 1004 if (!dump_kset)
1068 return -ENOMEM; 1005 return -ENOMEM;
1069 rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr); 1006 rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
1070 if (rc) { 1007 if (rc) {
1071 kset_unregister(dump_kset); 1008 kset_unregister(dump_kset);
1072 return rc; 1009 return rc;
@@ -1081,47 +1018,376 @@ static int __init dump_init(void)
1081 return 0; 1018 return 0;
1082} 1019}
1083 1020
1084static int __init shutdown_actions_init(void) 1021static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
1022 dump_run, dump_init};
1023
1024/*
1025 * vmcmd shutdown action: Trigger vm command on shutdown.
1026 */
1027
1028static char vmcmd_on_reboot[128];
1029static char vmcmd_on_panic[128];
1030static char vmcmd_on_halt[128];
1031static char vmcmd_on_poff[128];
1032
1033DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
1034DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
1035DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
1036DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
1037
1038static struct attribute *vmcmd_attrs[] = {
1039 &sys_vmcmd_on_reboot_attr.attr,
1040 &sys_vmcmd_on_panic_attr.attr,
1041 &sys_vmcmd_on_halt_attr.attr,
1042 &sys_vmcmd_on_poff_attr.attr,
1043 NULL,
1044};
1045
1046static struct attribute_group vmcmd_attr_group = {
1047 .attrs = vmcmd_attrs,
1048};
1049
1050static struct kset *vmcmd_kset;
1051
1052static void vmcmd_run(struct shutdown_trigger *trigger)
1085{ 1053{
1086 int rc; 1054 char *cmd, *next_cmd;
1055
1056 if (strcmp(trigger->name, ON_REIPL_STR) == 0)
1057 cmd = vmcmd_on_reboot;
1058 else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
1059 cmd = vmcmd_on_panic;
1060 else if (strcmp(trigger->name, ON_HALT_STR) == 0)
1061 cmd = vmcmd_on_halt;
1062 else if (strcmp(trigger->name, ON_POFF_STR) == 0)
1063 cmd = vmcmd_on_poff;
1064 else
1065 return;
1066
1067 if (strlen(cmd) == 0)
1068 return;
1069 do {
1070 next_cmd = strchr(cmd, '\n');
1071 if (next_cmd) {
1072 next_cmd[0] = 0;
1073 next_cmd += 1;
1074 }
1075 __cpcmd(cmd, NULL, 0, NULL);
1076 cmd = next_cmd;
1077 } while (cmd != NULL);
1078}
1079
1080static int vmcmd_init(void)
1081{
1082 if (!MACHINE_IS_VM)
1083 return -ENOTSUPP;
1084 vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
1085 if (!vmcmd_kset)
1086 return -ENOMEM;
1087 return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
1088}
1089
1090static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
1091 vmcmd_run, vmcmd_init};
1092
1093/*
1094 * stop shutdown action: Stop Linux on shutdown.
1095 */
1096
1097static void stop_run(struct shutdown_trigger *trigger)
1098{
1099 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
1100 for (;;);
1101}
1102
1103static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
1104 stop_run, NULL};
1105
1106/* action list */
1107
1108static struct shutdown_action *shutdown_actions_list[] = {
1109 &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
1110#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
1111
1112/*
1113 * Trigger section
1114 */
1115
1116static struct kset *shutdown_actions_kset;
1117
1118static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
1119 size_t len)
1120{
1121 int i;
1122 for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
1123 if (!shutdown_actions_list[i])
1124 continue;
1125 if (strncmp(buf, shutdown_actions_list[i]->name,
1126 strlen(shutdown_actions_list[i]->name)) == 0) {
1127 trigger->action = shutdown_actions_list[i];
1128 return len;
1129 }
1130 }
1131 return -EINVAL;
1132}
1133
1134/* on reipl */
1135
1136static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
1137 &reipl_action};
1138
1139static ssize_t on_reboot_show(struct kobject *kobj,
1140 struct kobj_attribute *attr, char *page)
1141{
1142 return sprintf(page, "%s\n", on_reboot_trigger.action->name);
1143}
1144
1145static ssize_t on_reboot_store(struct kobject *kobj,
1146 struct kobj_attribute *attr,
1147 const char *buf, size_t len)
1148{
1149 return set_trigger(buf, &on_reboot_trigger, len);
1150}
1151
1152static struct kobj_attribute on_reboot_attr =
1153 __ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
1154
1155static void do_machine_restart(char *__unused)
1156{
1157 smp_send_stop();
1158 on_reboot_trigger.action->fn(&on_reboot_trigger);
1159 reipl_run(NULL);
1160}
1161void (*_machine_restart)(char *command) = do_machine_restart;
1162
1163/* on panic */
1164
1165static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
1166
1167static ssize_t on_panic_show(struct kobject *kobj,
1168 struct kobj_attribute *attr, char *page)
1169{
1170 return sprintf(page, "%s\n", on_panic_trigger.action->name);
1171}
1172
1173static ssize_t on_panic_store(struct kobject *kobj,
1174 struct kobj_attribute *attr,
1175 const char *buf, size_t len)
1176{
1177 return set_trigger(buf, &on_panic_trigger, len);
1178}
1179
1180static struct kobj_attribute on_panic_attr =
1181 __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
1182
1183static void do_panic(void)
1184{
1185 on_panic_trigger.action->fn(&on_panic_trigger);
1186 stop_run(&on_panic_trigger);
1187}
1188
1189/* on halt */
1190
1191static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
1192
1193static ssize_t on_halt_show(struct kobject *kobj,
1194 struct kobj_attribute *attr, char *page)
1195{
1196 return sprintf(page, "%s\n", on_halt_trigger.action->name);
1197}
1198
1199static ssize_t on_halt_store(struct kobject *kobj,
1200 struct kobj_attribute *attr,
1201 const char *buf, size_t len)
1202{
1203 return set_trigger(buf, &on_halt_trigger, len);
1204}
1205
1206static struct kobj_attribute on_halt_attr =
1207 __ATTR(on_halt, 0644, on_halt_show, on_halt_store);
1208
1209
1210static void do_machine_halt(void)
1211{
1212 smp_send_stop();
1213 on_halt_trigger.action->fn(&on_halt_trigger);
1214 stop_run(&on_halt_trigger);
1215}
1216void (*_machine_halt)(void) = do_machine_halt;
1217
1218/* on power off */
1219
1220static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
1221
1222static ssize_t on_poff_show(struct kobject *kobj,
1223 struct kobj_attribute *attr, char *page)
1224{
1225 return sprintf(page, "%s\n", on_poff_trigger.action->name);
1226}
1227
1228static ssize_t on_poff_store(struct kobject *kobj,
1229 struct kobj_attribute *attr,
1230 const char *buf, size_t len)
1231{
1232 return set_trigger(buf, &on_poff_trigger, len);
1233}
1234
1235static struct kobj_attribute on_poff_attr =
1236 __ATTR(on_poff, 0644, on_poff_show, on_poff_store);
1237
1238
1239static void do_machine_power_off(void)
1240{
1241 smp_send_stop();
1242 on_poff_trigger.action->fn(&on_poff_trigger);
1243 stop_run(&on_poff_trigger);
1244}
1245void (*_machine_power_off)(void) = do_machine_power_off;
1087 1246
1247static void __init shutdown_triggers_init(void)
1248{
1088 shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL, 1249 shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
1089 firmware_kobj); 1250 firmware_kobj);
1090 if (!shutdown_actions_kset) 1251 if (!shutdown_actions_kset)
1091 return -ENOMEM; 1252 goto fail;
1092 rc = sysfs_create_file(&shutdown_actions_kset->kobj, &on_panic_attr); 1253 if (sysfs_create_file(&shutdown_actions_kset->kobj,
1093 if (rc) { 1254 &on_reboot_attr.attr))
1094 kset_unregister(shutdown_actions_kset); 1255 goto fail;
1095 return rc; 1256 if (sysfs_create_file(&shutdown_actions_kset->kobj,
1257 &on_panic_attr.attr))
1258 goto fail;
1259 if (sysfs_create_file(&shutdown_actions_kset->kobj,
1260 &on_halt_attr.attr))
1261 goto fail;
1262 if (sysfs_create_file(&shutdown_actions_kset->kobj,
1263 &on_poff_attr.attr))
1264 goto fail;
1265
1266 return;
1267fail:
1268 panic("shutdown_triggers_init failed\n");
1269}
1270
1271static void __init shutdown_actions_init(void)
1272{
1273 int i;
1274
1275 for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
1276 if (!shutdown_actions_list[i]->init)
1277 continue;
1278 if (shutdown_actions_list[i]->init())
1279 shutdown_actions_list[i] = NULL;
1096 } 1280 }
1097 atomic_notifier_chain_register(&panic_notifier_list,
1098 &shutdown_on_panic_nb);
1099 return 0;
1100} 1281}
1101 1282
1102static int __init s390_ipl_init(void) 1283static int __init s390_ipl_init(void)
1103{ 1284{
1104 int rc;
1105
1106 sclp_get_ipl_info(&sclp_ipl_info);
1107 reipl_probe(); 1285 reipl_probe();
1108 rc = ipl_init(); 1286 shutdown_actions_init();
1109 if (rc) 1287 shutdown_triggers_init();
1110 return rc;
1111 rc = reipl_init();
1112 if (rc)
1113 return rc;
1114 rc = dump_init();
1115 if (rc)
1116 return rc;
1117 rc = shutdown_actions_init();
1118 if (rc)
1119 return rc;
1120 return 0; 1288 return 0;
1121} 1289}
1122 1290
1123__initcall(s390_ipl_init); 1291__initcall(s390_ipl_init);
1124 1292
1293static void __init strncpy_skip_quote(char *dst, char *src, int n)
1294{
1295 int sx, dx;
1296
1297 dx = 0;
1298 for (sx = 0; src[sx] != 0; sx++) {
1299 if (src[sx] == '"')
1300 continue;
1301 dst[dx++] = src[sx];
1302 if (dx >= n)
1303 break;
1304 }
1305}
1306
1307static int __init vmcmd_on_reboot_setup(char *str)
1308{
1309 if (!MACHINE_IS_VM)
1310 return 1;
1311 strncpy_skip_quote(vmcmd_on_reboot, str, 127);
1312 vmcmd_on_reboot[127] = 0;
1313 on_reboot_trigger.action = &vmcmd_action;
1314 return 1;
1315}
1316__setup("vmreboot=", vmcmd_on_reboot_setup);
1317
1318static int __init vmcmd_on_panic_setup(char *str)
1319{
1320 if (!MACHINE_IS_VM)
1321 return 1;
1322 strncpy_skip_quote(vmcmd_on_panic, str, 127);
1323 vmcmd_on_panic[127] = 0;
1324 on_panic_trigger.action = &vmcmd_action;
1325 return 1;
1326}
1327__setup("vmpanic=", vmcmd_on_panic_setup);
1328
1329static int __init vmcmd_on_halt_setup(char *str)
1330{
1331 if (!MACHINE_IS_VM)
1332 return 1;
1333 strncpy_skip_quote(vmcmd_on_halt, str, 127);
1334 vmcmd_on_halt[127] = 0;
1335 on_halt_trigger.action = &vmcmd_action;
1336 return 1;
1337}
1338__setup("vmhalt=", vmcmd_on_halt_setup);
1339
1340static int __init vmcmd_on_poff_setup(char *str)
1341{
1342 if (!MACHINE_IS_VM)
1343 return 1;
1344 strncpy_skip_quote(vmcmd_on_poff, str, 127);
1345 vmcmd_on_poff[127] = 0;
1346 on_poff_trigger.action = &vmcmd_action;
1347 return 1;
1348}
1349__setup("vmpoff=", vmcmd_on_poff_setup);
1350
1351static int on_panic_notify(struct notifier_block *self,
1352 unsigned long event, void *data)
1353{
1354 do_panic();
1355 return NOTIFY_OK;
1356}
1357
1358static struct notifier_block on_panic_nb = {
1359 .notifier_call = on_panic_notify,
1360 .priority = 0,
1361};
1362
1363void __init setup_ipl(void)
1364{
1365 ipl_info.type = get_ipl_type();
1366 switch (ipl_info.type) {
1367 case IPL_TYPE_CCW:
1368 ipl_info.data.ccw.dev_id.devno = ipl_devno;
1369 ipl_info.data.ccw.dev_id.ssid = 0;
1370 break;
1371 case IPL_TYPE_FCP:
1372 case IPL_TYPE_FCP_DUMP:
1373 ipl_info.data.fcp.dev_id.devno =
1374 IPL_PARMBLOCK_START->ipl_info.fcp.devno;
1375 ipl_info.data.fcp.dev_id.ssid = 0;
1376 ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
1377 ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
1378 break;
1379 case IPL_TYPE_NSS:
1380 strncpy(ipl_info.data.nss.name, kernel_nss_name,
1381 sizeof(ipl_info.data.nss.name));
1382 break;
1383 case IPL_TYPE_UNKNOWN:
1384 default:
1385 /* We have no info to copy */
1386 break;
1387 }
1388 atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
1389}
1390
1125void __init ipl_save_parameters(void) 1391void __init ipl_save_parameters(void)
1126{ 1392{
1127 struct cio_iplinfo iplinfo; 1393 struct cio_iplinfo iplinfo;
@@ -1202,3 +1468,4 @@ void s390_reset_system(void)
1202 1468
1203 do_reset_calls(); 1469 do_reset_calls();
1204} 1470}
1471
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index cbdf3fb05e81..fcebf645618a 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -126,75 +126,6 @@ void __cpuinit cpu_init(void)
126} 126}
127 127
128/* 128/*
129 * VM halt and poweroff setup routines
130 */
131char vmhalt_cmd[128] = "";
132char vmpoff_cmd[128] = "";
133static char vmpanic_cmd[128] = "";
134
135static void strncpy_skip_quote(char *dst, char *src, int n)
136{
137 int sx, dx;
138
139 dx = 0;
140 for (sx = 0; src[sx] != 0; sx++) {
141 if (src[sx] == '"') continue;
142 dst[dx++] = src[sx];
143 if (dx >= n) break;
144 }
145}
146
147static int __init vmhalt_setup(char *str)
148{
149 strncpy_skip_quote(vmhalt_cmd, str, 127);
150 vmhalt_cmd[127] = 0;
151 return 1;
152}
153
154__setup("vmhalt=", vmhalt_setup);
155
156static int __init vmpoff_setup(char *str)
157{
158 strncpy_skip_quote(vmpoff_cmd, str, 127);
159 vmpoff_cmd[127] = 0;
160 return 1;
161}
162
163__setup("vmpoff=", vmpoff_setup);
164
165static int vmpanic_notify(struct notifier_block *self, unsigned long event,
166 void *data)
167{
168 if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
169 cpcmd(vmpanic_cmd, NULL, 0, NULL);
170
171 return NOTIFY_OK;
172}
173
174#define PANIC_PRI_VMPANIC 0
175
176static struct notifier_block vmpanic_nb = {
177 .notifier_call = vmpanic_notify,
178 .priority = PANIC_PRI_VMPANIC
179};
180
181static int __init vmpanic_setup(char *str)
182{
183 static int register_done __initdata = 0;
184
185 strncpy_skip_quote(vmpanic_cmd, str, 127);
186 vmpanic_cmd[127] = 0;
187 if (!register_done) {
188 register_done = 1;
189 atomic_notifier_chain_register(&panic_notifier_list,
190 &vmpanic_nb);
191 }
192 return 1;
193}
194
195__setup("vmpanic=", vmpanic_setup);
196
197/*
198 * condev= and conmode= setup parameter. 129 * condev= and conmode= setup parameter.
199 */ 130 */
200 131
@@ -308,38 +239,6 @@ static void __init setup_zfcpdump(unsigned int console_devno)
308static inline void setup_zfcpdump(unsigned int console_devno) {} 239static inline void setup_zfcpdump(unsigned int console_devno) {}
309#endif /* CONFIG_ZFCPDUMP */ 240#endif /* CONFIG_ZFCPDUMP */
310 241
311#ifdef CONFIG_SMP
312void (*_machine_restart)(char *command) = machine_restart_smp;
313void (*_machine_halt)(void) = machine_halt_smp;
314void (*_machine_power_off)(void) = machine_power_off_smp;
315#else
316/*
317 * Reboot, halt and power_off routines for non SMP.
318 */
319static void do_machine_restart_nonsmp(char * __unused)
320{
321 do_reipl();
322}
323
324static void do_machine_halt_nonsmp(void)
325{
326 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
327 __cpcmd(vmhalt_cmd, NULL, 0, NULL);
328 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
329}
330
331static void do_machine_power_off_nonsmp(void)
332{
333 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
334 __cpcmd(vmpoff_cmd, NULL, 0, NULL);
335 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
336}
337
338void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
339void (*_machine_halt)(void) = do_machine_halt_nonsmp;
340void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
341#endif
342
343 /* 242 /*
344 * Reboot, halt and power_off stubs. They just call _machine_restart, 243 * Reboot, halt and power_off stubs. They just call _machine_restart,
345 * _machine_halt or _machine_power_off. 244 * _machine_halt or _machine_power_off.
@@ -913,7 +812,7 @@ setup_arch(char **cmdline_p)
913 812
914 parse_early_param(); 813 parse_early_param();
915 814
916 setup_ipl_info(); 815 setup_ipl();
917 setup_memory_end(); 816 setup_memory_end();
918 setup_addressing_mode(); 817 setup_addressing_mode();
919 setup_memory(); 818 setup_memory();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 320e4e97bf52..d300a7fdf711 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -234,33 +234,6 @@ void smp_send_stop(void)
234} 234}
235 235
236/* 236/*
237 * Reboot, halt and power_off routines for SMP.
238 */
239void machine_restart_smp(char *__unused)
240{
241 smp_send_stop();
242 do_reipl();
243}
244
245void machine_halt_smp(void)
246{
247 smp_send_stop();
248 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
249 __cpcmd(vmhalt_cmd, NULL, 0, NULL);
250 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
251 for (;;);
252}
253
254void machine_power_off_smp(void)
255{
256 smp_send_stop();
257 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
258 __cpcmd(vmpoff_cmd, NULL, 0, NULL);
259 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
260 for (;;);
261}
262
263/*
264 * This is the main routine where commands issued by other 237 * This is the main routine where commands issued by other
265 * cpus are handled. 238 * cpus are handled.
266 */ 239 */
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
index 2c40fd3a137f..d0dcc9c5f7c3 100644
--- a/include/asm-s390/ipl.h
+++ b/include/asm-s390/ipl.h
@@ -83,6 +83,8 @@ extern u32 dump_prefix_page;
83extern unsigned int zfcpdump_prefix_array[]; 83extern unsigned int zfcpdump_prefix_array[];
84 84
85extern void do_reipl(void); 85extern void do_reipl(void);
86extern void do_halt(void);
87extern void do_poff(void);
86extern void ipl_save_parameters(void); 88extern void ipl_save_parameters(void);
87 89
88enum { 90enum {
@@ -118,7 +120,7 @@ struct ipl_info
118}; 120};
119 121
120extern struct ipl_info ipl_info; 122extern struct ipl_info ipl_info;
121extern void setup_ipl_info(void); 123extern void setup_ipl(void);
122 124
123/* 125/*
124 * DIAG 308 support 126 * DIAG 308 support