aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/lowcore.h24
-rw-r--r--arch/s390/include/asm/system.h16
-rw-r--r--arch/s390/kernel/ipl.c56
-rw-r--r--arch/s390/kernel/setup.c5
-rw-r--r--arch/s390/kernel/smp.c9
-rw-r--r--drivers/s390/char/zcore.c88
6 files changed, 172 insertions, 26 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
461static 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
461extern void (*_machine_restart)(char *command); 477extern void (*_machine_restart)(char *command);
462extern void (*_machine_halt)(void); 478extern void (*_machine_halt)(void);
463extern void (*_machine_power_off)(void); 479extern 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
67struct shutdown_action { 68struct shutdown_action {
68 char *name; 69 char *name;
@@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
146static struct ipl_parameter_block *reipl_block_fcp; 147static struct ipl_parameter_block *reipl_block_fcp;
147static struct ipl_parameter_block *reipl_block_ccw; 148static struct ipl_parameter_block *reipl_block_ccw;
148static struct ipl_parameter_block *reipl_block_nss; 149static struct ipl_parameter_block *reipl_block_nss;
150static struct ipl_parameter_block *reipl_block_actual;
149 151
150static int dump_capabilities = DUMP_TYPE_NONE; 152static int dump_capabilities = DUMP_TYPE_NONE;
151static enum dump_type dump_type = DUMP_TYPE_NONE; 153static 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
1340static 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
1368static int __init dump_reipl_init(void)
1369{
1370 if (!diag308_set_works)
1371 return -EOPNOTSUPP;
1372 else
1373 return 0;
1374}
1375
1376static 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
1423static struct shutdown_action *shutdown_actions_list[] = { 1470static 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 */
86int __initdata memory_end_set; 86int __initdata memory_end_set;
87unsigned long __initdata memory_end; 87unsigned long __initdata memory_end;
88 88
89/* An array with a pointer to the lowcore of every CPU. */
90struct _lowcore *lowcore_ptr[NR_CPUS];
91EXPORT_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
439static void __init 444static 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 */
56struct _lowcore *lowcore_ptr[NR_CPUS];
57EXPORT_SYMBOL(lowcore_ptr);
58
59static struct task_struct *current_set[NR_CPUS]; 53static struct task_struct *current_set[NR_CPUS];
60 54
61static u8 smp_cpu_type; 55static 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())
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index eefc6611412e..cfe782ee6473 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * For more information please refer to Documentation/s390/zfcpdump.txt 6 * For more information please refer to Documentation/s390/zfcpdump.txt
7 * 7 *
8 * Copyright IBM Corp. 2003,2007 8 * Copyright IBM Corp. 2003,2008
9 * Author(s): Michael Holzheu 9 * Author(s): Michael Holzheu
10 */ 10 */
11 11
@@ -48,12 +48,19 @@ struct sys_info {
48 union save_area lc_mask; 48 union save_area lc_mask;
49}; 49};
50 50
51struct ipib_info {
52 unsigned long ipib;
53 u32 checksum;
54} __attribute__((packed));
55
51static struct sys_info sys_info; 56static struct sys_info sys_info;
52static struct debug_info *zcore_dbf; 57static struct debug_info *zcore_dbf;
53static int hsa_available; 58static int hsa_available;
54static struct dentry *zcore_dir; 59static struct dentry *zcore_dir;
55static struct dentry *zcore_file; 60static struct dentry *zcore_file;
56static struct dentry *zcore_memmap_file; 61static struct dentry *zcore_memmap_file;
62static struct dentry *zcore_reipl_file;
63static struct ipl_parameter_block *ipl_block;
57 64
58/* 65/*
59 * Copy memory from HSA to kernel or user memory (not reentrant): 66 * Copy memory from HSA to kernel or user memory (not reentrant):
@@ -527,6 +534,33 @@ static const struct file_operations zcore_memmap_fops = {
527 .release = zcore_memmap_release, 534 .release = zcore_memmap_release,
528}; 535};
529 536
537static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
538 size_t count, loff_t *ppos)
539{
540 if (ipl_block) {
541 diag308(DIAG308_SET, ipl_block);
542 diag308(DIAG308_IPL, NULL);
543 }
544 return count;
545}
546
547static int zcore_reipl_open(struct inode *inode, struct file *filp)
548{
549 return 0;
550}
551
552static int zcore_reipl_release(struct inode *inode, struct file *filp)
553{
554 return 0;
555}
556
557static const struct file_operations zcore_reipl_fops = {
558 .owner = THIS_MODULE,
559 .write = zcore_reipl_write,
560 .open = zcore_reipl_open,
561 .release = zcore_reipl_release,
562};
563
530 564
531static void __init set_s390_lc_mask(union save_area *map) 565static void __init set_s390_lc_mask(union save_area *map)
532{ 566{
@@ -645,6 +679,39 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr)
645 return 0; 679 return 0;
646} 680}
647 681
682/*
683 * Provide IPL parameter information block from either HSA or memory
684 * for future reipl
685 */
686static int __init zcore_reipl_init(void)
687{
688 struct ipib_info ipib_info;
689 int rc;
690
691 rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
692 if (rc)
693 return rc;
694 if (ipib_info.ipib == 0)
695 return 0;
696 ipl_block = (void *) __get_free_page(GFP_KERNEL);
697 if (!ipl_block)
698 return -ENOMEM;
699 if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
700 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
701 else
702 rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE);
703 if (rc) {
704 free_page((unsigned long) ipl_block);
705 return rc;
706 }
707 if (cksm(ipl_block, ipl_block->hdr.len) != ipib_info.checksum) {
708 TRACE("Checksum does not match\n");
709 free_page((unsigned long) ipl_block);
710 ipl_block = NULL;
711 }
712 return 0;
713}
714
648static int __init zcore_init(void) 715static int __init zcore_init(void)
649{ 716{
650 unsigned char arch; 717 unsigned char arch;
@@ -690,6 +757,10 @@ static int __init zcore_init(void)
690 if (rc) 757 if (rc)
691 goto fail; 758 goto fail;
692 759
760 rc = zcore_reipl_init();
761 if (rc)
762 goto fail;
763
693 zcore_dir = debugfs_create_dir("zcore" , NULL); 764 zcore_dir = debugfs_create_dir("zcore" , NULL);
694 if (!zcore_dir) { 765 if (!zcore_dir) {
695 rc = -ENOMEM; 766 rc = -ENOMEM;
@@ -707,9 +778,17 @@ static int __init zcore_init(void)
707 rc = -ENOMEM; 778 rc = -ENOMEM;
708 goto fail_file; 779 goto fail_file;
709 } 780 }
781 zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
782 NULL, &zcore_reipl_fops);
783 if (!zcore_reipl_file) {
784 rc = -ENOMEM;
785 goto fail_memmap_file;
786 }
710 hsa_available = 1; 787 hsa_available = 1;
711 return 0; 788 return 0;
712 789
790fail_memmap_file:
791 debugfs_remove(zcore_memmap_file);
713fail_file: 792fail_file:
714 debugfs_remove(zcore_file); 793 debugfs_remove(zcore_file);
715fail_dir: 794fail_dir:
@@ -723,10 +802,15 @@ static void __exit zcore_exit(void)
723{ 802{
724 debug_unregister(zcore_dbf); 803 debug_unregister(zcore_dbf);
725 sclp_sdias_exit(); 804 sclp_sdias_exit();
805 free_page((unsigned long) ipl_block);
806 debugfs_remove(zcore_reipl_file);
807 debugfs_remove(zcore_memmap_file);
808 debugfs_remove(zcore_file);
809 debugfs_remove(zcore_dir);
726 diag308(DIAG308_REL_HSA, NULL); 810 diag308(DIAG308_REL_HSA, NULL);
727} 811}
728 812
729MODULE_AUTHOR("Copyright IBM Corp. 2003,2007"); 813MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
730MODULE_DESCRIPTION("zcore module for zfcpdump support"); 814MODULE_DESCRIPTION("zcore module for zfcpdump support");
731MODULE_LICENSE("GPL"); 815MODULE_LICENSE("GPL");
732 816