Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3152

kernel-2.6.18-194.11.1.el5.src.rpm

From: Hans-Joachim Picht <hpicht@redhat.com>
Date: Thu, 12 Mar 2009 15:26:18 +0100
Subject: [s390] kernel: shutdown action 'dump_reipl'
Message-id: 20090312142618.GO5103@redhat.com
O-Subject: [RHEL5 U4 PATCH 14/20] FEAT: s390 - kernel : Shutdown action "dump_reipl"
Bugzilla: 474688

Description
============

A new shutdown action "dump_reipl" is provided combining the
already existing actions "dump" and "reipl": first a dump is
taken, and after the dump process has completed an automatic
re-ipl of the system is triggered.

Bugzilla
=========

BZ 474688
https://bugzilla.redhat.com/show_bug.cgi?id=474688

Upstream status of the patch:
=============================

This patch is currently queued until the 2.6.30 merge window opens.
It has been posted upstream for review:
http://lkml.indiana.edu/hypermail/linux/kernel/0902.3/00677.html

Test status:
============

The patch has been tested by the IBM test department.

Please ACK.

With best regards,

	--Hans

diff --git a/arch/s390/boot/zfcpdump.c b/arch/s390/boot/zfcpdump.c
index b8fc6ac..f2acfc2 100644
--- a/arch/s390/boot/zfcpdump.c
+++ b/arch/s390/boot/zfcpdump.c
@@ -11,8 +11,6 @@
  * Author(s): Michael Holzheu
  */
 
-//#define GZIP_SUPPORT
-
 #include <errno.h>
 #include <string.h>
 #include <dirent.h>
@@ -42,6 +40,7 @@ static struct globals g;
 static int parse_parameter(char *parameter)
 {
 	char *token;
+	char *end_ptr;
 
 	token = strtok(parameter, "=");
 	if (token == NULL)
@@ -72,7 +71,12 @@ static int parse_parameter(char *parameter)
 				  "specified\n", PARM_MEM);
 			return -1;
 		}
