aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2008-01-26 08:11:11 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-01-26 08:11:19 -0500
commit99ca4e582d4a4088969681efff97be44d98421a1 (patch)
treef6478bcdc30d84cc6f67485bd78c9ba54827e07e /arch/s390/kernel/ipl.c
parentceb3dfbae1d3faacaedfc64c913fd18cd3624f72 (diff)
[S390] kernel: Shutdown Actions Interface
In case of a kernel panic it is currently possible to specify that a dump should be created, the system should be rebooted or stopped. Virtual sysfs files under the directory /sys/firmware/ are used for that configuration. In addition to that, there are kernel parameters 'vmhalt', 'vmpoff' and 'vmpanic', which can be used to specify z/VM commands, which are automatically executed in case of halt, power off or a kernel panic. This patch combines both functionalities and allows to specify the z/VM CP commands also via sysfs attributes. In addition to that, it enhances the existing handling of shutdown triggers (e.g. halt or panic) and associated shutdown actions (e.g. dump or reipl) and makes it more flexible. Signed-off-by: Michael Holzheu <holzheu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c931
1 files changed, 599 insertions, 332 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