aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2006-12-15 11:18:22 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-12-15 11:18:22 -0500
commita45e14148fb34175cba042df8979e7982758635f (patch)
tree10add976d1291f4172e95aea60e2c44594b9813d
parentb3c14d0bfd1739b930f26df90552a4d8cdcca0a6 (diff)
[S390] Fix reboot hang on LPARs
Reboot hangs on LPARs without diag308 support. The reason for this is, that before the reboot is done, the channel subsystem is shut down. During the reset on each possible subchannel a "store subchannel" is done. This operation can end in a program check interruption, if the specified subchannel set is not implemented by the hardware. During the reset, currently we do not have a program check handler, which leads to the described kernel bug. We install now a new program check handler for the reboot code to fix this problem. Signed-off-by: Michael Holzheu <holzheu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/ipl.c10
-rw-r--r--arch/s390/kernel/reset.S42
-rw-r--r--drivers/s390/cio/cio.c25
-rw-r--r--include/asm-s390/reset.h1
4 files changed, 75 insertions, 3 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index a36bea1188d..d2e6a0a56ad 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1037,13 +1037,15 @@ static void do_reset_calls(void)
1037} 1037}
1038 1038
1039extern void reset_mcck_handler(void); 1039extern void reset_mcck_handler(void);
1040extern void reset_pgm_handler(void);
1040 1041
1041void s390_reset_system(void) 1042void s390_reset_system(void)
1042{ 1043{
1043 struct _lowcore *lc; 1044 struct _lowcore *lc;
1044 1045
1045 /* Stack for interrupt/machine check handler */
1046 lc = (struct _lowcore *)(unsigned long) store_prefix(); 1046 lc = (struct _lowcore *)(unsigned long) store_prefix();
1047
1048 /* Stack for interrupt/machine check handler */
1047 lc->panic_stack = S390_lowcore.panic_stack; 1049 lc->panic_stack = S390_lowcore.panic_stack;
1048 1050
1049 /* Disable prefixing */ 1051 /* Disable prefixing */
@@ -1056,5 +1058,11 @@ void s390_reset_system(void)
1056 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; 1058 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
1057 S390_lowcore.mcck_new_psw.addr = 1059 S390_lowcore.mcck_new_psw.addr =
1058 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; 1060 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
1061
1062 /* Set new program check handler */
1063 S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
1064 S390_lowcore.program_new_psw.addr =
1065 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
1066
1059 do_reset_calls(); 1067 do_reset_calls();
1060} 1068}
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S
index be8688c0665..8a87355161f 100644
--- a/arch/s390/kernel/reset.S
+++ b/arch/s390/kernel/reset.S
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) IBM Corp. 2006 4 * Copyright (C) IBM Corp. 2006
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> 5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 * Michael Holzheu <holzheu@de.ibm.com>
6 */ 7 */
7 8
8#include <asm/ptrace.h> 9#include <asm/ptrace.h>
@@ -27,6 +28,26 @@ reset_mcck_handler:
27s390_reset_mcck_handler: 28s390_reset_mcck_handler:
28 .quad 0 29 .quad 0
29 30
31 .globl reset_pgm_handler
32reset_pgm_handler:
33 stmg %r0,%r15,__LC_SAVE_AREA
34 basr %r13,0
350: lg %r15,__LC_PANIC_STACK # load panic stack
36 aghi %r15,-STACK_FRAME_OVERHEAD
37 lg %r1,s390_reset_pgm_handler-0b(%r13)
38 ltgr %r1,%r1
39 jz 1f
40 basr %r14,%r1
41 lmg %r0,%r15,__LC_SAVE_AREA
42 lpswe __LC_PGM_OLD_PSW
431: lpswe disabled_wait_psw-0b(%r13)
44 .globl s390_reset_pgm_handler
45s390_reset_pgm_handler:
46 .quad 0
47 .align 8
48disabled_wait_psw:
49 .quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler
50
30#else /* CONFIG_64BIT */ 51#else /* CONFIG_64BIT */
31 52
32 .globl reset_mcck_handler 53 .globl reset_mcck_handler
@@ -45,4 +66,25 @@ reset_mcck_handler:
45s390_reset_mcck_handler: 66s390_reset_mcck_handler:
46 .long 0 67 .long 0
47 68
69 .globl reset_pgm_handler
70reset_pgm_handler:
71 stm %r0,%r15,__LC_SAVE_AREA
72 basr %r13,0
730: l %r15,__LC_PANIC_STACK # load panic stack
74 ahi %r15,-STACK_FRAME_OVERHEAD
75 l %r1,s390_reset_pgm_handler-0b(%r13)
76 ltr %r1,%r1
77 jz 1f
78 basr %r14,%r1
79 lm %r0,%r15,__LC_SAVE_AREA
80 lpsw __LC_PGM_OLD_PSW
81
821: lpsw disabled_wait_psw-0b(%r13)
83 .globl s390_reset_pgm_handler
84s390_reset_pgm_handler:
85 .long 0
86disabled_wait_psw:
87 .align 8
88 .long 0x000a0000,0x00000000 + reset_pgm_handler
89
48#endif /* CONFIG_64BIT */ 90#endif /* CONFIG_64BIT */
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 7835a714a40..3a403f195cf 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -871,11 +871,32 @@ __clear_subchannel_easy(struct subchannel_id schid)
871 return -EBUSY; 871 return -EBUSY;
872} 872}
873 873
874static int pgm_check_occured;
875
876static void cio_reset_pgm_check_handler(void)
877{
878 pgm_check_occured = 1;
879}
880
881static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
882{
883 int rc;
884
885 pgm_check_occured = 0;
886 s390_reset_pgm_handler = cio_reset_pgm_check_handler;
887 rc = stsch(schid, addr);
888 s390_reset_pgm_handler = NULL;
889 if (pgm_check_occured)
890 return -EIO;
891 else
892 return rc;
893}
894
874static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) 895static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
875{ 896{
876 struct schib schib; 897 struct schib schib;
877 898
878 if (stsch_err(schid, &schib)) 899 if (stsch_reset(schid, &schib))
879 return -ENXIO; 900 return -ENXIO;
880 if (!schib.pmcw.ena) 901 if (!schib.pmcw.ena)
881 return 0; 902 return 0;
@@ -972,7 +993,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
972 struct schib schib; 993 struct schib schib;
973 struct sch_match_id *match_id = data; 994 struct sch_match_id *match_id = data;
974 995
975 if (stsch_err(schid, &schib)) 996 if (stsch_reset(schid, &schib))
976 return -ENXIO; 997 return -ENXIO;
977 if (schib.pmcw.dnv && 998 if (schib.pmcw.dnv &&
978 (schib.pmcw.dev == match_id->devid.devno) && 999 (schib.pmcw.dev == match_id->devid.devno) &&
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h
index 9b439cf6780..532e65a2aaf 100644
--- a/include/asm-s390/reset.h
+++ b/include/asm-s390/reset.h
@@ -19,5 +19,6 @@ extern void register_reset_call(struct reset_call *reset);
19extern void unregister_reset_call(struct reset_call *reset); 19extern void unregister_reset_call(struct reset_call *reset);
20extern void s390_reset_system(void); 20extern void s390_reset_system(void);
21extern void (*s390_reset_mcck_handler)(void); 21extern void (*s390_reset_mcck_handler)(void);
22extern void (*s390_reset_pgm_handler)(void);
22 23
23#endif /* _ASM_S390_RESET_H */ 24#endif /* _ASM_S390_RESET_H */