aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2006-12-04 09:40:26 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-12-04 09:40:26 -0500
commit15e9b586e0bd3692e2a21c5be178810d9d32214e (patch)
tree8bcf2c9b3780281c9562eab965e3ca6ba64e5bc0
parent2254f5a7779452395e37ea2f7d6e1a550d34e678 (diff)
[S390] Reset infrastructure for re-IPL.
In case of re-IPL and diag308 doesn't work we have to reset all devices manually and wait synchronously that each reset finished. This patch adds the necessary infrastucture and the first exploiter of it. Subsystems that need to add a function that needs to be called at re-IPL may register/unregister this function via struct reset_call { struct reset_call *next; void (*fn)(void); }; void register_reset_call(struct reset_call *reset); void unregister_reset_call(struct reset_call *reset); When the registered function get called the context is: - all cpus beside the current one are stopped - all machine checks and interrupts are disabled - prefixing is disabled - a default machine check handler is available for use The registered functions may not take any locks are sleep. For the common I/O layer part of this patch: Introduce a reset_call css_reset that does the following: - clear all subchannels - perform a rchp on all channel paths and wait for the resulting machine checks This replaces the calls to clear_all_subchannels() and cio_reset_channel_paths() for kexec and ccw reipl. reipl_ccw_dev() now uses reipl_find_schid() to determine the subchannel id for a given device id. Also remove cio_reset_channel_paths() and friends since they are not needed anymore. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/ipl.c54
-rw-r--r--arch/s390/kernel/machine_kexec.c9
-rw-r--r--arch/s390/kernel/reipl.S17
-rw-r--r--arch/s390/kernel/reipl64.S16
-rw-r--r--arch/s390/kernel/relocate_kernel.S5
-rw-r--r--arch/s390/kernel/relocate_kernel64.S5
-rw-r--r--arch/s390/kernel/reset.S48
-rw-r--r--drivers/s390/cio/chsc.c35
-rw-r--r--drivers/s390/cio/cio.c128
-rw-r--r--include/asm-s390/cio.h4
-rw-r--r--include/asm-s390/lowcore.h8
-rw-r--r--include/asm-s390/reset.h23
13 files changed, 246 insertions, 108 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index aa978978d3d1..a81881c9b297 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -4,7 +4,7 @@
4 4
5EXTRA_AFLAGS := -traditional 5EXTRA_AFLAGS := -traditional
6 6
7obj-y := bitmap.o traps.o time.o process.o \ 7obj-y := bitmap.o traps.o time.o process.o reset.o \
8 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ 8 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
9 semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o 9 semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
10 10
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index ec127826f221..77f4aff630fe 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -19,6 +19,7 @@
19#include <asm/cpcmd.h> 19#include <asm/cpcmd.h>
20#include <asm/cio.h> 20#include <asm/cio.h>
21#include <asm/ebcdic.h> 21#include <asm/ebcdic.h>
22#include <asm/reset.h>
22 23
23#define IPL_PARM_BLOCK_VERSION 0 24#define IPL_PARM_BLOCK_VERSION 0
24#define LOADPARM_LEN 8 25#define LOADPARM_LEN 8
@@ -1024,3 +1025,56 @@ static int __init s390_ipl_init(void)
1024} 1025}
1025 1026
1026__initcall(s390_ipl_init); 1027__initcall(s390_ipl_init);
1028
1029static LIST_HEAD(rcall);
1030static DEFINE_MUTEX(rcall_mutex);
1031
1032void register_reset_call(struct reset_call *reset)
1033{
1034 mutex_lock(&rcall_mutex);
1035 list_add(&reset->list, &rcall);
1036 mutex_unlock(&rcall_mutex);
1037}
1038EXPORT_SYMBOL_GPL(register_reset_call);
1039
1040void unregister_reset_call(struct reset_call *reset)
1041{
1042 mutex_lock(&rcall_mutex);
1043 list_del(&reset->list);
1044 mutex_unlock(&rcall_mutex);
1045}
1046EXPORT_SYMBOL_GPL(unregister_reset_call);
1047
1048static void do_reset_calls(void)
1049{
1050 struct reset_call *reset;
1051
1052 list_for_each_entry(reset, &rcall, list)
1053 reset->fn();
1054}
1055
1056extern void reset_mcck_handler(void);
1057
1058void s390_reset_system(void)
1059{
1060 struct _lowcore *lc;
1061
1062 /* Disable all interrupts/machine checks */
1063 __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
1064
1065 /* Stack for interrupt/machine check handler */
1066 lc = (struct _lowcore *)(unsigned long) store_prefix();
1067 lc->panic_stack = S390_lowcore.panic_stack;
1068
1069 /* Disable prefixing */
1070 set_prefix(0);
1071
1072 /* Disable lowcore protection */
1073 __ctl_clear_bit(0,28);
1074
1075 /* Set new machine check handler */
1076 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
1077 S390_lowcore.mcck_new_psw.addr =
1078 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
1079 do_reset_calls();
1080}
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index 60b1ea9f946b..202bf1fdfe39 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -22,6 +22,7 @@
22#include <asm/pgalloc.h> 22#include <asm/pgalloc.h>
23#include <asm/system.h> 23#include <asm/system.h>
24#include <asm/smp.h> 24#include <asm/smp.h>
25#include <asm/reset.h>
25 26
26static void kexec_halt_all_cpus(void *); 27static void kexec_halt_all_cpus(void *);
27 28
@@ -62,12 +63,6 @@ machine_shutdown(void)
62NORET_TYPE void 63NORET_TYPE void
63machine_kexec(struct kimage *image) 64machine_kexec(struct kimage *image)
64{ 65{
65 clear_all_subchannels();
66 cio_reset_channel_paths();
67
68 /* Disable lowcore protection */
69 ctl_clear_bit(0,28);
70
71 on_each_cpu(kexec_halt_all_cpus, image, 0, 0); 66 on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
72 for (;;); 67 for (;;);
73} 68}
@@ -98,6 +93,8 @@ kexec_halt_all_cpus(void *kernel_image)
98 cpu_relax(); 93 cpu_relax();
99 } 94 }
100 95
96 s390_reset_system();
97
101 image = (struct kimage *) kernel_image; 98 image = (struct kimage *) kernel_image;
102 data_mover = (relocate_kernel_t) 99 data_mover = (relocate_kernel_t)
103 (page_to_pfn(image->control_code_page) << PAGE_SHIFT); 100 (page_to_pfn(image->control_code_page) << PAGE_SHIFT);
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index 0340477f3b08..f9434d42ce9f 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -11,19 +11,10 @@
11 .globl do_reipl_asm 11 .globl do_reipl_asm
12do_reipl_asm: basr %r13,0 12do_reipl_asm: basr %r13,0
13.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) 13.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
14 14.Lpg1: # do store status of all registers
15 # switch off lowcore protection
16
17.Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
18 stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13)
19 ni .Lctlsave1-.Lpg0(%r13),0xef
20 lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13)
21
22 # do store status of all registers
23 15
24 stm %r0,%r15,__LC_GPREGS_SAVE_AREA 16 stm %r0,%r15,__LC_GPREGS_SAVE_AREA
25 stctl %c0,%c15,__LC_CREGS_SAVE_AREA 17 stctl %c0,%c15,__LC_CREGS_SAVE_AREA
26 mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13)
27 stam %a0,%a15,__LC_AREGS_SAVE_AREA 18 stam %a0,%a15,__LC_AREGS_SAVE_AREA
28 stpx __LC_PREFIX_SAVE_AREA 19 stpx __LC_PREFIX_SAVE_AREA
29 stckc .Lclkcmp-.Lpg0(%r13) 20 stckc .Lclkcmp-.Lpg0(%r13)
@@ -56,8 +47,7 @@ do_reipl_asm: basr %r13,0
56.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 47.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
57 jz .L003 48 jz .L003
58 bas %r14,.Ldisab-.Lpg0(%r13) 49 bas %r14,.Ldisab-.Lpg0(%r13)
59.L003: spx .Lnull-.Lpg0(%r13) 50.L003: st %r1,__LC_SUBCHANNEL_ID
60 st %r1,__LC_SUBCHANNEL_ID
61 lpsw 0 51 lpsw 0
62 sigp 0,0,0(6) 52 sigp 0,0,0(6)
63.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) 53.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
@@ -65,9 +55,6 @@ do_reipl_asm: basr %r13,0
65 .align 8 55 .align 8
66.Lclkcmp: .quad 0x0000000000000000 56.Lclkcmp: .quad 0x0000000000000000
67.Lall: .long 0xff000000 57.Lall: .long 0xff000000
68.Lnull: .long 0x00000000
69.Lctlsave1: .long 0x00000000
70.Lctlsave2: .long 0x00000000
71 .align 8 58 .align 8
72.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 59.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
73.Lpcnew: .long 0x00080000,0x80000000+.Lecs 60.Lpcnew: .long 0x00080000,0x80000000+.Lecs
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
index de7435054f7c..f18ef260ca23 100644
--- a/arch/s390/kernel/reipl64.S
+++ b/arch/s390/kernel/reipl64.S
@@ -10,10 +10,10 @@
10#include <asm/lowcore.h> 10#include <asm/lowcore.h>
11 .globl do_reipl_asm 11 .globl do_reipl_asm
12do_reipl_asm: basr %r13,0 12do_reipl_asm: basr %r13,0
13.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
14.Lpg1: # do store status of all registers
13 15
14 # do store status of all registers 16 stg %r1,.Lregsave-.Lpg0(%r13)
15
16.Lpg0: stg %r1,.Lregsave-.Lpg0(%r13)
17 lghi %r1,0x1000 17 lghi %r1,0x1000
18 stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) 18 stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
19 lg %r0,.Lregsave-.Lpg0(%r13) 19 lg %r0,.Lregsave-.Lpg0(%r13)
@@ -27,11 +27,7 @@ do_reipl_asm: basr %r13,0
27 stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) 27 stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
28 stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) 28 stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
29 29
30 lpswe .Lnewpsw-.Lpg0(%r13) 30 lctlg %c6,%c6,.Lall-.Lpg0(%r13)
31.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
32 stctg %c0,%c0,.Lregsave-.Lpg0(%r13)
33 ni .Lregsave+4-.Lpg0(%r13),0xef
34 lctlg %c0,%c0,.Lregsave-.Lpg0(%r13)
35 lgr %r1,%r2 31 lgr %r1,%r2
36 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) 32 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
37 stsch .Lschib-.Lpg0(%r13) 33 stsch .Lschib-.Lpg0(%r13)
@@ -56,8 +52,7 @@ do_reipl_asm: basr %r13,0
56.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 52.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
57 jz .L003 53 jz .L003
58 bas %r14,.Ldisab-.Lpg0(%r13) 54 bas %r14,.Ldisab-.Lpg0(%r13)
59.L003: spx .Lnull-.Lpg0(%r13) 55.L003: st %r1,__LC_SUBCHANNEL_ID
60 st %r1,__LC_SUBCHANNEL_ID
61 lhi %r1,0 # mode 0 = esa 56 lhi %r1,0 # mode 0 = esa
62 slr %r0,%r0 # set cpuid to zero 57 slr %r0,%r0 # set cpuid to zero
63 sigp %r1,%r0,0x12 # switch to esa mode 58 sigp %r1,%r0,0x12 # switch to esa mode
@@ -70,7 +65,6 @@ do_reipl_asm: basr %r13,0
70.Lclkcmp: .quad 0x0000000000000000 65.Lclkcmp: .quad 0x0000000000000000
71.Lall: .quad 0x00000000ff000000 66.Lall: .quad 0x00000000ff000000
72.Lregsave: .quad 0x0000000000000000 67.Lregsave: .quad 0x0000000000000000
73.Lnull: .long 0x0000000000000000
74 .align 16 68 .align 16
75/* 69/*
76 * These addresses have to be 31 bit otherwise 70 * These addresses have to be 31 bit otherwise
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
index f9899ff2e5b0..3b456b80bcee 100644
--- a/arch/s390/kernel/relocate_kernel.S
+++ b/arch/s390/kernel/relocate_kernel.S
@@ -26,8 +26,7 @@
26 relocate_kernel: 26 relocate_kernel:
27 basr %r13,0 # base address 27 basr %r13,0 # base address
28 .base: 28 .base:
29 stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) 29 stnsm sys_msk-.base(%r13),0xfb # disable DAT
30 spx zero64-.base(%r13) # absolute addressing mode
31 stctl %c0,%c15,ctlregs-.base(%r13) 30 stctl %c0,%c15,ctlregs-.base(%r13)
32 stm %r0,%r15,gprregs-.base(%r13) 31 stm %r0,%r15,gprregs-.base(%r13)
33 la %r1,load_psw-.base(%r13) 32 la %r1,load_psw-.base(%r13)
@@ -97,8 +96,6 @@
97 lpsw 0 # hopefully start new kernel... 96 lpsw 0 # hopefully start new kernel...
98 97
99 .align 8 98 .align 8
100 zero64:
101 .quad 0
102 load_psw: 99 load_psw:
103 .long 0x00080000,0x80000000 100 .long 0x00080000,0x80000000
104 sys_msk: 101 sys_msk:
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
index 4fb443042d9c..1f9ea2067b59 100644
--- a/arch/s390/kernel/relocate_kernel64.S
+++ b/arch/s390/kernel/relocate_kernel64.S
@@ -27,8 +27,7 @@
27 relocate_kernel: 27 relocate_kernel:
28 basr %r13,0 # base address 28 basr %r13,0 # base address
29 .base: 29 .base:
30 stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs 30 stnsm sys_msk-.base(%r13),0xfb # disable DAT
31 spx zero64-.base(%r13) # absolute addressing mode
32 stctg %c0,%c15,ctlregs-.base(%r13) 31 stctg %c0,%c15,ctlregs-.base(%r13)
33 stmg %r0,%r15,gprregs-.base(%r13) 32 stmg %r0,%r15,gprregs-.base(%r13)
34 lghi %r0,3 33 lghi %r0,3
@@ -100,8 +99,6 @@
100 lpsw 0 # hopefully start new kernel... 99 lpsw 0 # hopefully start new kernel...
101 100
102 .align 8 101 .align 8
103 zero64:
104 .quad 0
105 load_psw: 102 load_psw:
106 .long 0x00080000,0x80000000 103 .long 0x00080000,0x80000000
107 sys_msk: 104 sys_msk:
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S
new file mode 100644
index 000000000000..be8688c0665c
--- /dev/null
+++ b/arch/s390/kernel/reset.S
@@ -0,0 +1,48 @@
1/*
2 * arch/s390/kernel/reset.S
3 *
4 * Copyright (C) IBM Corp. 2006
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */
7
8#include <asm/ptrace.h>
9#include <asm/lowcore.h>
10
11#ifdef CONFIG_64BIT
12
13 .globl reset_mcck_handler
14reset_mcck_handler:
15 basr %r13,0
160: lg %r15,__LC_PANIC_STACK # load panic stack
17 aghi %r15,-STACK_FRAME_OVERHEAD
18 lg %r1,s390_reset_mcck_handler-0b(%r13)
19 ltgr %r1,%r1
20 jz 1f
21 basr %r14,%r1
221: la %r1,4095
23 lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
24 lpswe __LC_MCK_OLD_PSW
25
26 .globl s390_reset_mcck_handler
27s390_reset_mcck_handler:
28 .quad 0
29
30#else /* CONFIG_64BIT */
31
32 .globl reset_mcck_handler
33reset_mcck_handler:
34 basr %r13,0
350: l %r15,__LC_PANIC_STACK # load panic stack
36 ahi %r15,-STACK_FRAME_OVERHEAD
37 l %r1,s390_reset_mcck_handler-0b(%r13)
38 ltr %r1,%r1
39 jz 1f
40 basr %r14,%r1
411: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
42 lpsw __LC_MCK_OLD_PSW
43
44 .globl s390_reset_mcck_handler
45s390_reset_mcck_handler:
46 .long 0
47
48#endif /* CONFIG_64BIT */
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 2d78f0f4a40f..9d92540bd99e 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1465,41 +1465,6 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no)
1465 return desc; 1465 return desc;
1466} 1466}
1467 1467
1468static int reset_channel_path(struct channel_path *chp)
1469{
1470 int cc;
1471
1472 cc = rchp(chp->id);
1473 switch (cc) {
1474 case 0:
1475 return 0;
1476 case 2:
1477 return -EBUSY;
1478 default:
1479 return -ENODEV;
1480 }
1481}
1482
1483static void reset_channel_paths_css(struct channel_subsystem *css)
1484{
1485 int i;
1486
1487 for (i = 0; i <= __MAX_CHPID; i++) {
1488 if (css->chps[i])
1489 reset_channel_path(css->chps[i]);
1490 }
1491}
1492
1493void cio_reset_channel_paths(void)
1494{
1495 int i;
1496
1497 for (i = 0; i <= __MAX_CSSID; i++) {
1498 if (css[i] && css[i]->valid)
1499 reset_channel_paths_css(css[i]);
1500 }
1501}
1502
1503static int __init 1468static int __init
1504chsc_alloc_sei_area(void) 1469chsc_alloc_sei_area(void)
1505{ 1470{
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 8936e460a807..20aee2783847 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -21,6 +21,7 @@
21#include <asm/irq.h> 21#include <asm/irq.h>
22#include <asm/irq_regs.h> 22#include <asm/irq_regs.h>
23#include <asm/setup.h> 23#include <asm/setup.h>
24#include <asm/reset.h>
24#include "airq.h" 25#include "airq.h"
25#include "cio.h" 26#include "cio.h"
26#include "css.h" 27#include "css.h"
@@ -28,6 +29,7 @@
28#include "ioasm.h" 29#include "ioasm.h"
29#include "blacklist.h" 30#include "blacklist.h"
30#include "cio_debug.h" 31#include "cio_debug.h"
32#include "../s390mach.h"
31 33
32debug_info_t *cio_debug_msg_id; 34debug_info_t *cio_debug_msg_id;
33debug_info_t *cio_debug_trace_id; 35debug_info_t *cio_debug_trace_id;
@@ -841,26 +843,12 @@ __clear_subchannel_easy(struct subchannel_id schid)
841 return -EBUSY; 843 return -EBUSY;
842} 844}
843 845
844struct sch_match_id { 846static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
845 struct subchannel_id schid;
846 struct ccw_dev_id devid;
847 int rc;
848};
849
850static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid,
851 void *data)
852{ 847{
853 struct schib schib; 848 struct schib schib;
854 struct sch_match_id *match_id = data;
855 849
856 if (stsch_err(schid, &schib)) 850 if (stsch_err(schid, &schib))
857 return -ENXIO; 851 return -ENXIO;
858 if (match_id && schib.pmcw.dnv &&
859 (schib.pmcw.dev == match_id->devid.devno) &&
860 (schid.ssid == match_id->devid.ssid)) {
861 match_id->schid = schid;
862 match_id->rc = 0;
863 }
864 if (!schib.pmcw.ena) 852 if (!schib.pmcw.ena)
865 return 0; 853 return 0;
866 switch(__disable_subchannel_easy(schid, &schib)) { 854 switch(__disable_subchannel_easy(schid, &schib)) {
@@ -876,27 +864,111 @@ static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid,
876 return 0; 864 return 0;
877} 865}
878 866
879static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, 867static atomic_t chpid_reset_count;
880 struct subchannel_id *schid) 868
869static void s390_reset_chpids_mcck_handler(void)
870{
871 struct crw crw;
872 struct mci *mci;
873
874 /* Check for pending channel report word. */
875 mci = (struct mci *)&S390_lowcore.mcck_interruption_code;
876 if (!mci->cp)
877 return;
878 /* Process channel report words. */
879 while (stcrw(&crw) == 0) {
880 /* Check for responses to RCHP. */
881 if (crw.slct && crw.rsc == CRW_RSC_CPATH)
882 atomic_dec(&chpid_reset_count);
883 }
884}
885
886#define RCHP_TIMEOUT (30 * USEC_PER_SEC)
887static void css_reset(void)
888{
889 int i, ret;
890 unsigned long long timeout;
891
892 /* Reset subchannels. */
893 for_each_subchannel(__shutdown_subchannel_easy, NULL);
894 /* Reset channel paths. */
895 s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
896 /* Enable channel report machine checks. */
897 __ctl_set_bit(14, 28);
898 /* Temporarily reenable machine checks. */
899 local_mcck_enable();
900 for (i = 0; i <= __MAX_CHPID; i++) {
901 ret = rchp(i);
902 if ((ret == 0) || (ret == 2))
903 /*
904 * rchp either succeeded, or another rchp is already
905 * in progress. In either case, we'll get a crw.
906 */
907 atomic_inc(&chpid_reset_count);
908 }
909 /* Wait for machine check for all channel paths. */
910 timeout = get_clock() + (RCHP_TIMEOUT << 12);
911 while (atomic_read(&chpid_reset_count) != 0) {
912 if (get_clock() > timeout)
913 break;
914 cpu_relax();
915 }
916 /* Disable machine checks again. */
917 local_mcck_disable();
918 /* Disable channel report machine checks. */
919 __ctl_clear_bit(14, 28);
920 s390_reset_mcck_handler = NULL;
921}
922
923static struct reset_call css_reset_call = {
924 .fn = css_reset,
925};
926
927static int __init init_css_reset_call(void)
928{
929 atomic_set(&chpid_reset_count, 0);
930 register_reset_call(&css_reset_call);
931 return 0;
932}
933
934arch_initcall(init_css_reset_call);
935
936struct sch_match_id {
937 struct subchannel_id schid;
938 struct ccw_dev_id devid;
939 int rc;
940};
941
942static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
943{
944 struct schib schib;
945 struct sch_match_id *match_id = data;
946
947 if (stsch_err(schid, &schib))
948 return -ENXIO;
949 if (schib.pmcw.dnv &&
950 (schib.pmcw.dev == match_id->devid.devno) &&
951 (schid.ssid == match_id->devid.ssid)) {
952 match_id->schid = schid;
953 match_id->rc = 0;
954 return 1;
955 }
956 return 0;
957}
958
959static int reipl_find_schid(struct ccw_dev_id *devid,
960 struct subchannel_id *schid)
881{ 961{
882 struct sch_match_id match_id; 962 struct sch_match_id match_id;
883 963
884 match_id.devid = *devid; 964 match_id.devid = *devid;
885 match_id.rc = -ENODEV; 965 match_id.rc = -ENODEV;
886 local_irq_disable(); 966 for_each_subchannel(__reipl_subchannel_match, &match_id);
887 for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id);
888 if (match_id.rc == 0) 967 if (match_id.rc == 0)
889 *schid = match_id.schid; 968 *schid = match_id.schid;
890 return match_id.rc; 969 return match_id.rc;
891} 970}
892 971
893
894void clear_all_subchannels(void)
895{
896 local_irq_disable();
897 for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL);
898}
899
900extern void do_reipl_asm(__u32 schid); 972extern void do_reipl_asm(__u32 schid);
901 973
902/* Make sure all subchannels are quiet before we re-ipl an lpar. */ 974/* Make sure all subchannels are quiet before we re-ipl an lpar. */
@@ -904,9 +976,9 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
904{ 976{
905 struct subchannel_id schid; 977 struct subchannel_id schid;
906 978
907 if (clear_all_subchannels_and_match(devid, &schid)) 979 s390_reset_system();
980 if (reipl_find_schid(devid, &schid) != 0)
908 panic("IPL Device not found\n"); 981 panic("IPL Device not found\n");
909 cio_reset_channel_paths();
910 do_reipl_asm(*((__u32*)&schid)); 982 do_reipl_asm(*((__u32*)&schid));
911} 983}
912 984
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 81287d86329d..cabd5bb74b5a 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -285,10 +285,6 @@ extern int diag210(struct diag210 *addr);
285 285
286extern void wait_cons_dev(void); 286extern void wait_cons_dev(void);
287 287
288extern void clear_all_subchannels(void);
289
290extern void cio_reset_channel_paths(void);
291
292extern void css_schedule_reprobe(void); 288extern void css_schedule_reprobe(void);
293 289
294extern void reipl_ccw_dev(struct ccw_dev_id *id); 290extern void reipl_ccw_dev(struct ccw_dev_id *id);
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 06583ed0bde7..74f7389bd3ee 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -362,6 +362,14 @@ static inline void set_prefix(__u32 address)
362 asm volatile("spx %0" : : "m" (address) : "memory"); 362 asm volatile("spx %0" : : "m" (address) : "memory");
363} 363}
364 364
365static inline __u32 store_prefix(void)
366{
367 __u32 address;
368
369 asm volatile("stpx %0" : "=m" (address));
370 return address;
371}
372
365#define __PANIC_MAGIC 0xDEADC0DE 373#define __PANIC_MAGIC 0xDEADC0DE
366 374
367#endif 375#endif
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h
new file mode 100644
index 000000000000..9b439cf67800
--- /dev/null
+++ b/include/asm-s390/reset.h
@@ -0,0 +1,23 @@
1/*
2 * include/asm-s390/reset.h
3 *
4 * Copyright IBM Corp. 2006
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */
7
8#ifndef _ASM_S390_RESET_H
9#define _ASM_S390_RESET_H
10
11#include <linux/list.h>
12
13struct reset_call {
14 struct list_head list;
15 void (*fn)(void);
16};
17
18extern void register_reset_call(struct reset_call *reset);
19extern void unregister_reset_call(struct reset_call *reset);
20extern void s390_reset_system(void);
21extern void (*s390_reset_mcck_handler)(void);
22
23#endif /* _ASM_S390_RESET_H */