Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Michael Holzheu and committed by
Martin Schwidefsky
99ca4e58 ceb3dfba

+604 -463
+600 -333
arch/s390/kernel/ipl.c
··· 2 2 * arch/s390/kernel/ipl.c 3 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 6 * Author(s): Michael Holzheu <holzheu@de.ibm.com> 7 7 * Heiko Carstens <heiko.carstens@de.ibm.com> 8 8 * Volker Sameske <sameske@de.ibm.com> ··· 31 31 #define IPL_FCP_DUMP_STR "fcp_dump" 32 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 + 50 + struct shutdown_action; 51 + struct 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 + 65 + struct shutdown_action { 66 + char *name; 67 + void (*fn) (struct shutdown_trigger *trigger); 68 + int (*init) (void); 69 + }; 70 + 34 71 static char *ipl_type_str(enum ipl_type type) 35 72 { 36 73 switch (type) { ··· 90 53 DUMP_TYPE_CCW = 2, 91 54 DUMP_TYPE_FCP = 4, 92 55 }; 93 - 94 - #define DUMP_NONE_STR "none" 95 - #define DUMP_CCW_STR "ccw" 96 - #define DUMP_FCP_STR "fcp" 97 56 98 57 static char *dump_type_str(enum dump_type type) 99 58 { ··· 132 99 DUMP_METHOD_FCP_DIAG, 133 100 }; 134 101 135 - enum shutdown_action { 136 - SHUTDOWN_REIPL, 137 - SHUTDOWN_DUMP, 138 - SHUTDOWN_STOP, 139 - }; 140 - 141 - #define SHUTDOWN_REIPL_STR "reipl" 142 - #define SHUTDOWN_DUMP_STR "dump" 143 - #define SHUTDOWN_STOP_STR "stop" 144 - 145 - static char *shutdown_action_str(enum shutdown_action action) 146 - { 147 - switch (action) { 148 - case SHUTDOWN_REIPL: 149 - return SHUTDOWN_REIPL_STR; 150 - case SHUTDOWN_DUMP: 151 - return SHUTDOWN_DUMP_STR; 152 - case SHUTDOWN_STOP: 153 - return SHUTDOWN_STOP_STR; 154 - default: 155 - return NULL; 156 - } 157 - } 158 - 159 102 static int diag308_set_works = 0; 160 103 161 104 static int reipl_capabilities = IPL_TYPE_UNKNOWN; ··· 148 139 static enum dump_method dump_method = DUMP_METHOD_NONE; 149 140 static struct ipl_parameter_block *dump_block_fcp; 150 141 static struct ipl_parameter_block *dump_block_ccw; 151 - 152 - static enum shutdown_action on_panic_action = SHUTDOWN_STOP; 153 142 154 143 static struct sclp_ipl_info sclp_ipl_info; 155 144 ··· 212 205 struct kobj_attribute *attr, \ 213 206 const char *buf, size_t len) \ 214 207 { \ 215 - if (sscanf(buf, _fmt_in, _value) != 1) \ 216 - return -EINVAL; \ 208 + strncpy(_value, buf, sizeof(_value) - 1); \ 209 + strstrip(_value); \ 217 210 return len; \ 218 211 } \ 219 212 static struct kobj_attribute sys_##_prefix##_##_name##_attr = \ ··· 250 243 if (ipl->ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP) 251 244 return IPL_TYPE_FCP_DUMP; 252 245 return IPL_TYPE_FCP; 253 - } 254 - 255 - void __init setup_ipl_info(void) 256 - { 257 - ipl_info.type = get_ipl_type(); 258 - switch (ipl_info.type) { 259 - case IPL_TYPE_CCW: 260 - ipl_info.data.ccw.dev_id.devno = ipl_devno; 261 - ipl_info.data.ccw.dev_id.ssid = 0; 262 - break; 263 - case IPL_TYPE_FCP: 264 - case IPL_TYPE_FCP_DUMP: 265 - ipl_info.data.fcp.dev_id.devno = 266 - IPL_PARMBLOCK_START->ipl_info.fcp.devno; 267 - ipl_info.data.fcp.dev_id.ssid = 0; 268 - ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn; 269 - ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun; 270 - break; 271 - case IPL_TYPE_NSS: 272 - strncpy(ipl_info.data.nss.name, kernel_nss_name, 273 - sizeof(ipl_info.data.nss.name)); 274 - break; 275 - case IPL_TYPE_UNKNOWN: 276 - default: 277 - /* We have no info to copy */ 278 - break; 279 - } 280 246 } 281 247 282 248 struct ipl_info ipl_info; ··· 408 428 409 429 static struct kset *ipl_kset; 410 430 431 + static int __init ipl_register_fcp_files(void) 432 + { 433 + int rc; 434 + 435 + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group); 436 + if (rc) 437 + goto out; 438 + rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr); 439 + if (rc) 440 + goto out_ipl_parm; 441 + rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr); 442 + if (!rc) 443 + goto out; 444 + 445 + sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr); 446 + 447 + out_ipl_parm: 448 + sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group); 449 + out: 450 + return rc; 451 + } 452 + 453 + static void ipl_run(struct shutdown_trigger *trigger) 454 + { 455 + diag308(DIAG308_IPL, NULL); 456 + if (MACHINE_IS_VM) 457 + __cpcmd("IPL", NULL, 0, NULL); 458 + else if (ipl_info.type == IPL_TYPE_CCW) 459 + reipl_ccw_dev(&ipl_info.data.ccw.dev_id); 460 + } 461 + 462 + static int ipl_init(void) 463 + { 464 + int rc; 465 + 466 + ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj); 467 + if (!ipl_kset) { 468 + rc = -ENOMEM; 469 + goto out; 470 + } 471 + switch (ipl_info.type) { 472 + case IPL_TYPE_CCW: 473 + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); 474 + break; 475 + case IPL_TYPE_FCP: 476 + case IPL_TYPE_FCP_DUMP: 477 + rc = ipl_register_fcp_files(); 478 + break; 479 + case IPL_TYPE_NSS: 480 + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group); 481 + break; 482 + default: 483 + rc = sysfs_create_group(&ipl_kset->kobj, 484 + &ipl_unknown_attr_group); 485 + break; 486 + } 487 + out: 488 + if (rc) 489 + panic("ipl_init failed: rc = %i\n", rc); 490 + 491 + return 0; 492 + } 493 + 494 + static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run, 495 + ipl_init}; 496 + 411 497 /* 412 - * reipl section 498 + * reipl shutdown action: Reboot Linux on shutdown. 413 499 */ 414 500 415 501 /* FCP reipl device attributes */ ··· 646 600 } 647 601 648 602 static struct kobj_attribute reipl_type_attr = 649 - __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); 603 + __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); 650 604 651 605 static struct kset *reipl_kset; 652 606 653 - /* 654 - * dump section 655 - */ 656 - 657 - /* FCP dump device attributes */ 658 - 659 - DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n", 660 - dump_block_fcp->ipl_info.fcp.wwpn); 661 - DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n", 662 - dump_block_fcp->ipl_info.fcp.lun); 663 - DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", 664 - dump_block_fcp->ipl_info.fcp.bootprog); 665 - DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n", 666 - dump_block_fcp->ipl_info.fcp.br_lba); 667 - DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", 668 - dump_block_fcp->ipl_info.fcp.devno); 669 - 670 - static struct attribute *dump_fcp_attrs[] = { 671 - &sys_dump_fcp_device_attr.attr, 672 - &sys_dump_fcp_wwpn_attr.attr, 673 - &sys_dump_fcp_lun_attr.attr, 674 - &sys_dump_fcp_bootprog_attr.attr, 675 - &sys_dump_fcp_br_lba_attr.attr, 676 - NULL, 677 - }; 678 - 679 - static struct attribute_group dump_fcp_attr_group = { 680 - .name = IPL_FCP_STR, 681 - .attrs = dump_fcp_attrs, 682 - }; 683 - 684 - /* CCW dump device attributes */ 685 - 686 - DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 687 - dump_block_ccw->ipl_info.ccw.devno); 688 - 689 - static struct attribute *dump_ccw_attrs[] = { 690 - &sys_dump_ccw_device_attr.attr, 691 - NULL, 692 - }; 693 - 694 - static struct attribute_group dump_ccw_attr_group = { 695 - .name = IPL_CCW_STR, 696 - .attrs = dump_ccw_attrs, 697 - }; 698 - 699 - /* dump type */ 700 - 701 - static int dump_set_type(enum dump_type type) 702 - { 703 - if (!(dump_capabilities & type)) 704 - return -EINVAL; 705 - switch(type) { 706 - case DUMP_TYPE_CCW: 707 - if (MACHINE_IS_VM) 708 - dump_method = DUMP_METHOD_CCW_VM; 709 - else if (diag308_set_works) 710 - dump_method = DUMP_METHOD_CCW_DIAG; 711 - else 712 - dump_method = DUMP_METHOD_CCW_CIO; 713 - break; 714 - case DUMP_TYPE_FCP: 715 - dump_method = DUMP_METHOD_FCP_DIAG; 716 - break; 717 - default: 718 - dump_method = DUMP_METHOD_NONE; 719 - } 720 - dump_type = type; 721 - return 0; 722 - } 723 - 724 - static ssize_t dump_type_show(struct kobject *kobj, 725 - struct kobj_attribute *attr, char *page) 726 - { 727 - return sprintf(page, "%s\n", dump_type_str(dump_type)); 728 - } 729 - 730 - static ssize_t dump_type_store(struct kobject *kobj, 731 - struct kobj_attribute *attr, 732 - const char *buf, size_t len) 733 - { 734 - int rc = -EINVAL; 735 - 736 - if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0) 737 - rc = dump_set_type(DUMP_TYPE_NONE); 738 - else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0) 739 - rc = dump_set_type(DUMP_TYPE_CCW); 740 - else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0) 741 - rc = dump_set_type(DUMP_TYPE_FCP); 742 - return (rc != 0) ? rc : len; 743 - } 744 - 745 - static struct kobj_attribute dump_type_attr = 746 - __ATTR(dump_type, 0644, dump_type_show, dump_type_store); 747 - 748 - static struct kset *dump_kset; 749 - 750 - /* 751 - * Shutdown actions section 752 - */ 753 - 754 - static struct kset *shutdown_actions_kset; 755 - 756 - /* on panic */ 757 - 758 - static ssize_t on_panic_show(struct kobject *kobj, 759 - struct kobj_attribute *attr, char *page) 760 - { 761 - return sprintf(page, "%s\n", shutdown_action_str(on_panic_action)); 762 - } 763 - 764 - static ssize_t on_panic_store(struct kobject *kobj, 765 - struct kobj_attribute *attr, 766 - const char *buf, size_t len) 767 - { 768 - if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0) 769 - on_panic_action = SHUTDOWN_REIPL; 770 - else if (strncmp(buf, SHUTDOWN_DUMP_STR, 771 - strlen(SHUTDOWN_DUMP_STR)) == 0) 772 - on_panic_action = SHUTDOWN_DUMP; 773 - else if (strncmp(buf, SHUTDOWN_STOP_STR, 774 - strlen(SHUTDOWN_STOP_STR)) == 0) 775 - on_panic_action = SHUTDOWN_STOP; 776 - else 777 - return -EINVAL; 778 - 779 - return len; 780 - } 781 - 782 - static struct kobj_attribute on_panic_attr = 783 - __ATTR(on_panic, 0644, on_panic_show, on_panic_store); 784 - 785 - void do_reipl(void) 607 + void reipl_run(struct shutdown_trigger *trigger) 786 608 { 787 609 struct ccw_dev_id devid; 788 610 static char buf[100]; ··· 701 787 default: 702 788 break; 703 789 } 704 - signal_processor(smp_processor_id(), sigp_stop_and_store_status); 705 - } 706 - 707 - static void do_dump(void) 708 - { 709 - struct ccw_dev_id devid; 710 - static char buf[100]; 711 - 712 - switch (dump_method) { 713 - case DUMP_METHOD_CCW_CIO: 714 - smp_send_stop(); 715 - devid.devno = dump_block_ccw->ipl_info.ccw.devno; 716 - devid.ssid = 0; 717 - reipl_ccw_dev(&devid); 718 - break; 719 - case DUMP_METHOD_CCW_VM: 720 - smp_send_stop(); 721 - sprintf(buf, "STORE STATUS"); 722 - __cpcmd(buf, NULL, 0, NULL); 723 - sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); 724 - __cpcmd(buf, NULL, 0, NULL); 725 - break; 726 - case DUMP_METHOD_CCW_DIAG: 727 - diag308(DIAG308_SET, dump_block_ccw); 728 - diag308(DIAG308_DUMP, NULL); 729 - break; 730 - case DUMP_METHOD_FCP_DIAG: 731 - diag308(DIAG308_SET, dump_block_fcp); 732 - diag308(DIAG308_DUMP, NULL); 733 - break; 734 - case DUMP_METHOD_NONE: 735 - default: 736 - return; 737 - } 738 - printk(KERN_EMERG "Dump failed!\n"); 739 - } 740 - 741 - /* init functions */ 742 - 743 - static int __init ipl_register_fcp_files(void) 744 - { 745 - int rc; 746 - 747 - rc = sysfs_create_group(&ipl_kset->kobj, 748 - &ipl_fcp_attr_group); 749 - if (rc) 750 - goto out; 751 - rc = sysfs_create_bin_file(&ipl_kset->kobj, 752 - &ipl_parameter_attr); 753 - if (rc) 754 - goto out_ipl_parm; 755 - rc = sysfs_create_bin_file(&ipl_kset->kobj, 756 - &ipl_scp_data_attr); 757 - if (!rc) 758 - goto out; 759 - 760 - sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr); 761 - 762 - out_ipl_parm: 763 - sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group); 764 - out: 765 - return rc; 766 - } 767 - 768 - static int __init ipl_init(void) 769 - { 770 - int rc; 771 - 772 - ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj); 773 - if (!ipl_kset) 774 - return -ENOMEM; 775 - switch (ipl_info.type) { 776 - case IPL_TYPE_CCW: 777 - rc = sysfs_create_group(&ipl_kset->kobj, 778 - &ipl_ccw_attr_group); 779 - break; 780 - case IPL_TYPE_FCP: 781 - case IPL_TYPE_FCP_DUMP: 782 - rc = ipl_register_fcp_files(); 783 - break; 784 - case IPL_TYPE_NSS: 785 - rc = sysfs_create_group(&ipl_kset->kobj, 786 - &ipl_nss_attr_group); 787 - break; 788 - default: 789 - rc = sysfs_create_group(&ipl_kset->kobj, 790 - &ipl_unknown_attr_group); 791 - break; 792 - } 793 - if (rc) 794 - kset_unregister(ipl_kset); 795 - return rc; 796 790 } 797 791 798 792 static void __init reipl_probe(void) ··· 792 970 return 0; 793 971 } 794 972 795 - static int __init reipl_init(void) 973 + static int reipl_init(void) 796 974 { 797 975 int rc; 798 976 ··· 817 995 if (rc) 818 996 return rc; 819 997 return 0; 998 + } 999 + 1000 + static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR, 1001 + reipl_run, reipl_init}; 1002 + 1003 + /* 1004 + * dump shutdown action: Dump Linux on shutdown. 1005 + */ 1006 + 1007 + /* FCP dump device attributes */ 1008 + 1009 + DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n", 1010 + dump_block_fcp->ipl_info.fcp.wwpn); 1011 + DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n", 1012 + dump_block_fcp->ipl_info.fcp.lun); 1013 + DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", 1014 + dump_block_fcp->ipl_info.fcp.bootprog); 1015 + DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n", 1016 + dump_block_fcp->ipl_info.fcp.br_lba); 1017 + DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", 1018 + dump_block_fcp->ipl_info.fcp.devno); 1019 + 1020 + static struct attribute *dump_fcp_attrs[] = { 1021 + &sys_dump_fcp_device_attr.attr, 1022 + &sys_dump_fcp_wwpn_attr.attr, 1023 + &sys_dump_fcp_lun_attr.attr, 1024 + &sys_dump_fcp_bootprog_attr.attr, 1025 + &sys_dump_fcp_br_lba_attr.attr, 1026 + NULL, 1027 + }; 1028 + 1029 + static struct attribute_group dump_fcp_attr_group = { 1030 + .name = IPL_FCP_STR, 1031 + .attrs = dump_fcp_attrs, 1032 + }; 1033 + 1034 + /* CCW dump device attributes */ 1035 + 1036 + DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", 1037 + dump_block_ccw->ipl_info.ccw.devno); 1038 + 1039 + static struct attribute *dump_ccw_attrs[] = { 1040 + &sys_dump_ccw_device_attr.attr, 1041 + NULL, 1042 + }; 1043 + 1044 + static struct attribute_group dump_ccw_attr_group = { 1045 + .name = IPL_CCW_STR, 1046 + .attrs = dump_ccw_attrs, 1047 + }; 1048 + 1049 + /* dump type */ 1050 + 1051 + static int dump_set_type(enum dump_type type) 1052 + { 1053 + if (!(dump_capabilities & type)) 1054 + return -EINVAL; 1055 + switch (type) { 1056 + case DUMP_TYPE_CCW: 1057 + if (MACHINE_IS_VM) 1058 + dump_method = DUMP_METHOD_CCW_VM; 1059 + else 1060 + dump_method = DUMP_METHOD_CCW_CIO; 1061 + break; 1062 + case DUMP_TYPE_FCP: 1063 + dump_method = DUMP_METHOD_FCP_DIAG; 1064 + break; 1065 + default: 1066 + dump_method = DUMP_METHOD_NONE; 1067 + } 1068 + dump_type = type; 1069 + return 0; 1070 + } 1071 + 1072 + static ssize_t dump_type_show(struct kobject *kobj, 1073 + struct kobj_attribute *attr, char *page) 1074 + { 1075 + return sprintf(page, "%s\n", dump_type_str(dump_type)); 1076 + } 1077 + 1078 + static ssize_t dump_type_store(struct kobject *kobj, 1079 + struct kobj_attribute *attr, 1080 + const char *buf, size_t len) 1081 + { 1082 + int rc = -EINVAL; 1083 + 1084 + if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0) 1085 + rc = dump_set_type(DUMP_TYPE_NONE); 1086 + else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0) 1087 + rc = dump_set_type(DUMP_TYPE_CCW); 1088 + else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0) 1089 + rc = dump_set_type(DUMP_TYPE_FCP); 1090 + return (rc != 0) ? rc : len; 1091 + } 1092 + 1093 + static struct kobj_attribute dump_type_attr = 1094 + __ATTR(dump_type, 0644, dump_type_show, dump_type_store); 1095 + 1096 + static struct kset *dump_kset; 1097 + 1098 + static void dump_run(struct shutdown_trigger *trigger) 1099 + { 1100 + struct ccw_dev_id devid; 1101 + static char buf[100]; 1102 + 1103 + switch (dump_method) { 1104 + case DUMP_METHOD_CCW_CIO: 1105 + smp_send_stop(); 1106 + devid.devno = dump_block_ccw->ipl_info.ccw.devno; 1107 + devid.ssid = 0; 1108 + reipl_ccw_dev(&devid); 1109 + break; 1110 + case DUMP_METHOD_CCW_VM: 1111 + smp_send_stop(); 1112 + sprintf(buf, "STORE STATUS"); 1113 + __cpcmd(buf, NULL, 0, NULL); 1114 + sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); 1115 + __cpcmd(buf, NULL, 0, NULL); 1116 + break; 1117 + case DUMP_METHOD_CCW_DIAG: 1118 + diag308(DIAG308_SET, dump_block_ccw); 1119 + diag308(DIAG308_DUMP, NULL); 1120 + break; 1121 + case DUMP_METHOD_FCP_DIAG: 1122 + diag308(DIAG308_SET, dump_block_fcp); 1123 + diag308(DIAG308_DUMP, NULL); 1124 + break; 1125 + case DUMP_METHOD_NONE: 1126 + default: 1127 + return; 1128 + } 1129 + printk(KERN_EMERG "Dump failed!\n"); 820 1130 } 821 1131 822 1132 static int __init dump_ccw_init(void) ··· 996 1042 return 0; 997 1043 } 998 1044 999 - #define SHUTDOWN_ON_PANIC_PRIO 0 1000 - 1001 - static int shutdown_on_panic_notify(struct notifier_block *self, 1002 - unsigned long event, void *data) 1003 - { 1004 - if (on_panic_action == SHUTDOWN_DUMP) 1005 - do_dump(); 1006 - else if (on_panic_action == SHUTDOWN_REIPL) 1007 - do_reipl(); 1008 - return NOTIFY_OK; 1009 - } 1010 - 1011 - static struct notifier_block shutdown_on_panic_nb = { 1012 - .notifier_call = shutdown_on_panic_notify, 1013 - .priority = SHUTDOWN_ON_PANIC_PRIO 1014 - }; 1015 - 1016 - static int __init dump_init(void) 1045 + static int dump_init(void) 1017 1046 { 1018 1047 int rc; 1019 1048 1020 1049 dump_kset = kset_create_and_add("dump", NULL, firmware_kobj); 1021 1050 if (!dump_kset) 1022 1051 return -ENOMEM; 1023 - rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr); 1052 + rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr); 1024 1053 if (rc) { 1025 1054 kset_unregister(dump_kset); 1026 1055 return rc; ··· 1018 1081 return 0; 1019 1082 } 1020 1083 1021 - static int __init shutdown_actions_init(void) 1022 - { 1023 - int rc; 1084 + static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR, 1085 + dump_run, dump_init}; 1024 1086 1087 + /* 1088 + * vmcmd shutdown action: Trigger vm command on shutdown. 1089 + */ 1090 + 1091 + static char vmcmd_on_reboot[128]; 1092 + static char vmcmd_on_panic[128]; 1093 + static char vmcmd_on_halt[128]; 1094 + static char vmcmd_on_poff[128]; 1095 + 1096 + DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot); 1097 + DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic); 1098 + DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt); 1099 + DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff); 1100 + 1101 + static struct attribute *vmcmd_attrs[] = { 1102 + &sys_vmcmd_on_reboot_attr.attr, 1103 + &sys_vmcmd_on_panic_attr.attr, 1104 + &sys_vmcmd_on_halt_attr.attr, 1105 + &sys_vmcmd_on_poff_attr.attr, 1106 + NULL, 1107 + }; 1108 + 1109 + static struct attribute_group vmcmd_attr_group = { 1110 + .attrs = vmcmd_attrs, 1111 + }; 1112 + 1113 + static struct kset *vmcmd_kset; 1114 + 1115 + static void vmcmd_run(struct shutdown_trigger *trigger) 1116 + { 1117 + char *cmd, *next_cmd; 1118 + 1119 + if (strcmp(trigger->name, ON_REIPL_STR) == 0) 1120 + cmd = vmcmd_on_reboot; 1121 + else if (strcmp(trigger->name, ON_PANIC_STR) == 0) 1122 + cmd = vmcmd_on_panic; 1123 + else if (strcmp(trigger->name, ON_HALT_STR) == 0) 1124 + cmd = vmcmd_on_halt; 1125 + else if (strcmp(trigger->name, ON_POFF_STR) == 0) 1126 + cmd = vmcmd_on_poff; 1127 + else 1128 + return; 1129 + 1130 + if (strlen(cmd) == 0) 1131 + return; 1132 + do { 1133 + next_cmd = strchr(cmd, '\n'); 1134 + if (next_cmd) { 1135 + next_cmd[0] = 0; 1136 + next_cmd += 1; 1137 + } 1138 + __cpcmd(cmd, NULL, 0, NULL); 1139 + cmd = next_cmd; 1140 + } while (cmd != NULL); 1141 + } 1142 + 1143 + static int vmcmd_init(void) 1144 + { 1145 + if (!MACHINE_IS_VM) 1146 + return -ENOTSUPP; 1147 + vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj); 1148 + if (!vmcmd_kset) 1149 + return -ENOMEM; 1150 + return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group); 1151 + } 1152 + 1153 + static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR, 1154 + vmcmd_run, vmcmd_init}; 1155 + 1156 + /* 1157 + * stop shutdown action: Stop Linux on shutdown. 1158 + */ 1159 + 1160 + static void stop_run(struct shutdown_trigger *trigger) 1161 + { 1162 + signal_processor(smp_processor_id(), sigp_stop_and_store_status); 1163 + for (;;); 1164 + } 1165 + 1166 + static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, 1167 + stop_run, NULL}; 1168 + 1169 + /* action list */ 1170 + 1171 + static struct shutdown_action *shutdown_actions_list[] = { 1172 + &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; 1173 + #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) 1174 + 1175 + /* 1176 + * Trigger section 1177 + */ 1178 + 1179 + static struct kset *shutdown_actions_kset; 1180 + 1181 + static int set_trigger(const char *buf, struct shutdown_trigger *trigger, 1182 + size_t len) 1183 + { 1184 + int i; 1185 + for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { 1186 + if (!shutdown_actions_list[i]) 1187 + continue; 1188 + if (strncmp(buf, shutdown_actions_list[i]->name, 1189 + strlen(shutdown_actions_list[i]->name)) == 0) { 1190 + trigger->action = shutdown_actions_list[i]; 1191 + return len; 1192 + } 1193 + } 1194 + return -EINVAL; 1195 + } 1196 + 1197 + /* on reipl */ 1198 + 1199 + static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR, 1200 + &reipl_action}; 1201 + 1202 + static ssize_t on_reboot_show(struct kobject *kobj, 1203 + struct kobj_attribute *attr, char *page) 1204 + { 1205 + return sprintf(page, "%s\n", on_reboot_trigger.action->name); 1206 + } 1207 + 1208 + static ssize_t on_reboot_store(struct kobject *kobj, 1209 + struct kobj_attribute *attr, 1210 + const char *buf, size_t len) 1211 + { 1212 + return set_trigger(buf, &on_reboot_trigger, len); 1213 + } 1214 + 1215 + static struct kobj_attribute on_reboot_attr = 1216 + __ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store); 1217 + 1218 + static void do_machine_restart(char *__unused) 1219 + { 1220 + smp_send_stop(); 1221 + on_reboot_trigger.action->fn(&on_reboot_trigger); 1222 + reipl_run(NULL); 1223 + } 1224 + void (*_machine_restart)(char *command) = do_machine_restart; 1225 + 1226 + /* on panic */ 1227 + 1228 + static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action}; 1229 + 1230 + static ssize_t on_panic_show(struct kobject *kobj, 1231 + struct kobj_attribute *attr, char *page) 1232 + { 1233 + return sprintf(page, "%s\n", on_panic_trigger.action->name); 1234 + } 1235 + 1236 + static ssize_t on_panic_store(struct kobject *kobj, 1237 + struct kobj_attribute *attr, 1238 + const char *buf, size_t len) 1239 + { 1240 + return set_trigger(buf, &on_panic_trigger, len); 1241 + } 1242 + 1243 + static struct kobj_attribute on_panic_attr = 1244 + __ATTR(on_panic, 0644, on_panic_show, on_panic_store); 1245 + 1246 + static void do_panic(void) 1247 + { 1248 + on_panic_trigger.action->fn(&on_panic_trigger); 1249 + stop_run(&on_panic_trigger); 1250 + } 1251 + 1252 + /* on halt */ 1253 + 1254 + static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; 1255 + 1256 + static ssize_t on_halt_show(struct kobject *kobj, 1257 + struct kobj_attribute *attr, char *page) 1258 + { 1259 + return sprintf(page, "%s\n", on_halt_trigger.action->name); 1260 + } 1261 + 1262 + static ssize_t on_halt_store(struct kobject *kobj, 1263 + struct kobj_attribute *attr, 1264 + const char *buf, size_t len) 1265 + { 1266 + return set_trigger(buf, &on_halt_trigger, len); 1267 + } 1268 + 1269 + static struct kobj_attribute on_halt_attr = 1270 + __ATTR(on_halt, 0644, on_halt_show, on_halt_store); 1271 + 1272 + 1273 + static void do_machine_halt(void) 1274 + { 1275 + smp_send_stop(); 1276 + on_halt_trigger.action->fn(&on_halt_trigger); 1277 + stop_run(&on_halt_trigger); 1278 + } 1279 + void (*_machine_halt)(void) = do_machine_halt; 1280 + 1281 + /* on power off */ 1282 + 1283 + static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action}; 1284 + 1285 + static ssize_t on_poff_show(struct kobject *kobj, 1286 + struct kobj_attribute *attr, char *page) 1287 + { 1288 + return sprintf(page, "%s\n", on_poff_trigger.action->name); 1289 + } 1290 + 1291 + static ssize_t on_poff_store(struct kobject *kobj, 1292 + struct kobj_attribute *attr, 1293 + const char *buf, size_t len) 1294 + { 1295 + return set_trigger(buf, &on_poff_trigger, len); 1296 + } 1297 + 1298 + static struct kobj_attribute on_poff_attr = 1299 + __ATTR(on_poff, 0644, on_poff_show, on_poff_store); 1300 + 1301 + 1302 + static void do_machine_power_off(void) 1303 + { 1304 + smp_send_stop(); 1305 + on_poff_trigger.action->fn(&on_poff_trigger); 1306 + stop_run(&on_poff_trigger); 1307 + } 1308 + void (*_machine_power_off)(void) = do_machine_power_off; 1309 + 1310 + static void __init shutdown_triggers_init(void) 1311 + { 1025 1312 shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL, 1026 1313 firmware_kobj); 1027 1314 if (!shutdown_actions_kset) 1028 - return -ENOMEM; 1029 - rc = sysfs_create_file(&shutdown_actions_kset->kobj, &on_panic_attr); 1030 - if (rc) { 1031 - kset_unregister(shutdown_actions_kset); 1032 - return rc; 1315 + goto fail; 1316 + if (sysfs_create_file(&shutdown_actions_kset->kobj, 1317 + &on_reboot_attr.attr)) 1318 + goto fail; 1319 + if (sysfs_create_file(&shutdown_actions_kset->kobj, 1320 + &on_panic_attr.attr)) 1321 + goto fail; 1322 + if (sysfs_create_file(&shutdown_actions_kset->kobj, 1323 + &on_halt_attr.attr)) 1324 + goto fail; 1325 + if (sysfs_create_file(&shutdown_actions_kset->kobj, 1326 + &on_poff_attr.attr)) 1327 + goto fail; 1328 + 1329 + return; 1330 + fail: 1331 + panic("shutdown_triggers_init failed\n"); 1332 + } 1333 + 1334 + static void __init shutdown_actions_init(void) 1335 + { 1336 + int i; 1337 + 1338 + for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { 1339 + if (!shutdown_actions_list[i]->init) 1340 + continue; 1341 + if (shutdown_actions_list[i]->init()) 1342 + shutdown_actions_list[i] = NULL; 1033 1343 } 1034 - atomic_notifier_chain_register(&panic_notifier_list, 1035 - &shutdown_on_panic_nb); 1036 - return 0; 1037 1344 } 1038 1345 1039 1346 static int __init s390_ipl_init(void) 1040 1347 { 1041 - int rc; 1042 - 1043 - sclp_get_ipl_info(&sclp_ipl_info); 1044 1348 reipl_probe(); 1045 - rc = ipl_init(); 1046 - if (rc) 1047 - return rc; 1048 - rc = reipl_init(); 1049 - if (rc) 1050 - return rc; 1051 - rc = dump_init(); 1052 - if (rc) 1053 - return rc; 1054 - rc = shutdown_actions_init(); 1055 - if (rc) 1056 - return rc; 1349 + shutdown_actions_init(); 1350 + shutdown_triggers_init(); 1057 1351 return 0; 1058 1352 } 1059 1353 1060 1354 __initcall(s390_ipl_init); 1355 + 1356 + static void __init strncpy_skip_quote(char *dst, char *src, int n) 1357 + { 1358 + int sx, dx; 1359 + 1360 + dx = 0; 1361 + for (sx = 0; src[sx] != 0; sx++) { 1362 + if (src[sx] == '"') 1363 + continue; 1364 + dst[dx++] = src[sx]; 1365 + if (dx >= n) 1366 + break; 1367 + } 1368 + } 1369 + 1370 + static int __init vmcmd_on_reboot_setup(char *str) 1371 + { 1372 + if (!MACHINE_IS_VM) 1373 + return 1; 1374 + strncpy_skip_quote(vmcmd_on_reboot, str, 127); 1375 + vmcmd_on_reboot[127] = 0; 1376 + on_reboot_trigger.action = &vmcmd_action; 1377 + return 1; 1378 + } 1379 + __setup("vmreboot=", vmcmd_on_reboot_setup); 1380 + 1381 + static int __init vmcmd_on_panic_setup(char *str) 1382 + { 1383 + if (!MACHINE_IS_VM) 1384 + return 1; 1385 + strncpy_skip_quote(vmcmd_on_panic, str, 127); 1386 + vmcmd_on_panic[127] = 0; 1387 + on_panic_trigger.action = &vmcmd_action; 1388 + return 1; 1389 + } 1390 + __setup("vmpanic=", vmcmd_on_panic_setup); 1391 + 1392 + static int __init vmcmd_on_halt_setup(char *str) 1393 + { 1394 + if (!MACHINE_IS_VM) 1395 + return 1; 1396 + strncpy_skip_quote(vmcmd_on_halt, str, 127); 1397 + vmcmd_on_halt[127] = 0; 1398 + on_halt_trigger.action = &vmcmd_action; 1399 + return 1; 1400 + } 1401 + __setup("vmhalt=", vmcmd_on_halt_setup); 1402 + 1403 + static int __init vmcmd_on_poff_setup(char *str) 1404 + { 1405 + if (!MACHINE_IS_VM) 1406 + return 1; 1407 + strncpy_skip_quote(vmcmd_on_poff, str, 127); 1408 + vmcmd_on_poff[127] = 0; 1409 + on_poff_trigger.action = &vmcmd_action; 1410 + return 1; 1411 + } 1412 + __setup("vmpoff=", vmcmd_on_poff_setup); 1413 + 1414 + static int on_panic_notify(struct notifier_block *self, 1415 + unsigned long event, void *data) 1416 + { 1417 + do_panic(); 1418 + return NOTIFY_OK; 1419 + } 1420 + 1421 + static struct notifier_block on_panic_nb = { 1422 + .notifier_call = on_panic_notify, 1423 + .priority = 0, 1424 + }; 1425 + 1426 + void __init setup_ipl(void) 1427 + { 1428 + ipl_info.type = get_ipl_type(); 1429 + switch (ipl_info.type) { 1430 + case IPL_TYPE_CCW: 1431 + ipl_info.data.ccw.dev_id.devno = ipl_devno; 1432 + ipl_info.data.ccw.dev_id.ssid = 0; 1433 + break; 1434 + case IPL_TYPE_FCP: 1435 + case IPL_TYPE_FCP_DUMP: 1436 + ipl_info.data.fcp.dev_id.devno = 1437 + IPL_PARMBLOCK_START->ipl_info.fcp.devno; 1438 + ipl_info.data.fcp.dev_id.ssid = 0; 1439 + ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn; 1440 + ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun; 1441 + break; 1442 + case IPL_TYPE_NSS: 1443 + strncpy(ipl_info.data.nss.name, kernel_nss_name, 1444 + sizeof(ipl_info.data.nss.name)); 1445 + break; 1446 + case IPL_TYPE_UNKNOWN: 1447 + default: 1448 + /* We have no info to copy */ 1449 + break; 1450 + } 1451 + atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 1452 + } 1061 1453 1062 1454 void __init ipl_save_parameters(void) 1063 1455 { ··· 1468 1202 1469 1203 do_reset_calls(); 1470 1204 } 1205 +
+1 -102
arch/s390/kernel/setup.c
··· 126 126 } 127 127 128 128 /* 129 - * VM halt and poweroff setup routines 130 - */ 131 - char vmhalt_cmd[128] = ""; 132 - char vmpoff_cmd[128] = ""; 133 - static char vmpanic_cmd[128] = ""; 134 - 135 - static 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 - 147 - static 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 - 156 - static 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 - 165 - static 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 - 176 - static struct notifier_block vmpanic_nb = { 177 - .notifier_call = vmpanic_notify, 178 - .priority = PANIC_PRI_VMPANIC 179 - }; 180 - 181 - static 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 129 * condev= and conmode= setup parameter. 199 130 */ 200 131 ··· 238 307 #else 239 308 static inline void setup_zfcpdump(unsigned int console_devno) {} 240 309 #endif /* CONFIG_ZFCPDUMP */ 241 - 242 - #ifdef CONFIG_SMP 243 - void (*_machine_restart)(char *command) = machine_restart_smp; 244 - void (*_machine_halt)(void) = machine_halt_smp; 245 - void (*_machine_power_off)(void) = machine_power_off_smp; 246 - #else 247 - /* 248 - * Reboot, halt and power_off routines for non SMP. 249 - */ 250 - static void do_machine_restart_nonsmp(char * __unused) 251 - { 252 - do_reipl(); 253 - } 254 - 255 - static void do_machine_halt_nonsmp(void) 256 - { 257 - if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 258 - __cpcmd(vmhalt_cmd, NULL, 0, NULL); 259 - signal_processor(smp_processor_id(), sigp_stop_and_store_status); 260 - } 261 - 262 - static void do_machine_power_off_nonsmp(void) 263 - { 264 - if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) 265 - __cpcmd(vmpoff_cmd, NULL, 0, NULL); 266 - signal_processor(smp_processor_id(), sigp_stop_and_store_status); 267 - } 268 - 269 - void (*_machine_restart)(char *command) = do_machine_restart_nonsmp; 270 - void (*_machine_halt)(void) = do_machine_halt_nonsmp; 271 - void (*_machine_power_off)(void) = do_machine_power_off_nonsmp; 272 - #endif 273 310 274 311 /* 275 312 * Reboot, halt and power_off stubs. They just call _machine_restart, ··· 812 913 813 914 parse_early_param(); 814 915 815 - setup_ipl_info(); 916 + setup_ipl(); 816 917 setup_memory_end(); 817 918 setup_addressing_mode(); 818 919 setup_memory();
-27
arch/s390/kernel/smp.c
··· 234 234 } 235 235 236 236 /* 237 - * Reboot, halt and power_off routines for SMP. 238 - */ 239 - void machine_restart_smp(char *__unused) 240 - { 241 - smp_send_stop(); 242 - do_reipl(); 243 - } 244 - 245 - void 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 - 254 - void 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 237 * This is the main routine where commands issued by other 265 238 * cpus are handled. 266 239 */
+3 -1
include/asm-s390/ipl.h
··· 83 83 extern unsigned int zfcpdump_prefix_array[]; 84 84 85 85 extern void do_reipl(void); 86 + extern void do_halt(void); 87 + extern void do_poff(void); 86 88 extern void ipl_save_parameters(void); 87 89 88 90 enum { ··· 120 118 }; 121 119 122 120 extern struct ipl_info ipl_info; 123 - extern void setup_ipl_info(void); 121 + extern void setup_ipl(void); 124 122 125 123 /* 126 124 * DIAG 308 support