Skip to content

Commit

Permalink
[S390] Fix reboot hang on LPARs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michael Holzheu authored and Martin Schwidefsky committed Dec 15, 2006
1 parent b3c14d0 commit a45e141
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 3 deletions.
10 changes: 9 additions & 1 deletion arch/s390/kernel/ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,13 +1037,15 @@ static void do_reset_calls(void)
}

extern void reset_mcck_handler(void);
extern void reset_pgm_handler(void);

void s390_reset_system(void)
{
struct _lowcore *lc;

/* Stack for interrupt/machine check handler */
lc = (struct _lowcore *)(unsigned long) store_prefix();

/* Stack for interrupt/machine check handler */
lc->panic_stack = S390_lowcore.panic_stack;

/* Disable prefixing */
Expand All @@ -1056,5 +1058,11 @@ void s390_reset_system(void)
S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
S390_lowcore.mcck_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;

/* Set new program check handler */
S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
S390_lowcore.program_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;

do_reset_calls();
}
42 changes: 42 additions & 0 deletions arch/s390/kernel/reset.S
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* Copyright (C) IBM Corp. 2006
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
*/

#include <asm/ptrace.h>
Expand All @@ -27,6 +28,26 @@ reset_mcck_handler:
s390_reset_mcck_handler:
.quad 0

.globl reset_pgm_handler
reset_pgm_handler:
stmg %r0,%r15,__LC_SAVE_AREA
basr %r13,0
0: lg %r15,__LC_PANIC_STACK # load panic stack
aghi %r15,-STACK_FRAME_OVERHEAD
lg %r1,s390_reset_pgm_handler-0b(%r13)
ltgr %r1,%r1
jz 1f
basr %r14,%r1
lmg %r0,%r15,__LC_SAVE_AREA
lpswe __LC_PGM_OLD_PSW
1: lpswe disabled_wait_psw-0b(%r13)
.globl s390_reset_pgm_handler
s390_reset_pgm_handler:
.quad 0
.align 8
disabled_wait_psw:
.quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler

#else /* CONFIG_64BIT */

.globl reset_mcck_handler
Expand All @@ -45,4 +66,25 @@ reset_mcck_handler:
s390_reset_mcck_handler:
.long 0

.globl reset_pgm_handler
reset_pgm_handler:
stm %r0,%r15,__LC_SAVE_AREA
basr %r13,0
0: l %r15,__LC_PANIC_STACK # load panic stack
ahi %r15,-STACK_FRAME_OVERHEAD
l %r1,s390_reset_pgm_handler-0b(%r13)
ltr %r1,%r1
jz 1f
basr %r14,%r1
lm %r0,%r15,__LC_SAVE_AREA
lpsw __LC_PGM_OLD_PSW

1: lpsw disabled_wait_psw-0b(%r13)
.globl s390_reset_pgm_handler
s390_reset_pgm_handler:
.long 0
disabled_wait_psw:
.align 8
.long 0x000a0000,0x00000000 + reset_pgm_handler

#endif /* CONFIG_64BIT */
25 changes: 23 additions & 2 deletions drivers/s390/cio/cio.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,11 +871,32 @@ __clear_subchannel_easy(struct subchannel_id schid)
return -EBUSY;
}

static int pgm_check_occured;

static void cio_reset_pgm_check_handler(void)
{
pgm_check_occured = 1;
}

static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
{
int rc;

pgm_check_occured = 0;
s390_reset_pgm_handler = cio_reset_pgm_check_handler;
rc = stsch(schid, addr);
s390_reset_pgm_handler = NULL;
if (pgm_check_occured)
return -EIO;
else
return rc;
}

static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
{
struct schib schib;

if (stsch_err(schid, &schib))
if (stsch_reset(schid, &schib))
return -ENXIO;
if (!schib.pmcw.ena)
return 0;
Expand Down Expand Up @@ -972,7 +993,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
struct schib schib;
struct sch_match_id *match_id = data;

if (stsch_err(schid, &schib))
if (stsch_reset(schid, &schib))
return -ENXIO;
if (schib.pmcw.dnv &&
(schib.pmcw.dev == match_id->devid.devno) &&
Expand Down
1 change: 1 addition & 0 deletions include/asm-s390/reset.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ extern void register_reset_call(struct reset_call *reset);
extern void unregister_reset_call(struct reset_call *reset);
extern void s390_reset_system(void);
extern void (*s390_reset_mcck_handler)(void);
extern void (*s390_reset_pgm_handler)(void);

#endif /* _ASM_S390_RESET_H */

0 comments on commit a45e141

Please sign in to comment.