diff options
author | Frank Munzert <munzert@de.ibm.com> | 2009-03-26 10:23:43 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-03-26 10:24:03 -0400 |
commit | 099b765139929efdcf232f8870804accf8c4cdc5 (patch) | |
tree | 9869bb629def6f49d5d3b82e8e0b301cabbc1b8c /arch/s390 | |
parent | d7fd5f1e3b195a8232b3ed768ac2809ddce8ca46 (diff) |
[S390] Automatic IPL after dump
Provide new shutdown action "dump_reipl" for automatic ipl after dump.
Signed-off-by: Frank Munzert <munzert@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/lowcore.h | 24 | ||||
-rw-r--r-- | arch/s390/include/asm/system.h | 16 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 56 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 5 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 9 |
5 files changed, 86 insertions, 24 deletions
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f3720defdd16..ee4b10ff9387 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -111,7 +111,7 @@ | |||
111 | 111 | ||
112 | #define __LC_PASTE 0xE40 | 112 | #define __LC_PASTE 0xE40 |
113 | 113 | ||
114 | #define __LC_PANIC_MAGIC 0xE00 | 114 | #define __LC_DUMP_REIPL 0xE00 |
115 | #ifndef __s390x__ | 115 | #ifndef __s390x__ |
116 | #define __LC_PFAULT_INTPARM 0x080 | 116 | #define __LC_PFAULT_INTPARM 0x080 |
117 | #define __LC_CPU_TIMER_SAVE_AREA 0x0D8 | 117 | #define __LC_CPU_TIMER_SAVE_AREA 0x0D8 |
@@ -286,12 +286,14 @@ struct _lowcore | |||
286 | __u64 int_clock; /* 0xc98 */ | 286 | __u64 int_clock; /* 0xc98 */ |
287 | __u8 pad11[0xe00-0xca0]; /* 0xca0 */ | 287 | __u8 pad11[0xe00-0xca0]; /* 0xca0 */ |
288 | 288 | ||
289 | /* 0xe00 is used as indicator for dump tools */ | 289 | /* 0xe00 contains the address of the IPL Parameter */ |
290 | /* whether the kernel died with panic() or not */ | 290 | /* Information block. Dump tools need IPIB for IPL */ |
291 | __u32 panic_magic; /* 0xe00 */ | 291 | /* after dump. */ |
292 | __u32 ipib; /* 0xe00 */ | ||
293 | __u32 ipib_checksum; /* 0xe04 */ | ||
292 | 294 | ||
293 | /* Align to the top 1k of prefix area */ | 295 | /* Align to the top 1k of prefix area */ |
294 | __u8 pad12[0x1000-0xe04]; /* 0xe04 */ | 296 | __u8 pad12[0x1000-0xe08]; /* 0xe08 */ |
295 | #else /* !__s390x__ */ | 297 | #else /* !__s390x__ */ |
296 | /* prefix area: defined by architecture */ | 298 | /* prefix area: defined by architecture */ |
297 | __u32 ccw1[2]; /* 0x000 */ | 299 | __u32 ccw1[2]; /* 0x000 */ |
@@ -379,12 +381,14 @@ struct _lowcore | |||
379 | __u64 int_clock; /* 0xde8 */ | 381 | __u64 int_clock; /* 0xde8 */ |
380 | __u8 pad12[0xe00-0xdf0]; /* 0xdf0 */ | 382 | __u8 pad12[0xe00-0xdf0]; /* 0xdf0 */ |
381 | 383 | ||
382 | /* 0xe00 is used as indicator for dump tools */ | 384 | /* 0xe00 contains the address of the IPL Parameter */ |
383 | /* whether the kernel died with panic() or not */ | 385 | /* Information block. Dump tools need IPIB for IPL */ |
384 | __u32 panic_magic; /* 0xe00 */ | 386 | /* after dump. */ |
387 | __u64 ipib; /* 0xe00 */ | ||
388 | __u32 ipib_checksum; /* 0xe08 */ | ||
385 | 389 | ||
386 | /* Per cpu primary space access list */ | 390 | /* Per cpu primary space access list */ |
387 | __u8 pad_0xe04[0xe38-0xe04]; /* 0xe04 */ | 391 | __u8 pad_0xe0c[0xe38-0xe0c]; /* 0xe0c */ |
388 | __u64 vdso_per_cpu_data; /* 0xe38 */ | 392 | __u64 vdso_per_cpu_data; /* 0xe38 */ |
389 | __u32 paste[16]; /* 0xe40 */ | 393 | __u32 paste[16]; /* 0xe40 */ |
390 | 394 | ||
@@ -433,8 +437,6 @@ static inline __u32 store_prefix(void) | |||
433 | return address; | 437 | return address; |
434 | } | 438 | } |
435 | 439 | ||
436 | #define __PANIC_MAGIC 0xDEADC0DE | ||
437 | |||
438 | #endif | 440 | #endif |
439 | 441 | ||
440 | #endif | 442 | #endif |
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 3a8b26eb1f2e..3f2ccb82b863 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
@@ -458,6 +458,22 @@ static inline unsigned short stap(void) | |||
458 | return cpu_address; | 458 | return cpu_address; |
459 | } | 459 | } |
460 | 460 | ||
461 | static inline u32 cksm(void *addr, unsigned long len) | ||
462 | { | ||
463 | register unsigned long _addr asm("0") = (unsigned long) addr; | ||
464 | register unsigned long _len asm("1") = len; | ||
465 | unsigned long accu = 0; | ||
466 | |||
467 | asm volatile( | ||
468 | "0:\n" | ||
469 | " cksm %0,%1\n" | ||
470 | " jnz 0b\n" | ||
471 | : "+d" (accu), "+d" (_addr), "+d" (_len) | ||
472 | : | ||
473 | : "cc", "memory"); | ||
474 | return accu; | ||
475 | } | ||
476 | |||
461 | extern void (*_machine_restart)(char *command); | 477 | extern void (*_machine_restart)(char *command); |
462 | extern void (*_machine_halt)(void); | 478 | extern void (*_machine_halt)(void); |
463 | extern void (*_machine_power_off)(void); | 479 | extern void (*_machine_power_off)(void); |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2dcf590faba6..5663c1f8e46a 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -56,13 +56,14 @@ struct shutdown_trigger { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Five shutdown action types are supported: | 59 | * The following shutdown action types are supported: |
60 | */ | 60 | */ |
61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" | 61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" |
62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" | 62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" |
63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" | 63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" |
64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" | 64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" |
65 | #define SHUTDOWN_ACTION_STOP_STR "stop" | 65 | #define SHUTDOWN_ACTION_STOP_STR "stop" |
66 | #define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl" | ||
66 | 67 | ||
67 | struct shutdown_action { | 68 | struct shutdown_action { |
68 | char *name; | 69 | char *name; |
@@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; | |||
146 | static struct ipl_parameter_block *reipl_block_fcp; | 147 | static struct ipl_parameter_block *reipl_block_fcp; |
147 | static struct ipl_parameter_block *reipl_block_ccw; | 148 | static struct ipl_parameter_block *reipl_block_ccw; |
148 | static struct ipl_parameter_block *reipl_block_nss; | 149 | static struct ipl_parameter_block *reipl_block_nss; |
150 | static struct ipl_parameter_block *reipl_block_actual; | ||
149 | 151 | ||
150 | static int dump_capabilities = DUMP_TYPE_NONE; | 152 | static int dump_capabilities = DUMP_TYPE_NONE; |
151 | static enum dump_type dump_type = DUMP_TYPE_NONE; | 153 | static enum dump_type dump_type = DUMP_TYPE_NONE; |
@@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type) | |||
835 | reipl_method = REIPL_METHOD_CCW_VM; | 837 | reipl_method = REIPL_METHOD_CCW_VM; |
836 | else | 838 | else |
837 | reipl_method = REIPL_METHOD_CCW_CIO; | 839 | reipl_method = REIPL_METHOD_CCW_CIO; |
840 | reipl_block_actual = reipl_block_ccw; | ||
838 | break; | 841 | break; |
839 | case IPL_TYPE_FCP: | 842 | case IPL_TYPE_FCP: |
840 | if (diag308_set_works) | 843 | if (diag308_set_works) |
@@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type) | |||
843 | reipl_method = REIPL_METHOD_FCP_RO_VM; | 846 | reipl_method = REIPL_METHOD_FCP_RO_VM; |
844 | else | 847 | else |
845 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; | 848 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; |
849 | reipl_block_actual = reipl_block_fcp; | ||
846 | break; | 850 | break; |
847 | case IPL_TYPE_FCP_DUMP: | 851 | case IPL_TYPE_FCP_DUMP: |
848 | reipl_method = REIPL_METHOD_FCP_DUMP; | 852 | reipl_method = REIPL_METHOD_FCP_DUMP; |
@@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type) | |||
852 | reipl_method = REIPL_METHOD_NSS_DIAG; | 856 | reipl_method = REIPL_METHOD_NSS_DIAG; |
853 | else | 857 | else |
854 | reipl_method = REIPL_METHOD_NSS; | 858 | reipl_method = REIPL_METHOD_NSS; |
859 | reipl_block_actual = reipl_block_nss; | ||
855 | break; | 860 | break; |
856 | case IPL_TYPE_UNKNOWN: | 861 | case IPL_TYPE_UNKNOWN: |
857 | reipl_method = REIPL_METHOD_DEFAULT; | 862 | reipl_method = REIPL_METHOD_DEFAULT; |
@@ -1332,6 +1337,48 @@ static struct shutdown_action __refdata dump_action = { | |||
1332 | .init = dump_init, | 1337 | .init = dump_init, |
1333 | }; | 1338 | }; |
1334 | 1339 | ||
1340 | static void dump_reipl_run(struct shutdown_trigger *trigger) | ||
1341 | { | ||
1342 | preempt_disable(); | ||
1343 | /* | ||
1344 | * Bypass dynamic address translation (DAT) when storing IPL parameter | ||
1345 | * information block address and checksum into the prefix area | ||
1346 | * (corresponding to absolute addresses 0-8191). | ||
1347 | * When enhanced DAT applies and the STE format control in one, | ||
1348 | * the absolute address is formed without prefixing. In this case a | ||
1349 | * normal store (stg/st) into the prefix area would no more match to | ||
1350 | * absolute addresses 0-8191. | ||
1351 | */ | ||
1352 | #ifdef CONFIG_64BIT | ||
1353 | asm volatile("sturg %0,%1" | ||
1354 | :: "a" ((unsigned long) reipl_block_actual), | ||
1355 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1356 | #else | ||
1357 | asm volatile("stura %0,%1" | ||
1358 | :: "a" ((unsigned long) reipl_block_actual), | ||
1359 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1360 | #endif | ||
1361 | asm volatile("stura %0,%1" | ||
1362 | :: "a" (cksm(reipl_block_actual, reipl_block_actual->hdr.len)), | ||
1363 | "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); | ||
1364 | preempt_enable(); | ||
1365 | dump_run(trigger); | ||
1366 | } | ||
1367 | |||
1368 | static int __init dump_reipl_init(void) | ||
1369 | { | ||
1370 | if (!diag308_set_works) | ||
1371 | return -EOPNOTSUPP; | ||
1372 | else | ||
1373 | return 0; | ||
1374 | } | ||
1375 | |||
1376 | static struct shutdown_action __refdata dump_reipl_action = { | ||
1377 | .name = SHUTDOWN_ACTION_DUMP_REIPL_STR, | ||
1378 | .fn = dump_reipl_run, | ||
1379 | .init = dump_reipl_init, | ||
1380 | }; | ||
1381 | |||
1335 | /* | 1382 | /* |
1336 | * vmcmd shutdown action: Trigger vm command on shutdown. | 1383 | * vmcmd shutdown action: Trigger vm command on shutdown. |
1337 | */ | 1384 | */ |
@@ -1421,7 +1468,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, | |||
1421 | /* action list */ | 1468 | /* action list */ |
1422 | 1469 | ||
1423 | static struct shutdown_action *shutdown_actions_list[] = { | 1470 | static struct shutdown_action *shutdown_actions_list[] = { |
1424 | &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; | 1471 | &ipl_action, &reipl_action, &dump_reipl_action, &dump_action, |
1472 | &vmcmd_action, &stop_action}; | ||
1425 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) | 1473 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) |
1426 | 1474 | ||
1427 | /* | 1475 | /* |
@@ -1434,11 +1482,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger, | |||
1434 | size_t len) | 1482 | size_t len) |
1435 | { | 1483 | { |
1436 | int i; | 1484 | int i; |
1485 | |||
1437 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { | 1486 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { |
1438 | if (!shutdown_actions_list[i]) | 1487 | if (!shutdown_actions_list[i]) |
1439 | continue; | 1488 | continue; |
1440 | if (strncmp(buf, shutdown_actions_list[i]->name, | 1489 | if (sysfs_streq(buf, shutdown_actions_list[i]->name)) { |
1441 | strlen(shutdown_actions_list[i]->name)) == 0) { | ||
1442 | trigger->action = shutdown_actions_list[i]; | 1490 | trigger->action = shutdown_actions_list[i]; |
1443 | return len; | 1491 | return len; |
1444 | } | 1492 | } |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c5cfb6185eac..8fdf08379ce9 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -86,6 +86,10 @@ volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | |||
86 | int __initdata memory_end_set; | 86 | int __initdata memory_end_set; |
87 | unsigned long __initdata memory_end; | 87 | unsigned long __initdata memory_end; |
88 | 88 | ||
89 | /* An array with a pointer to the lowcore of every CPU. */ | ||
90 | struct _lowcore *lowcore_ptr[NR_CPUS]; | ||
91 | EXPORT_SYMBOL(lowcore_ptr); | ||
92 | |||
89 | /* | 93 | /* |
90 | * This is set up by the setup-routine at boot-time | 94 | * This is set up by the setup-routine at boot-time |
91 | * for S390 need to find out, what we have to setup | 95 | * for S390 need to find out, what we have to setup |
@@ -434,6 +438,7 @@ setup_lowcore(void) | |||
434 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; | 438 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; |
435 | #endif | 439 | #endif |
436 | set_prefix((u32)(unsigned long) lc); | 440 | set_prefix((u32)(unsigned long) lc); |
441 | lowcore_ptr[0] = lc; | ||
437 | } | 442 | } |
438 | 443 | ||
439 | static void __init | 444 | static void __init |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2d337cbb9329..e279d0fbbbe8 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -50,12 +50,6 @@ | |||
50 | #include <asm/vdso.h> | 50 | #include <asm/vdso.h> |
51 | #include "entry.h" | 51 | #include "entry.h" |
52 | 52 | ||
53 | /* | ||
54 | * An array with a pointer the lowcore of every CPU. | ||
55 | */ | ||
56 | struct _lowcore *lowcore_ptr[NR_CPUS]; | ||
57 | EXPORT_SYMBOL(lowcore_ptr); | ||
58 | |||
59 | static struct task_struct *current_set[NR_CPUS]; | 53 | static struct task_struct *current_set[NR_CPUS]; |
60 | 54 | ||
61 | static u8 smp_cpu_type; | 55 | static u8 smp_cpu_type; |
@@ -82,9 +76,6 @@ void smp_send_stop(void) | |||
82 | /* Disable all interrupts/machine checks */ | 76 | /* Disable all interrupts/machine checks */ |
83 | __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); | 77 | __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); |
84 | 78 | ||
85 | /* write magic number to zero page (absolute 0) */ | ||
86 | lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; | ||
87 | |||
88 | /* stop all processors */ | 79 | /* stop all processors */ |
89 | for_each_online_cpu(cpu) { | 80 | for_each_online_cpu(cpu) { |
90 | if (cpu == smp_processor_id()) | 81 | if (cpu == smp_processor_id()) |