-		g.parm_mem = strtoll(mem_str, NULL, 0);
+		g.parm_mem = strtoll(mem_str, &end_ptr, 0);
+		if (*end_ptr != 0) {
+			PRINT_ERR("Invalid value for '%s' parameter "
+				  "specified\n", PARM_MEM);
+			return -1;
+		}
 	} else if (strcmp(token, PARM_COMP) == 0) {
 		/* Dump Compression */
 		g.parm_compress = strtok(NULL, "=");
@@ -243,6 +247,7 @@ static int read_file(const char *file, char *buf, int size)
 static int enable_zfcp_device(void)
 {
 	char command[1024], file[1024];
+	struct stat s;
 
 	/* device */
 	if (read_file(IPL_DEVNO, g.dump_devno, sizeof(g.dump_devno)))
@@ -255,9 +260,12 @@ static int enable_zfcp_device(void)
 	if (read_file(IPL_WWPN, g.dump_wwpn, sizeof(g.dump_wwpn)))
 		return -1;
 	sprintf(file, "/sys/bus/ccw/drivers/zfcp/%s/port_add", g.dump_devno);
-	sprintf(command, "%s\n", g.dump_wwpn);
-	if (write_to_file(file, command))
-		return -1;
+	/* The port_add attribute has been removed in recent kernels */
+	if (stat(file, &s) == 0) {
+		sprintf(command, "%s\n", g.dump_wwpn);
+		if (write_to_file(file, command))
+			return -1;
+	}
 
 	/* lun */
 	if (read_file(IPL_LUN, g.dump_lun, sizeof(g.dump_lun)))
@@ -328,7 +336,15 @@ static int umount_dump_device(void)
  */
 static void terminate(void)
 {
+	int fd;
+
 	sleep(WAIT_TIME_END); /* give the messages time to be displayed */
+	fd = open(DEV_ZCORE_REIPL, O_WRONLY, 0);
+	if (fd == -1)
+		goto no_reipl;
+	write(fd, REIPL, 1);
+	close(fd);
+no_reipl:
 	reboot(LINUX_REBOOT_CMD_POWER_OFF);
 }
 
@@ -661,9 +677,12 @@ static int create_dump(void)
 	struct dump_page dp;
 	char page_buf[DUMP_BUF_SIZE], buf[PAGE_SIZE], dpcpage[PAGE_SIZE];
 	char dump_name[1024];
-	__u64 mem_loc;
+	__u64 mem_loc, mem_count;
 	__u32 buf_loc = 0, dp_size, dp_flags;
-	int size, fin, fout;
+	int size, fin, fout, fmap, rc = 0;
+	char c_info[CHUNK_INFO_SIZE];
+	struct mem_chunk *chunk, *chunk_first = NULL, *chunk_prev = NULL;
+	char *end_ptr;
 
 	if (stat(g.dump_dir, &stat_buf) < 0) {
 		PRINT_ERR("Specified dump dir '%s' not found!\n", g.dump_dir);
@@ -686,11 +705,65 @@ static int create_dump(void)
 	else
 		return -1;
 
+	/* Open the memory map file - only available with kernel 2.6.25 or
+	* higher. If open fails, memory holes cannot be detected and only
+	* one single memory chunk is assumed */
+	fmap = open(DEV_ZCORE_MAP, O_RDONLY, 0);
+	if (fmap == -1) {
+		chunk_first = calloc(1, sizeof(struct mem_chunk));
+		if (chunk_first == NULL) {
+			PRINT_ERR("Could not allocate %d bytes of memory\n",
+				  (int) sizeof(struct mem_chunk));
+			return -1;
+		}
+		chunk_first->size = PARM_MEM_DFLT;
+	} else {
+	/* read information about memory chunks (start address and size) */
+		do {
+			if (read(fmap, c_info, sizeof(c_info)) != sizeof(c_info)) {
+				PRINT_ERR("read() memory map file '%s' "
+					  "failed!\n", DEV_ZCORE_MAP);
+				rc = -1;
+				goto failed_close_fmap;
+			}
+			chunk = calloc(1, sizeof(struct mem_chunk));
+			if (chunk == NULL) {
+				PRINT_ERR("Could not allocate %d bytes of "
+					  "memory\n",
+					  (int) sizeof(struct mem_chunk));
+				rc = -1;
+				goto failed_free_chunks;
+			}
+			chunk->size = strtoul(c_info + 17, &end_ptr, 16);
+			if (end_ptr != c_info + 33 || *end_ptr != ' ') {
+				PRINT_ERR("Invalid contents of memory map "
+					  "file '%s'!\n", DEV_ZCORE_MAP);
+				rc = -1;
+				goto failed_free_chunks;
+			}
+			if (chunk->size == 0)
+				break;
+			chunk->addr = strtoul(c_info, &end_ptr, 16);
+			if (end_ptr != c_info + 16 || *end_ptr != ' ') {
+				PRINT_ERR("Invalid contents of memory map "
+					  "file '%s'!\n", DEV_ZCORE_MAP);
+				rc = -1;
+				goto failed_free_chunks;
+			}
+			if (!chunk_first)
+				chunk_first = chunk;
+			else
+				chunk_prev->next = chunk;
+			chunk_prev = chunk;
+		} while (1);
+	}
+
 	/* try to open the source device */
 	fin = open(DEV_ZCORE, O_RDONLY, 0);
 	if (fin == -1) {
 		PRINT_ERR("open() source device '%s' failed!\n", DEV_ZCORE);
-		return -1;
+		rc = -1;
+		goto failed_free_chunks;
 	}
 
 	/* make the new filename */
@@ -698,6 +771,7 @@ static int create_dump(void)
 	fout = open(dump_name, DUMP_FLAGS, DUMP_MODE);
 	if (fout == -1) {
 		PRINT_ERR("open() of dump file \"%s\" failed!\n", dump_name);
+		rc = -1;
 		goto failed_close_fin;
 	}
 
@@ -708,10 +782,12 @@ static int create_dump(void)
 	if (lseek(fin, 0, SEEK_SET) < 0) {
 		PRINT_ERR("Cannot lseek() to get the dump header from the "
 			"dump file!\n");
+		rc = -1;
 		goto failed_close_fout;
 	}
 	if (read(fin, &s390_dh, sizeof(s390_dh)) != sizeof(s390_dh)) {
 		PRINT_ERR("Cannot read() dump header from dump file!\n");
+		rc = -1;
 		goto failed_close_fout;
 	}
 
@@ -742,21 +818,36 @@ static int create_dump(void)
 	memcpy(page_buf, &dh, sizeof(dh));
 	if (lseek(fout, 0L, SEEK_SET) < 0) {
 		PRINT_ERR("lseek() failed\n");
+		rc = -1;
 		goto failed_close_fout;
 	}
 	if (dump_write(fout, page_buf, DUMP_BUF_SIZE) != DUMP_BUF_SIZE) {
 		PRINT_ERR("Error: Write dump header failed\n");
+		rc = -1;
 		goto failed_close_fout;
 	}
 
 	/* write dump */
 
+	chunk = chunk_first;
 	mem_loc = 0;
+	mem_count = 0;
 	if (lseek(fin, DUMP_HEADER_SZ_S390SA, SEEK_SET) < 0) {
 		PRINT_ERR("lseek() failed\n");
+		rc = -1;
 		goto failed_close_fout;
 	}
-	while (mem_loc < dh.memory_size) {
+	while (mem_loc < dh.memory_end) {
+		if (mem_loc >= chunk->addr + chunk->size) {
+			chunk = chunk->next;
+			mem_loc = chunk->addr;
+			if (lseek(fin, DUMP_HEADER_SZ_S390SA + mem_loc,
+				  SEEK_SET) < 0) {
+				PRINT_ERR("lseek() failed\n");
+				rc = -1;
+				goto failed_close_fout;
+			}
+		}
 		if (read(fin, buf, PAGE_SIZE) != PAGE_SIZE) {
 			if (errno == EFAULT) {
 				/* probably memory hole. Skip page */
@@ -764,6 +855,7 @@ static int create_dump(void)
 				continue;
 			}
 			PRINT_PERR("read error\n");
+			rc = -1;
 			goto failed_close_fout;
 		}
 		memset(dpcpage, 0, PAGE_SIZE);
@@ -796,11 +888,13 @@ static int create_dump(void)
 		buf_loc += dp_size;
 		if (dump_write(fout, page_buf, buf_loc) != buf_loc) {
 			PRINT_ERR("write error\n");
+			rc = -1;
 			goto failed_close_fout;
 		}
 		buf_loc = 0;
 		mem_loc += PAGE_SIZE;
-		show_progress(mem_loc, dh.memory_size);
+		mem_count += PAGE_SIZE;
+		show_progress(mem_count, dh.memory_size);
 	}
 
 	/* write end marker */
@@ -809,15 +903,21 @@ static int create_dump(void)
 	dp.size    = DUMP_DH_END;
 	dp.flags   = 0x0;
 	dump_write(fout, &dp, sizeof(dp));
-	close(fin);
-	close(fout);
-	return 0;
 
 failed_close_fout:
 	close(fout);
 failed_close_fin:
 	close(fin);
-	return -1;
+failed_free_chunks:
+	chunk = chunk_first;
+	while (chunk) {
+		chunk_prev = chunk;
+		chunk = chunk->next;
+		free(chunk_prev);
+	}
+failed_close_fmap:
+	close(fmap);
+	return rc;
 }
 
 /*
diff --git a/arch/s390/boot/zfcpdump.h b/arch/s390/boot/zfcpdump.h
index 7fb3914..d0e4b6e 100644
--- a/arch/s390/boot/zfcpdump.h
+++ b/arch/s390/boot/zfcpdump.h
@@ -12,7 +12,7 @@
 #include <signal.h>
 #include <stdint.h>
 
-#define ZFCPDUMP_VERSION "2.0"
+#define ZFCPDUMP_VERSION "2.1"
 
 #define PRINT_TRACE(x...) \
 	do { \
@@ -76,6 +76,9 @@ struct globals {
 #define PROC_CMDLINE	"/proc/cmdline"
 #define PROC_MISC	"/proc/misc"
 #define DEV_ZCORE	"/sys/kernel/debug/zcore/mem"
+#define DEV_ZCORE_MAP	"/sys/kernel/debug/zcore/memmap"
+#define DEV_ZCORE_REIPL	"/sys/kernel/debug/zcore/reipl"
+#define REIPL		"1"
 #define DEV_SCSI	"/dev/sda"
 #define DUMP_DIR	"/mnt"
 
@@ -145,6 +148,7 @@ struct globals {
 #define DUMP_DH_END		0x4   /* end marker on a full dump        */
 
 #define PAGE_SIZE		4096
+#define CHUNK_INFO_SIZE		34  /* 2 16-byte char, each followed by blank */
 
 /*
  * This is the header dumped at the top of every valid crash dump.
@@ -209,6 +213,12 @@ struct dump_page {
 	__u32 flags;   /* flags (DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
 } __attribute__((packed));
 
+struct mem_chunk {
+	__u64 addr;    /* the start address of this memory chunk */
+	__u64 size;    /* the length of this memory chunk */
+	struct mem_chunk *next; /* pointer to next memory chunk */
+};
+
 /* Compression function */
 typedef int (*compress_fn_t)(const unsigned char *old, __u32 old_size,
 			     unsigned char *new, __u32 size);
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index c6dfba1..267340c 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -63,13 +63,14 @@ struct shutdown_trigger {
 };
 
 /*
- * Five shutdown action types are supported:
+ * The following shutdown action types are supported:
  */
 #define SHUTDOWN_ACTION_IPL_STR		"ipl"
 #define SHUTDOWN_ACTION_REIPL_STR	"reipl"
 #define SHUTDOWN_ACTION_DUMP_STR	"dump"
 #define SHUTDOWN_ACTION_VMCMD_STR	"vmcmd"
 #define SHUTDOWN_ACTION_STOP_STR	"stop"
+#define SHUTDOWN_ACTION_DUMP_REIPL_STR	"dump_reipl"
 
 struct shutdown_action {
 	char *name;
@@ -153,6 +154,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
 static struct ipl_parameter_block *reipl_block_nss;
+static struct ipl_parameter_block *reipl_block_actual;
 
 static int dump_capabilities = DUMP_TYPE_NONE;
 static enum dump_type dump_type = DUMP_TYPE_NONE;
@@ -870,6 +872,7 @@ static int reipl_set_type(enum ipl_type type)
 			reipl_method = REIPL_METHOD_CCW_VM;
 		else
 			reipl_method = REIPL_METHOD_CCW_CIO;
+		reipl_block_actual = reipl_block_ccw;
 		break;
 	case IPL_TYPE_FCP:
 		if (diag308_set_works)
@@ -878,6 +881,7 @@ static int reipl_set_type(enum ipl_type type)
 			reipl_method = REIPL_METHOD_FCP_RO_VM;
 		else
 			reipl_method = REIPL_METHOD_FCP_RO_DIAG;
+		reipl_block_actual = reipl_block_fcp;
 		break;
 	case IPL_TYPE_FCP_DUMP:
 		reipl_method = REIPL_METHOD_FCP_DUMP;
@@ -887,6 +891,7 @@ static int reipl_set_type(enum ipl_type type)
 			reipl_method = REIPL_METHOD_NSS_DIAG;
 		else
 			reipl_method = REIPL_METHOD_NSS;
+		reipl_block_actual = reipl_block_nss;
 		break;
 	case IPL_TYPE_UNKNOWN:
 		reipl_method = REIPL_METHOD_DEFAULT;
@@ -1362,6 +1367,48 @@ static struct shutdown_action dump_action = {
 	.init	= dump_init,
 };
 
+static void dump_reipl_run(struct shutdown_trigger *trigger)
+{
+	preempt_disable();
+	/*
+	 * Bypass dynamic address translation (DAT) when storing IPL parameter
+	 * information block address and checksum into the prefix area
+	 * (corresponding to absolute addresses 0-8191).
+	 * When enhanced DAT applies and the STE format control in one,
+	 * the absolute address is formed without prefixing. In this case a
+	 * normal store (stg/st) into the prefix area would no more match to
+	 * absolute addresses 0-8191.
+	 */
+#ifdef CONFIG_64BIT
+	asm volatile("sturg %0,%1"
+		:: "a" ((unsigned long) reipl_block_actual),
+		"a" (&lowcore_ptr[smp_processor_id()]->ipib));
+#else
+	asm volatile("stura %0,%1"
+		:: "a" ((unsigned long) reipl_block_actual),
+		"a" (&lowcore_ptr[smp_processor_id()]->ipib));
+#endif
+	asm volatile("stura %0,%1"
+		:: "a" (cksm(reipl_block_actual, reipl_block_actual->hdr.len)),
+		"a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum));
+	preempt_enable();
+	dump_run(trigger);
+}
+
+static int __init dump_reipl_init(void)
+{
+	if (!diag308_set_works)
+		return -EOPNOTSUPP;
+	else
+		return 0;
+}
+
+static struct shutdown_action dump_reipl_action = {
+	.name	= SHUTDOWN_ACTION_DUMP_REIPL_STR,
+	.fn	= dump_reipl_run,
+	.init	= dump_reipl_init,
+};
+
 /*
  * vmcmd shutdown action: Trigger vm command on shutdown.
  */
@@ -1453,7 +1500,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
 /* action list */
 
 static struct shutdown_action *shutdown_actions_list[] = {
-	&ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
+	&ipl_action, &reipl_action, &dump_reipl_action, &dump_action,
+	&vmcmd_action, &stop_action};
 #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
 
 /*
@@ -1465,12 +1513,18 @@ static decl_subsys(shutdown_actions, NULL, NULL);
 static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
 		       size_t len)
 {
-	int i;
+	int i, buflen;
+
+	if (buf[strlen(buf) - 1] == '\n')
+		buflen = strlen(buf) - 1;
+	else
+		buflen = strlen(buf);
 	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
 		if (!shutdown_actions_list[i])
 			continue;
-		if (strncmp(buf, shutdown_actions_list[i]->name,
-			    strlen(shutdown_actions_list[i]->name)) == 0) {
+		if (strlen(shutdown_actions_list[i]->name) != buflen)
+			continue;
+		if (strncmp(buf, shutdown_actions_list[i]->name, buflen) == 0) {
 			trigger->action = shutdown_actions_list[i];
 			return len;
 		}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 0c71557..5cd2733 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -630,6 +630,7 @@ setup_lowcore(void)
 	}
 #endif
 	set_prefix((u32)(unsigned long) lc);
+	lowcore_ptr[0] = lc;
 }
 
 static void __init
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 29148ec..12c27c2 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -239,9 +239,6 @@ static inline void do_store_status(void)
  */
 void smp_send_stop(void)
 {
-        /* write magic number to zero page (absolute 0) */
-	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
-
 	/* stop other processors. */
 	do_send_stop();
 
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 056dfb5..d68c831 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -5,7 +5,7 @@
  *
  * For more information please refer to Documentation/s390/zfcpdump.txt
  *
- * Copyright IBM Corp. 2003,2007
+ * Copyright IBM Corp. 2003,2008
  * Author(s): Michael Holzheu
  */
 
@@ -48,11 +48,18 @@ struct sys_info {
 	union save_area	lc_mask;
 };
 
+struct ipib_info {
+	unsigned long	ipib;
+	u32		checksum;
+}  __attribute__((packed));
+
 static struct sys_info sys_info;
 static struct debug_info *zcore_dbf;
 static int hsa_available;
 static struct dentry *zcore_dir;
 static struct dentry *zcore_file;
+static struct dentry *zcore_reipl_file;
+static struct ipl_parameter_block *ipl_block;
 
 /*
  * Copy memory from HSA to kernel or user memory (not reentrant):
@@ -521,6 +528,33 @@ static struct file_operations zcore_fops = {
 	.release	= zcore_release,
 };
 
+static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	if (ipl_block) {
+		diag308(DIAG308_SET, ipl_block);
+		diag308(DIAG308_IPL, NULL);
+	}
+	return count;
+}
+
+static int zcore_reipl_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static int zcore_reipl_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+static const struct file_operations zcore_reipl_fops = {
+	.owner		= THIS_MODULE,
+	.write		= zcore_reipl_write,
+	.open		= zcore_reipl_open,
+	.release	= zcore_reipl_release,
+};
+
 
 static void __init set_s390_lc_mask(union save_area *map)
 {
@@ -612,6 +646,39 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr)
 	get_cpu_id(&hdr->cpu_id);
 }
 
+/*
+ * Provide IPL parameter information block from either HSA or memory
+ * for future reipl
+ */
+static int __init zcore_reipl_init(void)
+{
+	struct ipib_info ipib_info;
+	int rc;
+
+	rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
+	if (rc)
+		return rc;
+	if (ipib_info.ipib == 0)
+		return 0;
+	ipl_block = (void *) __get_free_page(GFP_KERNEL);
+	if (!ipl_block)
+		return -ENOMEM;
+	if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
+		rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
+	else
+		rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE);
+	if (rc) {
+		free_page((unsigned long) ipl_block);
+		return rc;
+	}
+	if (cksm(ipl_block, ipl_block->hdr.len) != ipib_info.checksum) {
+		TRACE("Checksum does not match\n");
+		free_page((unsigned long) ipl_block);
+		ipl_block = NULL;
+	}
+	return 0;
+}
+
 static int __init zcore_init(void)
 {
 	unsigned char arch;
@@ -660,6 +727,10 @@ static int __init zcore_init(void)
 
 	zcore_header_init(arch, &zcore_header);
 
+	rc = zcore_reipl_init();
+	if (rc)
+		goto fail;
+
 	zcore_dir = debugfs_create_dir("zcore" , NULL);
 	if (!zcore_dir) {
 		rc = -ENOMEM;
@@ -670,11 +741,21 @@ static int __init zcore_init(void)
 	if (!zcore_file) {
 		debugfs_remove(zcore_dir);
 		rc = -ENOMEM;
-		goto fail;
+		goto fail_dir;
+	}
+	zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
+						NULL, &zcore_reipl_fops);
+	if (!zcore_reipl_file) {
+		rc = -ENOMEM;
+		goto fail_file;
 	}
 	hsa_available = 1;
 	return 0;
 
+fail_file:
+	debugfs_remove(zcore_file);
+fail_dir:
+	debugfs_remove(zcore_dir);
 fail:
 	diag308(DIAG308_REL_HSA, NULL);
 	return rc;
@@ -684,10 +765,14 @@ static void __exit zcore_exit(void)
 {
 	debug_unregister(zcore_dbf);
 	sclp_sdias_exit();
+	free_page((unsigned long) ipl_block);
+	debugfs_remove(zcore_reipl_file);
+	debugfs_remove(zcore_file);
+	debugfs_remove(zcore_dir);
 	diag308(DIAG308_REL_HSA, NULL);
 }
 
-MODULE_AUTHOR("Copyright IBM Corp. 2003,2007");
+MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
 MODULE_DESCRIPTION("zcore module for zfcpdump support");
 MODULE_LICENSE("GPL");
 
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
index 1171e6d..70fcffe 100644
--- a/include/asm-s390/ipl.h
+++ b/include/asm-s390/ipl.h
@@ -164,5 +164,6 @@ enum diag308_rc {
 };
 
 extern int diag308(unsigned long subcode, void *addr);
+extern u32 cksm(void *addr, unsigned long len);
 
 #endif /* _ASM_S390_IPL_H */
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 57af032..bca9946 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -109,7 +109,7 @@
 #endif /* __s390x__ */
 
 
-#define __LC_PANIC_MAGIC                0xE00
+#define __LC_DUMP_REIPL			0xE00
 #ifndef __s390x__
 #define __LC_PFAULT_INTPARM             0x080
 #define __LC_CPU_TIMER_SAVE_AREA        0x0D8
@@ -283,12 +283,14 @@ struct _lowcore
 	__u64        int_clock;                /* 0xc98 */
         __u8         pad11[0xe00-0xca0];       /* 0xca0 */
 
-        /* 0xe00 is used as indicator for dump tools */
-        /* whether the kernel died with panic() or not */
-        __u32        panic_magic;              /* 0xe00 */
+	/* 0xe00 contains the address of the IPL Parameter */
+	/* Information block. Dump tools need IPIB for IPL */
+	/* after dump.					   */
+	__u32	     ipib;		       /* 0xe00 */
+	__u32	     ipib_checksum;	       /* 0xe04 */
 
         /* Align to the top 1k of prefix area */
-	__u8         pad12[0x1000-0xe04];      /* 0xe04 */
+	__u8	     pad12[0x1000-0xe08];      /* 0xe08 */
 #else /* !__s390x__ */
         /* prefix area: defined by architecture */
 	__u32        ccw1[2];                  /* 0x000 */
@@ -374,11 +376,13 @@ struct _lowcore
 	__u64        int_clock;                /* 0xde8 */
         __u8         pad12[0xe00-0xdf0];       /* 0xdf0 */
 
-        /* 0xe00 is used as indicator for dump tools */
-        /* whether the kernel died with panic() or not */
-        __u32        panic_magic;              /* 0xe00 */
+	/* 0xe00 contains the address of the IPL Parameter */
+	/* Information block. Dump tools need IPIB for IPL */
+	/* after dump.					   */
+	__u64	     ipib;		       /* 0xe00 */
+	__u32	     ipib_checksum;	       /* 0xe08 */
 
-	__u8         pad13[0x1200-0xe04];      /* 0xe04 */
+	__u8         pad13[0x1200-0xe0c];      /* 0xe0c */
 
         /* System info area */ 
 
@@ -418,8 +422,6 @@ static inline __u32 store_prefix(void)
 	return address;
 }
 
-#define __PANIC_MAGIC           0xDEADC0DE
-
 #endif
 
 #endif
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index e029f17..63c4df0 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -478,6 +478,22 @@ extern void smp_ctl_clear_bit(int cr, int bit);
 
 #endif /* CONFIG_SMP */
 
+static inline u32 cksm(void *addr, unsigned long len)
+{
+	register unsigned long _addr asm("0") = (unsigned long) addr;
+	register unsigned long _len asm("1") = len;
+	unsigned long accu = 0;
+
+	asm volatile(
+		"0:\n"
+		"	cksm	%0,%1\n"
+		"	jnz	0b\n"
+		: "+d" (accu), "+d" (_addr), "+d" (_len)
+		:
+		: "cc", "memory");
+	return accu;
+}
+
 extern void (*_machine_restart)(char *command);
 extern void (*_machine_halt)(void);
 extern void (*_machine_power_off)(void);