Subject: [PATCH] [FEAT LS1212] zipl: Re-write boot loaders in C
From: Stefan Haberland <stefan.haberland@de.ibm.com>

Summary:     zipl: Re-write boot loaders in C
Description: Convert the zipl bootloader and dumper from assembler to
             C programming language for better serviceability.
Upstream-ID: -
Problem-ID:  LS1212

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
---
 common.mak                         |   18 
 include/util_part.h                |   17 
 include/util_proc.h                |   35 +
 libutil/util_part.c                |  284 ++++++++++++
 libutil/util_proc.c                |  394 ++++++++++++++++
 zipl/boot/Makefile                 |   99 ++--
 zipl/boot/cio.c                    |  273 +++++++++++
 zipl/boot/cio.h                    |  145 ++++++
 zipl/boot/common.S                 |  381 ----------------
 zipl/boot/eckd.h                   |   42 +
 zipl/boot/eckd0.S                  |   21 
 zipl/boot/eckd0_cdl.S              |   20 
 zipl/boot/eckd0_ldl.S              |   21 
 zipl/boot/eckd1.S                  |   65 +-
 zipl/boot/eckd1a.S                 |   79 ---
 zipl/boot/eckd1b.S                 |  209 +++++++-
 zipl/boot/eckd2.S                  |  124 -----
 zipl/boot/eckd2.c                  |   97 ++++
 zipl/boot/eckd2dump.S              |  767 --------------------------------
 zipl/boot/eckd2dump.c              |  200 ++++++++
 zipl/boot/eckd2dump.h              |   49 ++
 zipl/boot/eckd2dump_mv.c           |  206 ++++++++
 zipl/boot/eckd2dump_sv.c           |   83 +++
 zipl/boot/eckd2mvdump.S            |  594 -------------------------
 zipl/boot/entry.S                  |   18 
 zipl/boot/error.h                  |   68 ++
 zipl/boot/fba.h                    |   56 ++
 zipl/boot/fba0.S                   |   99 +---
 zipl/boot/fba1b.S                  |   90 +++
 zipl/boot/fba2.S                   |  129 -----
 zipl/boot/fba2.c                   |  122 +++++
 zipl/boot/fba2dump.S               |  556 -----------------------
 zipl/boot/fba2dump.c               |  186 +++++++
 zipl/boot/head.S                   |   27 +
 zipl/boot/kdump.c                  |   37 +
 zipl/boot/kdump.h                  |   43 +
 zipl/boot/kdump2.c                 |   46 +
 zipl/boot/kdump3.c                 |  108 ++++
 zipl/boot/libc.c                   |  380 ++++++++++++++++
 zipl/boot/libc.h                   |  103 ++++
 zipl/boot/menu.c                   |  194 ++++++++
 zipl/boot/menu.h                   |   41 +
 zipl/boot/s390.h                   |  374 +++++++++++++++
 zipl/boot/sclp.S                   |  675 ----------------------------
 zipl/boot/sclp.c                   |  361 +++++++++++++++
 zipl/boot/sclp.h                   |  156 ++++++
 zipl/boot/sclp_stage3.c            |  163 ++++++
 zipl/boot/sclp_stage3.h            |   52 ++
 zipl/boot/stage2.c                 |  137 +++++
 zipl/boot/stage2.h                 |   76 +++
 zipl/boot/stage2.lds               |   61 ++
 zipl/boot/stage2dump.c             |  300 ++++++++++++
 zipl/boot/stage2dump.h             |  127 +++++
 zipl/boot/stage3.S                 |  198 --------
 zipl/boot/stage3.c                 |  298 ++++++++++++
 zipl/boot/stage3.h                 |   38 +
 zipl/boot/stage3.lds               |   45 +
 zipl/boot/tape0.S                  |   22 
 zipl/boot/tape2dump.c              |  214 +++++++++
 zipl/boot/tapedump.S               |  875 -------------------------------------
 zipl/include/boot.h                |  249 ++++++++--
 zipl/include/bootmap.h             |    1 
 zipl/include/disk.h                |   11 
 zipl/include/install.h             |   10 
 zipl/include/job.h                 |   29 -
 zipl/include/misc.h                |    9 
 zipl/include/proc.h                |   37 -
 zipl/include/scan.h                |    3 
 zipl/include/zipl.h                |   16 
 zipl/man/zipl.8                    |   62 +-
 zipl/man/zipl.conf.5               |   46 -
 zipl/src/Makefile                  |   22 
 zipl/src/boot.c                    |  369 ++++++---------
 zipl/src/bootmap.c                 |  434 +++++++++---------
 zipl/src/disk.c                    |  286 +++++++++---
 zipl/src/install.c                 |  722 ++++++++++++++----------------
 zipl/src/job.c                     |  209 +++-----
 zipl/src/misc.c                    |  169 +++++++
 zipl/src/proc.c                    |  331 -------------
 zipl/src/scan.c                    |   34 -
 zipl/src/zipl.c                    |   52 +-
 zipl/src/zipl_helper.device-mapper |   46 +
 82 files changed, 7727 insertions(+), 6118 deletions(-)

--- a/common.mak
+++ b/common.mak
@@ -101,6 +101,24 @@ export AS LD CC CPP AR NM STRIP OBJCOPY
 
 all:
 
+# rules for shared files
+# needed to ensure that these files are build with their own build
+# flags even if they are build from external directories
+$(rootdir)/libutil/util_part.o:
+	make -C $(rootdir)/libutil/ util_part.o
+
+$(rootdir)/libutil/util_list.o:
+	make -C $(rootdir)/libutil/ util_list.o
+
+$(rootdir)/libutil/util_proc.o:
+	make -C $(rootdir)/libutil/ util_proc.o
+
+$(rootdir)/libvtoc/vtoc.o:
+	make -C $(rootdir)/libvtoc/ vtoc.o
+
+$(rootdir)/zipl/boot/data.o:
+	make -C $(rootdir)/zipl/boot/ data.o
+
 install_dirs:
 	for dir in $(INSTDIRS); do \
 		test -d $$dir || $(INSTALL) -g $(GROUP) -o $(OWNER) -d $$dir; \
--- /dev/null
+++ b/include/util_part.h
@@ -0,0 +1,17 @@
+/*
+ * util - Utility function library
+ *
+ * Partition detection functions
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#ifndef UTIL_PART_H
+#define UTIL_PART_H
+
+int util_part_search(const char *dev, size_t blk_start, size_t blk_cnt,
+		     size_t blk_size, int *ext_part);
+int util_part_search_fh(int fh, size_t blk_start, size_t blk_cnt,
+			size_t blk_size, int *ext_part);
+
+#endif /* UTIL_PART_H */
--- /dev/null
+++ b/include/util_proc.h
@@ -0,0 +1,35 @@
+/*
+ *   Scanner for the /proc files
+ *
+ * Copyright IBM Corp. 2001, 2007.
+ *
+ * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ */
+
+#ifndef PROC_H
+#define PROC_H
+
+#include <ctype.h>
+#include <sys/types.h>
+
+
+struct util_proc_part_entry {
+	dev_t device;
+	size_t blockcount;
+	char *name;
+};
+
+struct util_proc_dev_entry {
+	int blockdev;
+	dev_t device;
+	char *name;
+};
+
+
+int util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry);
+void util_proc_part_free_entry(struct util_proc_part_entry *entry);
+int util_proc_dev_get_entry(dev_t dev, int blockdev,
+			    struct util_proc_dev_entry *entry);
+void util_proc_dev_free_entry(struct util_proc_dev_entry *entry);
+
+#endif /* not PROC_H */
--- /dev/null
+++ b/libutil/util_part.c
@@ -0,0 +1,284 @@
+/*
+ * util - Utility function library
+ *
+ * Partition detection functions
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <endian.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "util.h"
+
+#define GPT_SIGNATURE		0x4546492050415254ULL /* EFI PART */
+#define MBR_SIGNATURE		0x55aa
+#define MBR_PART_TYPE_DOS_EXT	0x05 /* DOS extended partition */
+#define MBR_PART_TYPE_WIN98_EXT	0x0f /* Windows 98 extended partition */
+#define MBR_PART_TYPE_LINUX_EXT	0x85 /* Linux extended partition */
+#define MBR_PART_TYPE_GPT	0xee /* GPT partition */
+#define MBR_EXT_PART_NUM_FIRST	5 /* Partition number for first logical vol */
+
+/*
+ * MBR/MSDOS partition entry
+ */
+struct mbr_part_entry {
+	uint8_t status;
+	uint8_t chs_start[3];
+	uint8_t type;
+	uint8_t chs_end[3];
+	uint32_t blk_start;
+	uint32_t blk_cnt;
+} __attribute__((packed));
+
+/*
+ * Master Boot Record (MBR)
+ */
+struct mbr {
+	uint8_t reserved[0x1be];
+	struct mbr_part_entry part_entry_vec[4];
+	uint16_t signature;
+} __attribute__((packed));
+
+/*
+ * GUID Partition Table (GPT) header
+ */
+struct gpt {
+	uint64_t signature;
+	uint32_t version;
+	uint32_t hdr_size;
+	uint32_t hdr_crc;
+	uint32_t reserved1;
+	uint64_t blk_cur;
+	uint64_t blk_back;
+	uint64_t blk_first;
+	uint64_t blk_last;
+	uint8_t guid[16];
+	uint64_t part_tab_blk_start;
+	uint32_t part_tab_cnt;
+	uint32_t part_tab_entry_size;
+	uint32_t part_tab_crc;
+} __attribute__((packed));
+
+/*
+ * GPT partition entry
+ */
+struct gpt_part_entry {
+	uint8_t type[16];
+	uint8_t guid[16];
+	uint64_t blk_start;
+	uint64_t blk_end;
+	uint64_t attr;
+	char name[72];
+} __attribute__((packed));
+
+/*
+ * Check for extended partition
+ */
+static int mbr_part_is_ext(uint8_t type)
+{
+	if ((type == MBR_PART_TYPE_DOS_EXT) ||
+	    (type == MBR_PART_TYPE_WIN98_EXT) ||
+	    (type == MBR_PART_TYPE_LINUX_EXT))
+		return 1;
+	return 0;
+}
+
+/*
+ * Check if disk has a classic MBR partion table
+ */
+static int mbr_table_valid(struct mbr *mbr)
+{
+	return mbr->signature == MBR_SIGNATURE;
+}
+
+/*
+ * Search partition in logical volumes of an extended partition
+ */
+static int mbr_table_ext_search(int fh, size_t blk_start_mbr,
+				size_t blk_start, size_t blk_cnt,
+				size_t blk_size, int part_num)
+{
+	size_t start, cnt, start_next;
+	struct mbr mbr;
+
+	/* Read MBR for logical volume */
+	if (lseek(fh, blk_start_mbr * blk_size, SEEK_SET) == (off_t)-1)
+		return -1;
+	if (read(fh, &mbr, sizeof(mbr)) == -1)
+		return -1;
+
+	/* Check for invalid MBR or last entry */
+	if (mbr.signature != MBR_SIGNATURE)
+		return -1;
+	if (mbr.part_entry_vec[0].blk_start == 0)
+		return -1;
+
+	/* First entry contains a relative offset for current logical volume */
+	start = blk_start_mbr + le32toh(mbr.part_entry_vec[0].blk_start);
+	cnt = le32toh(mbr.part_entry_vec[0].blk_cnt);
+
+	if ((start == blk_start) && (cnt == blk_cnt))
+		return part_num;
+
+	/* Second entry contains relative offset for next logical volume */
+	start_next = le32toh(mbr.part_entry_vec[1].blk_start);
+	if (start_next == 0)
+		return 0;
+	start_next += blk_start_mbr;
+
+	/* Recursively search for next logical volume in chain */
+	return mbr_table_ext_search(fh, start_next, blk_start, blk_cnt,
+				    blk_size, part_num + 1);
+}
+
+/*
+ * Search partition in MBR partition table
+ */
+static int mbr_table_search(int fh, struct mbr *mbr, size_t blk_start,
+			    size_t blk_cnt, size_t blk_size, int *part_ext)
+{
+	int part_num_ext, part_num;
+	size_t start, cnt;
+	uint8_t type;
+
+	for (part_num = 1; part_num <= 4; part_num++) {
+		type = mbr->part_entry_vec[part_num - 1].type;
+		start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start);
+		cnt = le32toh(mbr->part_entry_vec[part_num - 1].blk_cnt);
+		if (start == 0) /* Empty slot */
+			continue;
+		/*
+		 * The kernel sets count for extended partitions explicitly.
+		 * Therefore we do not check count here.
+		 */
+		if (mbr_part_is_ext(type) && (start == blk_start)) {
+			*part_ext = 1;
+			return part_num;
+		}
+		if ((start == blk_start) && (cnt == blk_cnt))
+			return part_num;
+		if (!mbr_part_is_ext(type))
+			continue;
+		part_num_ext = mbr_table_ext_search(fh, start, blk_start,
+						    blk_cnt, blk_size,
+						    MBR_EXT_PART_NUM_FIRST);
+		if (part_num_ext != 0)
+			return part_num_ext;
+	}
+	return 0;
+}
+
+/*
+ * Search partition in GPT partition table
+ */
+static int gpt_table_search(int fh, struct gpt *gpt, size_t blk_start,
+			    size_t blk_cnt, size_t blk_size)
+{
+	size_t start, end, part_tab_blk_start, blk_end;
+	uint32_t part_tab_cnt, part_tab_entry_size;
+	struct gpt_part_entry *part_entry;
+	unsigned int part_num;
+
+	blk_end = blk_start + blk_cnt - 1;
+	part_tab_entry_size = le32toh(gpt->part_tab_entry_size);
+	part_tab_cnt = le32toh(gpt->part_tab_cnt);
+	part_tab_blk_start = le64toh(gpt->part_tab_blk_start);
+
+	if (lseek(fh, part_tab_blk_start * blk_size, SEEK_SET) == (off_t)-1)
+		return -1;
+	for (part_num = 1; part_num <= part_tab_cnt; part_num++) {
+		char buf[part_tab_entry_size];
+
+		part_entry = (struct gpt_part_entry *) buf;
+		if (read(fh, buf, sizeof(buf)) == -1)
+			return -1;
+		start = le64toh(part_entry->blk_start);
+		end = le64toh(part_entry->blk_end);
+		if (start == 0) /* Empty slot */
+			continue;
+		if ((start == blk_start) && (end == blk_end))
+			return part_num;
+	}
+	return 0;
+}
+
+/*
+ * Check if disk has a GPT partition table
+ */
+static int gpt_table_valid(struct gpt *gpt, struct mbr *mbr)
+{
+	int cnt, part_num;
+	uint32_t start;
+	uint8_t type;
+
+	if (gpt->signature != GPT_SIGNATURE)
+		return 0;
+
+	/* Check for protective MBR (one reserved GPT partition) */
+	for (part_num = 1, cnt = 0; part_num <= 4; part_num++) {
+		start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start);
+		type = mbr->part_entry_vec[part_num - 1].type;
+		if (!start)
+			continue;
+		if (type != MBR_PART_TYPE_GPT)
+			return 0;
+		if (++cnt > 1)
+			return 0;
+	}
+	return 1;
+}
+
+/*
+ * Search for partition with given start block and count
+ *
+ * Return partition number when found, 0 when not found, and on error -1
+ * Set "part_ext" to 1 for extended partitions otherwise to 0.
+ */
+int util_part_search_fh(int fh, size_t blk_start, size_t blk_cnt,
+			size_t blk_size, int *part_ext)
+{
+	struct gpt gpt;
+	struct mbr mbr;
+
+	if (lseek(fh, 0, SEEK_SET) == (off_t)-1)
+		return -1;
+	if (read(fh, &mbr, sizeof(mbr)) == -1)
+		return -1;
+	if (lseek(fh, blk_size, SEEK_SET) == (off_t)-1)
+		return -1;
+	if (read(fh, &gpt, sizeof(gpt)) == -1)
+		return -1;
+	*part_ext = 0;
+	if (gpt_table_valid(&gpt, &mbr))
+		return gpt_table_search(fh, &gpt, blk_start, blk_cnt, blk_size);
+	if (mbr_table_valid(&mbr))
+		return mbr_table_search(fh, &mbr, blk_start, blk_cnt, blk_size,
+					part_ext);
+	return -1;
+}
+
+/*
+ * Search for partition with given start block and count
+ *
+ * Return partition number when found, 0 when not found, and on error -1
+ * Set "part_ext" to 1 for extended partitions otherwise to 0.
+ */
+int util_part_search(const char *device, size_t blk_start, size_t blk_cnt,
+		     size_t blk_size, int *part_ext)
+{
+	int rc, fh;
+
+	fh = open(device, O_RDONLY);
+	if (fh == -1)
+		return -1;
+	rc = util_part_search_fh(fh, blk_start, blk_cnt, blk_size, part_ext);
+	close(fh);
+	return rc;
+}
--- /dev/null
+++ b/libutil/util_proc.c
@@ -0,0 +1,394 @@
+/*
+ * s390-tools/zipl/src/proc.c
+ *   Scanner for the /proc/ files
+ *
+ * Copyright IBM Corp. 2001, 2007.
+ *
+ * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ */
+
+#include "util_proc.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+static const char util_proc_part_filename[] = "/proc/partitions";
+static const char util_proc_dev_filename[] = "/proc/devices";
+
+struct file_buffer {
+	char *buffer;
+	off_t pos;
+	size_t length;
+};
+
+#define INITIAL_FILE_BUFFER_SIZE	1024
+
+/* Read file into buffer without querying its size (necessary for reading files
+ * from /proc). Upon success, return zero and set BUFFER to point to
+ * the file buffer and SIZE (if non-null) to contain the file size. Return
+ * non-zero otherwise. Add a null-byte at the end of the buffer if
+ * NIL_TERMINATE is non-zero.  */
+static int
+util_proc_read_special_file(const char *filename, char **buffer, size_t *size,
+		       int nil_terminate)
+{
+	FILE *file;
+	char *data;
+	char *new_data;
+	size_t count;
+	size_t current_size;
+	int current;
+
+	file = fopen(filename, "r");
+	if (file == NULL) {
+		printf("Could not open %s\n",
+		       filename);
+		return -1;
+	}
+	current_size = INITIAL_FILE_BUFFER_SIZE;
+	count = 0;
+	data = (char *) malloc(current_size);
+	if (data == NULL) {
+		printf("Could not allocate %lld bytes of memory",
+		       (unsigned long long) size);
+		fclose(file);
+		return -1;
+	}
+	current = fgetc(file);
+	while (current != EOF || nil_terminate) {
+		if (current == EOF) {
+			current = 0;
+			nil_terminate = 0;
+		}
+		data[count++] = (char) current;
+		if (count >= current_size) {
+			new_data = (char *) malloc(current_size * 2);
+			if (new_data == NULL) {
+				printf("Could not allocate %lld bytes of memory",
+				       (unsigned long long) size);
+				free(data);
+				fclose(file);
+				return -1;
+			}
+			memcpy(new_data, data, current_size);
+			free(data);
+			data = new_data;
+			current_size *= 2;
+		}
+		current = fgetc(file);
+	}
+	fclose(file);
+	*buffer = data;
+	if (size)
+		*size = count;
+	return 0;
+}
+
+/* Get the contents of a file and fill in the respective fields of
+ * FILE. Return 0 on success, non-zero otherwise. */
+static int
+get_file_buffer(struct file_buffer *file, const char *filename)
+{
+	int rc;
+
+	rc = util_proc_read_special_file(filename, &file->buffer,
+					 &file->length, 0);
+	file->pos = 0;
+	return rc;
+}
+
+
+/* Free resources allocated for file buffer identified by
+ * FILE. */
+static void
+free_file_buffer(struct file_buffer *file)
+{
+	if (file->buffer != NULL) {
+		free(file->buffer);
+		file->buffer = NULL;
+		file->pos = 0;
+		file->length = 0;
+	}
+}
+
+
+/* Return character at current FILE buffer position or EOF if at end of
+ * file. */
+static int
+current_char(struct file_buffer *file)
+{
+	if (file->buffer != NULL)
+		if (file->pos < (off_t) file->length)
+			return file->buffer[file->pos];
+	return EOF;
+}
+
+
+/* Advance the current file pointer of file buffer FILE until the current
+ * character is no longer a whitespace or until the end of line or file is
+ * reached. Return 0 if at least one whitespace character was encountered,
+ * non-zero otherwise. */
+static int
+skip_whitespaces(struct file_buffer *file)
+{
+	int rc;
+
+	rc = -1;
+	while ((current_char(file) != '\n') && isspace(current_char(file))) {
+		rc = 0;
+		file->pos++;
+	}
+	return rc;
+}
+
+
+/* Scan a positive integer number at the current position of file buffer FILE
+ * and advance the position respectively. Upon success, return zero and set
+ * NUMBER to contain the scanned number. Return non-zero otherwise. */
+static int
+scan_number(struct file_buffer *file, size_t *number)
+{
+	int rc;
+	size_t old_number;
+
+	*number = 0;
+	rc = -1;
+	while (isdigit(current_char(file))) {
+		rc = 0;
+		old_number = *number;
+		*number = *number * 10 + current_char(file) - '0';
+		/* Check for overflow */
+		if (old_number > *number) {
+			rc = -1;
+			break;
+		}
+		file->pos++;
+	}
+	return rc;
+}
+
+
+/* Scan a device node name at the current position of file buffer FILE and
+ * advance the position respectively. Upon success, return zero and set
+ * NAME to contain a copy of the scanned name. Return non-zero otherwise. */
+static int
+scan_name(struct file_buffer *file, char **name)
+{
+	off_t start_pos;
+
+	start_pos = file->pos;
+	while (!isspace(current_char(file)) &&
+	       (current_char(file) != EOF))
+			file->pos++;
+	if (file->pos > start_pos) {
+		*name = (char *) malloc(file->pos - start_pos + 1);
+		if (*name == NULL)
+			return -1;
+		memcpy((void *) *name, (void *) &file->buffer[start_pos],
+		       file->pos - start_pos);
+		(*name)[file->pos - start_pos] = 0;
+		return 0;
+	} else
+		return -1;
+}
+
+/* Scan for the specified STRING at the current position of file buffer FILE
+ * and advance the position respectively. Upon success, return zero. Return
+ * non-zero otherwise. */
+static int
+scan_string(struct file_buffer *file, const char *string)
+{
+	int i;
+
+	i = 0;
+	for (i = 0; string[i] && (current_char(file) == string[i]);
+	     i++, file->pos++)
+		;
+	if (string[i] == '\0')
+		return 0;
+	return -1;
+}
+
+
+/* Advance the current file position to beginning of next line in file buffer
+ * FILE or to end of file. */
+static void
+skip_line(struct file_buffer *file)
+{
+	while ((current_char(file) != '\n') && (current_char(file) != EOF))
+		file->pos++;
+	if (current_char(file) == '\n')
+		file->pos++;
+}
+
+
+/* Return non-zero if the current file position of file buffer FILE is at the
+ * end of file. Return zero otherwise. */
+static int
+eof(struct file_buffer *file)
+{
+	return file->pos >= (off_t) file->length;
+}
+
+
+/* Scan a line of the specified /proc/partitions FILE buffer and advance the
+ * current file position pointer respectively. If the current line matches
+ * the correct pattern, fill in the corresponding data into ENTRY and return 0.
+ * Return non-zero otherwise. */
+static int
+scan_part_entry(struct file_buffer *file, struct util_proc_part_entry *entry)
+{
+	int rc;
+	size_t dev_major;
+	size_t dev_minor;
+	size_t blockcount;
+	char *name;
+
+	/* Scan for: (\s*)(\d+)(\s+)(\d+)(\s+)(\d+)(\s+)(\S+)(\.*)$ */
+	skip_whitespaces(file);
+	rc = scan_number(file, &dev_major);
+	if (rc)
+		return rc;
+	rc = skip_whitespaces(file);
+	if (rc)
+		return rc;
+	rc = scan_number(file, &dev_minor);
+	if (rc)
+		return rc;
+	rc = skip_whitespaces(file);
+	if (rc)
+		return rc;
+	rc = scan_number(file, &blockcount);
+	if (rc)
+		return rc;
+	rc = skip_whitespaces(file);
+	if (rc)
+		return rc;
+	rc = scan_name(file, &name);
+	if (rc)
+		return rc;
+	skip_line(file);
+	entry->device = makedev(dev_major, dev_minor);
+	entry->blockcount = blockcount;
+	entry->name = name;
+	return 0;
+}
+
+
+/* Release resources associated with ENTRY. */
+void
+util_proc_part_free_entry(struct util_proc_part_entry *entry)
+{
+	if (entry->name != NULL) {
+		free(entry->name);
+		entry->name = NULL;
+	}
+}
+
+/* Scan a line of the specified /proc/devices FILE buffer and advance the
+ * current file position pointer respectively. If the current line matches
+ * the correct pattern, fill in the corresponding data into ENTRY and return 0.
+ * Return non-zero otherwise. */
+static int
+scan_dev_entry(struct file_buffer *file, struct util_proc_dev_entry *entry,
+	       int blockdev)
+{
+	int rc;
+	size_t dev_major;
+	char *name;
+
+	/* Scan for: (\s*)(\d+)(\s+)(\S+)(\.*)$ */
+	skip_whitespaces(file);
+	rc = scan_number(file, &dev_major);
+	if (rc)
+		return rc;
+	rc = skip_whitespaces(file);
+	if (rc)
+		return rc;
+	rc = scan_name(file, &name);
+	if (rc)
+		return rc;
+	skip_line(file);
+	entry->device = makedev(dev_major, 0);
+	entry->name = name;
+	entry->blockdev = blockdev;
+	return 0;
+}
+
+
+/* Release resources associated with ENTRY. */
+void
+util_proc_dev_free_entry(struct util_proc_dev_entry *entry)
+{
+	if (entry->name != NULL) {
+		free(entry->name);
+		entry->name = NULL;
+	}
+}
+
+
+/* Scan /proc/partitions for an entry matching DEVICE. When there is a match,
+ * store entry data in ENTRY and return 0. Return non-zero otherwise. */
+int
+util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry)
+{
+	struct file_buffer file;
+	int rc;
+
+	rc = get_file_buffer(&file, util_proc_part_filename);
+	if (rc)
+		return rc;
+	rc = -1;
+	while (!eof(&file)) {
+		if (scan_part_entry(&file, entry) == 0) {
+			if (entry->device == device) {
+				rc = 0;
+				break;
+			}
+			util_proc_part_free_entry(entry);
+		} else
+			skip_line(&file);
+	}
+	free_file_buffer(&file);
+	return rc;
+}
+
+/* Scan /proc/devices for a blockdevice (BLOCKDEV is 1) or a character
+ * device (BLOCKDEV is 0) with a major number matching the major number of DEV.
+ * When there is a match, store entry data in ENTRY and return 0. Return
+ * non-zero otherwise. */
+int
+util_proc_dev_get_entry(dev_t device, int blockdev,
+			struct util_proc_dev_entry *entry)
+{
+	struct file_buffer file;
+	int rc;
+	int scan_blockdev = 0;
+
+	rc = get_file_buffer(&file, util_proc_dev_filename);
+	if (rc)
+		return rc;
+	rc = -1;
+	while (!eof(&file)) {
+		if (scan_string(&file, "Block") == 0) {
+			skip_line(&file);
+			scan_blockdev = 1;
+			continue;
+		} else if (scan_dev_entry(&file, entry, scan_blockdev) == 0) {
+			if ((major(entry->device) == major(device)) &&
+			    blockdev == scan_blockdev) {
+				rc = 0;
+				break;
+			}
+			util_proc_dev_free_entry(entry);
+		} else
+			skip_line(&file);
+	}
+	free_file_buffer(&file);
+	return rc;
+}
--- a/zipl/boot/Makefile
+++ b/zipl/boot/Makefile
@@ -1,14 +1,26 @@
 # Common definitions
 include ../../common.mak
 
-S390_TOOLS_VERSION_EBCDIC := $(shell echo -n $(S390_TOOLS_RELEASE) | dd conv=ebcdic 2> /dev/null | hexdump -v -e '/1 "0x%02x,"' | sed 's/.$$//')
+CFLAGS	= -Os -g -I../include -D__ASSEMBLY__ \
+	  -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
+	  -fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
+	  -fno-delete-null-pointer-checks -fno-strict-aliasing \
+	  -fexec-charset=IBM1047 -m64 -mpacked-stack \
+	  -mstack-size=8192 -mstack-guard=128 -msoft-float $(WARNFLAGS)
+
+FILES	= fba0.bin fba1b.bin fba2.bin \
+	  eckd0_ldl.bin eckd0_cdl.bin \
+	  eckd1.bin eckd1b.bin eckd2.bin \
+	  tape0.bin \
+	  eckd2dump_sv.bin tape2dump.bin fba2dump.bin eckd2dump_mv.bin \
+	  stage3.bin
 
-CFLAGS  += -I../include -D__ASSEMBLY__ \
-		-DS390_TOOLS_VERSION_EBCDIC=$(S390_TOOLS_VERSION_EBCDIC)
-LDFLAGS = -O2
-FILES	:= fba0.bin fba2.bin eckd0.bin eckd1a.bin eckd1b.bin eckd2.bin \
-	   eckd2dump.bin tapedump.bin stage3.bin tape0.bin fba2dump.bin \
-	   eckd2mvdump.bin
+HEADERS	= cio.h eckd2dump.h fba.h libc.h s390.h sclp_stage3.h stage2dump.h \
+	  eckd.h error.h kdump.h menu.h sclp.h stage2.h stage3.h
+
+*.o: $(HEADERS)
+
+eckd2dump.o: cio.h
 
 all: data.o data.h tape0.bin
 
@@ -18,26 +30,54 @@ all: data.o data.h tape0.bin
 %.o:	%.S
 	$(CC) $(CFLAGS) -c -o $@ $<
 
+eckd2dump_sv.exec: \
+	head.o stage2dump.o cio.o eckd2dump.o eckd2dump_sv.o \
+	libc.o sclp.o entry.o
+eckd2dump_mv.exec: \
+	head.o stage2dump.o cio.o eckd2dump.o eckd2dump_mv.o \
+	libc.o sclp.o entry.o
+fba2dump.exec: \
+	head.o stage2dump.o cio.o fba2dump.o \
+	libc.o sclp.o entry.o
+tape2dump.exec: \
+	head.o stage2dump.o cio.o tape2dump.o \
+	libc.o sclp.o entry.o
+eckd2.exec: head.o stage2.o cio.o eckd2.o libc.o menu.o sclp.o \
+	    kdump2.o kdump.o entry.o
+fba2.exec: head.o stage2.o cio.o fba2.o libc.o menu.o sclp.o \
+	   kdump2.o kdump.o entry.o
+stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \
+	     kdump.o entry.o
+
 %.exec:	%.o
-	@STAGE=$$(                                  \
-		echo $@ | awk '                           \
-			match($$0,/[0-9]+/){                    \
-				print substr($$0,RSTART,RLENGTH)      \
-			}                                       \
-			/tapedump/{                             \
-				print "2"                             \
-			}'                                      \
-	);                                          \
-	case $$STAGE in                             \
-		0) SFLAGS="-nostdlib -Wl,-Ttext,0";;      \
-		1) SFLAGS="-nostdlib -Wl,-Ttext,0x218";;  \
-		2) SFLAGS="-nostdlib -Wl,-Ttext,0x2000";; \
-		3) SFLAGS="-nostdlib -Wl,-Ttext,0xA000";; \
-	esac;                                       \
-	$(LINK) $(LDFLAGS) $$SFLAGS $^ $(LOADLIBES) $(LDLIBS) -o $@
+	@STAGE=$$( \
+		echo $@ | awk ' \
+			match($$0,/[0-9]+b*/){ \
+				print substr($$0,RSTART,RLENGTH) \
+			}' \
+	); \
+	case $$STAGE in \
+		0) SFLAGS="-nostdlib -Wl,-Ttext,0";; \
+		1) SFLAGS="-nostdlib -Wl,-Ttext,0x18";; \
+		1b) SFLAGS="-nostdlib -Wl,-Ttext,0xE000";; \
+		2) SFLAGS="-nostdlib -Wl,-T,stage2.lds";; \
+		3) SFLAGS="-nostdlib -Wl,-T,stage3.lds";; \
+	esac; \
+	$(LINK) $$SFLAGS -m64 $^ -o $@
 
 %.bin:	%.exec
-	$(OBJCOPY) -O binary --only-section=.text $< $@
+	$(OBJCOPY) -O binary \
+		--only-section=.stage2.head \
+		--only-section=.text.dummy \
+		--only-section=.text.start \
+		--only-section=.text \
+		--only-section=.ex_table \
+		--only-section=.data \
+		--only-section=.rodata.str1.2 \
+		--only-section=.rodata \
+		--only-section=.stage2dump.tail \
+		--only-section=.eckd2dump_mv.tail \
+		$< $@
 
 data.o: $(FILES)
 	$(LD) -r -b binary -o data.o $(FILES)
@@ -48,15 +88,6 @@ data.h: data.o
 				echo "extern char $$SYMBOL;" >>data.h; done
 
 clean:
-	rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin
+	rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin *.xxx *.yyy
 
 .PHONY: all clean
-
-
-# Additional manual dependencies
-
-eckd2.o: common.S menu.S sclp.S
-fba2.o: common.S menu.S sclp.S
-eckd2dump.o: dumpcommon.S
-tapedump.o: dumpcommon.S
-eckd2mvdump.o: dumpcommon.S
--- /dev/null
+++ b/zipl/boot/cio.c
@@ -0,0 +1,273 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common IO functions for channel based devices.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "cio.h"
+#include "error.h"
+#include "s390.h"
+#include "libc.h"
+
+static unsigned long initial_lpm = 0x00;
+static const char *msg_essch = "Start subchannel failed";
+static const char *msg_eenable_dev = "Enable device failed";
+
+static int clear_subchannel(struct subchannel_id subchannel_id)
+{
+	register struct subchannel_id reg1 asm ("1") = subchannel_id;
+	int rc;
+
+	asm volatile(
+		"     csch\n"
+		"     ipm    %0\n"
+		"     srl    %0,28\n"
+		: "=d" (rc)
+		: "d" (reg1)
+		: "cc");
+	return rc;
+}
+
+static int test_subchannel(struct subchannel_id subchannel_id, struct irb *irb)
+{
+	register struct subchannel_id reg1 asm ("1") = subchannel_id;
+	int rc;
+
+	asm volatile(
+		"       tsch    0(%3)\n"
+		"       ipm     %0\n"
+		"       srl     %0,28\n"
+		: "=d" (rc), "=m" (*irb)
+		: "d" (reg1), "a" (irb)
+		: "cc");
+	return rc;
+}
+
+static int start_subchannel(struct subchannel_id subchannel_id, struct orb *orb)
+{
+	register struct subchannel_id reg1 asm ("1") = subchannel_id;
+	int rc;
+
+	asm volatile(
+		"      ssch    0(%2)\n"
+		"      ipm     %0\n"
+		"      srl     %0,28\n"
+		: "=d" (rc)
+		: "d" (reg1), "a" (orb), "m" (*orb)
+		: "cc", "memory");
+	return rc;
+}
+
+int store_subchannel(struct subchannel_id subchannel_id, struct schib *schib)
+{
+	register struct subchannel_id reg1 asm ("1") = subchannel_id;
+	int ccode;
+
+	asm volatile(
+		"      stsch    0(%3)\n"
+		"      ipm      %0\n"
+		"      srl      %0,28\n"
+		: "=d" (ccode), "=m" (*schib)
+		: "d" (reg1), "a" (schib)
+		: "cc");
+	return ccode;
+}
+
+static int modify_subchannel(struct subchannel_id subchannel_id,
+			     struct schib *schib)
+{
+	register struct subchannel_id reg1 asm ("1") = subchannel_id;
+	int rc;
+
+	asm volatile(
+		"      msch    0(%2)\n"
+		"      ipm     %0\n"
+		"      srl     %0,28\n"
+		: "=d" (rc)
+		: "d" (reg1), "a" (schib), "m" (*schib)
+		: "cc");
+	return rc;
+}
+
+void io_irq_enable(void)
+{
+	unsigned long ctl = 0xff000000;
+
+	__ctl_load(ctl, 6, 6);
+}
+
+
+void io_irq_disable(void)
+{
+	unsigned long ctl = 0x00000000;
+
+	__ctl_load(ctl, 6, 6);
+}
+
+/*
+ * load wait psw and test subchannel after interrupt was received
+ * return condition code
+ */
+static int wait_for_int(struct subchannel_id subchannel_id, struct irb *irb)
+{
+	int rc;
+
+	do {
+		load_wait_psw(0x0202000180000000ULL, &S390_lowcore.io_new_psw);
+		rc = test_subchannel(subchannel_id, irb);
+	} while (rc == 1);
+
+	return rc;
+}
+
+/*
+ * get next path for IO
+ * call panic if no path is left
+ */
+static uint32_t next_path(uint32_t mask, struct subchannel_id subchannel_id,
+			  struct irb *irb)
+{
+	if (!initial_lpm) {
+		mask >>= 1;
+		if (mask == 0)
+			panic(ESSCH, "%s", msg_essch);
+	}
+
+	/* clear initial path mask to iterate throu other paths, too */
+	initial_lpm = 0;
+
+	if (clear_subchannel(subchannel_id))
+		panic(ESSCH, "%s", msg_essch);
+
+	wait_for_int(subchannel_id, irb);
+
+	return mask;
+}
+
+void start_io(struct subchannel_id subchannel_id, struct irb *irb,
+	      struct orb *orb)
+{
+	uint32_t mask = FIRST_PATH_MASK;
+	struct scsw *scsw;
+	int rc, retry = MAX_RETRIES;
+
+	while (1) {
+		/*
+		 * set path mask in orb to initial path mask or to current mask
+		 * initial_lpm gets cleared in next_path()
+		 */
+		if (!initial_lpm)
+			orb->lpm = mask;
+		else
+			orb->lpm = initial_lpm;
+
+		rc = start_subchannel(subchannel_id, orb);
+		if (rc == CC_NOT_OPER) {
+			mask = next_path(mask, subchannel_id, irb);
+			retry = MAX_RETRIES;
+			continue;
+		} else if (rc != CC_INITIATED) {
+			/*
+			 * possible status pending
+			 * call test_subchannel to clear and retry
+			 */
+			goto retry;
+		}
+
+		scsw = (struct scsw *)irb;
+		/* wait for interrupt and device is ready */
+		do {
+			rc = wait_for_int(subchannel_id, irb);
+			if (rc)
+				panic(ESSCH, "%s", msg_essch);
+
+			/* device end */
+			if (scsw->dstat & 0x04)
+				break;
+			/* deferred condition code */
+			if (scsw->cc != 0)
+				break;
+			/* status alert set */
+			if (scsw->stctl & 0x10)
+				break;
+			/* channel state */
+			if (scsw->cstat & 0xff)
+				break;
+		} while (1);
+
+		/* path not operational */
+		if (scsw->cc == 3) {
+			mask = next_path(mask, subchannel_id, irb);
+			retry = MAX_RETRIES;
+			continue;
+		}
+
+		/*
+		 * If no deferred condition code is set as well as
+		 * no channel status, no alert status control and no device
+		 * status except channel_end and device_end, we are done.
+		 */
+		if (scsw->cc == 0 &&
+		    scsw->cstat == 0 &&
+		    scsw->dstat & 0x04 &&
+		    !(scsw->stctl & 0x10) &&
+		    !(scsw->dstat & 0xf3))
+			return;
+
+retry:
+		/* else we clear the subchannel and do a retry */
+		test_subchannel(subchannel_id, irb);
+		retry--;
+
+		/*
+		 * if no retry is left we try another path;
+		 * if no path is left it will panic
+		 */
+		if (retry <= 0) {
+			mask = next_path(mask, subchannel_id, irb);
+			retry = MAX_RETRIES;
+		}
+	}
+}
+
+void set_device(struct subchannel_id subchannel_id, int enabled)
+{
+	struct schib schib;
+	struct irb *irb;
+	int i, rc;
+
+	irb = (struct irb *)&S390_lowcore.irb;
+	rc = store_subchannel(subchannel_id, &schib);
+
+	if (rc == CC_NOT_OPER)
+		/* Panic if path not operational */
+		panic(EENABLE_DEV, "%s", msg_eenable_dev);
+
+	/* enable/disable subchannel */
+	schib.pmcw.ena = enabled ? ENABLED : DISABLED;
+
+	for (i = 0; i < 256; i++) {
+		rc = modify_subchannel(subchannel_id, &schib);
+		if (!rc) {
+			/* successful */
+			break;
+		} else if (rc == CC_STATUS_PENDING || rc == CC_BUSY) {
+			/* call test_subchannel to clear pending status */
+			rc = test_subchannel(subchannel_id, irb);
+			if (rc == CC_NOT_OPER)
+				panic(EENABLE_DEV, "%s", msg_eenable_dev);
+		} else if (rc == CC_NOT_OPER) {
+			/* Panic if path not operational */
+			panic(EENABLE_DEV, "%s", msg_eenable_dev);
+		}
+	}
+
+	if (!enabled)
+		return;
+
+	/* set initial lpm to lpum if path is enabled and 0 if not */
+	initial_lpm = rc ? 0 : schib.pmcw.lpum;
+}
--- /dev/null
+++ b/zipl/boot/cio.h
@@ -0,0 +1,145 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common I/O functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ *            Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+#ifndef CIO_H
+#define CIO_H
+
+#include "libc.h"
+#include "s390.h"
+
+/* Condition codes */
+#define CC_INITIATED		0
+#define CC_STATUS_PENDING	1
+#define CC_BUSY			2
+#define CC_NOT_OPER		3
+
+/* CCW FLAGS */
+#define CCW_FLAG_IDA		0x04
+#define CCW_FLAG_CC		0x40
+#define CCW_FLAG_SLI		0x20
+
+#define FIRST_PATH_MASK		0x80
+
+#define DISABLED		0
+#define ENABLED			1
+
+#define MAX_RETRIES		255
+
+struct subchannel_id {
+	uint32_t cssid:8;
+	uint32_t:4;
+	uint32_t m:1;
+	uint32_t ssid:2;
+	uint32_t one:1;
+	uint32_t sch_no:16;
+} __packed __aligned(4);
+
+struct ccw1 {
+	uint8_t cmd_code;
+	uint8_t flags;
+	uint16_t count;
+	uint32_t cda;
+}  __packed __aligned(8);
+
+struct irb {
+	uint8_t data[64];
+} __packed __aligned(4);
+
+struct orb {
+	uint32_t intparm;	/* interruption parameter */
+	uint32_t key:4;		/* flags, like key, suspend control, etc. */
+	uint32_t spnd:1;	/* suspend control */
+	uint32_t res1:1;	/* reserved */
+	uint32_t mod:1;		/* modification control */
+	uint32_t sync:1;	/* synchronize control */
+	uint32_t fmt:1;		/* format control */
+	uint32_t pfch:1;	/* prefetch control */
+	uint32_t isic:1;	/* initial-status-interruption control */
+	uint32_t alcc:1;	/* address-limit-checking control */
+	uint32_t ssic:1;	/* suppress-suspended-interr. control */
+	uint32_t res2:1;	/* reserved */
+	uint32_t c64:1;		/* IDAW/QDIO 64 bit control  */
+	uint32_t i2k:1;		/* IDAW 2/4kB block size control */
+	uint32_t lpm:8;		/* logical path mask */
+	uint32_t ils:1;		/* incorrect length */
+	uint32_t zero:6;	/* reserved zeros */
+	uint32_t orbx:1;	/* ORB extension control */
+	uint32_t cpa;		/* channel program address */
+	uint8_t reserved[20];
+} __packed __aligned(4);
+
+struct scsw {
+	uint32_t key:4;
+	uint32_t sctl:1;
+	uint32_t eswf:1;
+	uint32_t cc:2;
+	uint32_t fmt:1;
+	uint32_t pfch:1;
+	uint32_t isic:1;
+	uint32_t alcc:1;
+	uint32_t ssi:1;
+	uint32_t zcc:1;
+	uint32_t ectl:1;
+	uint32_t pno:1;
+	uint32_t res:1;
+	uint32_t fctl:3;
+	uint32_t actl:7;
+	uint32_t stctl:5;
+	uint32_t cpa;
+	uint32_t dstat:8;
+	uint32_t cstat:8;
+	uint32_t count:16;
+} __packed;
+
+struct pmcw {
+	uint32_t intparm;	/* interruption parameter */
+	uint32_t qf:1;
+	uint32_t w:1;
+	uint32_t isc:3;		/* interruption sublass */
+	uint32_t res5:3;	/* reserved zeros */
+	uint32_t ena:1;		/* enabled */
+	uint32_t lm:2;		/* limit mode */
+	uint32_t mme:2;		/* measurement-mode enable */
+	uint32_t mp:1;		/* multipath mode */
+	uint32_t tf:1;		/* timing facility */
+	uint32_t dnv:1;		/* device number valid */
+	uint32_t dev:16;	/* device number */
+	uint8_t  lpm;		/* logical path mask */
+	uint8_t  pnom;		/* path not operational mask */
+	uint8_t  lpum;		/* last path used mask */
+	uint8_t  pim;		/* path installed mask */
+	uint16_t mbi;		/* measurement-block index */
+	uint8_t  pom;		/* path operational mask */
+	uint8_t  pam;		/* path available mask */
+	uint8_t  chpid[8];	/* CHPID 0-7 (if available) */
+	uint32_t unused1:8;	/* reserved zeros */
+	uint32_t st:3;
+	uint32_t unused2:18;	/* reserved zeros */
+	uint32_t mbfc:1;	/* measurement block format control */
+	uint32_t xmwme:1;	/* extended measurement word mode enable */
+	uint32_t csense:1;	/* concurrent sense; can be enabled ...*/
+				/*  ... per MSCH, however, if facility */
+				/*  ... is not installed, this results */
+				/*  ... in an operand exception.       */
+} __packed;
+
+struct schib {
+	struct pmcw pmcw;	/* path management control word */
+	struct scsw scsw;	/* subchannel status word */
+	uint64_t mba;		/* measurement block address */
+	uint8_t mda[4];		/* model dependent area */
+} __packed __aligned(4);
+
+void start_io(struct subchannel_id , struct irb *, struct orb *);
+int store_subchannel(struct subchannel_id, struct schib *);
+void io_irq_enable(void);
+void io_irq_disable(void);
+void set_device(struct subchannel_id, int);
+
+#endif /* CIO_H */
--- a/zipl/boot/common.S
+++ /dev/null
@@ -1,381 +0,0 @@
-#
-#  Common code for the different second stage boot loaders
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
-#		Heiko Carstens (heiko.carstens@de.ibm.com)
-#
-
-# some definitions from kernel land
-__LC_IRB = 0x0300
-__LC_IPLDEV  = 0xC6C
-__LC_PANIC_MAGIC= 0xE00
-
-# Error codes shown as address in disabled wait psw
-
-EENABLE_DEV  = 0x00000100 # enable device failed
-EDISABLE_DEV = 0x00000101 # disable device failed
-ESSCH        = 0x00000102 # start subchannel failed
-EWRONGTYPE   = 0x00000200 # wrong ipl type supplied
-	.macro stage2_start
-#
-# Function entry point at 0x2000 is called with C linkage
-#   %r2-%r3: load descriptor
-#   %r3    : device subchannel id
-#   %r4    : load address
-#
-        basr   %r1,0
-        b      _load_blocklist-.(%r1)
-	.align 8
-
-#
-# Program execution of the second stage boot loader starts at 0x2008
-#
-        .globl _start
-_start: stm    %r0,%r15,0x180           # store all registers 
-        basr   %r13,0
-0:      l      %r15,3f-0b(%r13)         # load end of stack address
-
-	bas    %r14,_menu-0b(%r13)	# show menu
-	sll    %r2,3			# get offset from config number
-	lr     %r6,%r2
-
-        l      %r11,0xb8                # load ipl device subchannel id
-	lr     %r2,%r11
-	bas    %r14,_enable_device-0b(%r13)
-	ltr     %r2,%r2			# lpum valid?
-	bz     6f-0b(%r13)
-	stc    %r2,.Llpm-0b(%r13)	# save lpum
-6:
-        la     %r10,0
-        st     %r10,__LC_PANIC_MAGIC    # clear panic flag
-	lm     %r2,%r3,STAGE2_DESC      # get block with configurations
-	lr     %r4,%r11
-	l      %r5,4f-0b(%r13)
-	la     %r12,0(%r5)              # FIXME: provide the correct offset
-        bas    %r14,_load_direct-0b(%r13)
-	ar     %r6,%r12
-        lm     %r2,%r3,8(%r6)           # get block with load descriptors
-        lr     %r4,%r11
-        lr     %r5,%r12                 # set load address
-        bas    %r14,_load_direct-0b(%r13)
-	la     %r12,32(%r12)		# skip header entry
-1:      lm     %r2,%r3,0(%r12)		# load blocklist container of descriptor
-	l      %r4,20(%r12)		# load type
-	lhi    %r5,0xf
-	nr     %r4,%r5			# only the last four bits are the type
-	l      %r5,28(%r12)		# load address
-	l      %r6,24(%r12)		# load psw mask
-	sll    %r4,2
-	l      %r1,5f-0b(%r4,%r13)	# function pointer according to type
-	lr     %r4,%r11			# pass subchannel id
-        bas    %r14,0(%r1)
-2:	la     %r12,32(%r12)		# next load descriptor
-        b      1b-0b(%r13)
-3:      .long  0x10000-96
-4:	.long  0x8000
-5:	.long  _bug			# type 0: not allowed
-	.long  _execute			# type 1: jump to target
-	.long  _load_binary		# type 2: binary file
-
-_bug:
-	basr   %r1,0
-0:	l      %r2,1f-0b(%r1)
-	bas    %r4,_panik-0b(%r1)	# won't return
-        br     %r14
-1:	.long  EWRONGTYPE
-
-
-_load_binary:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      s      %r15,1f-0b(%r13)         # create stack frame
-        lr     %r12,%r4
-	bas    %r14,_load_blocklist-0b(%r13)
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-1:	.long  96
-	
-_execute:
-	basr   %r1,0
-0:	st     %r6,0(%r0)		# write supplied psw to address 0
-	st     %r5,4(%r0)
-	lr     %r2,%r11
-	bas    %r14,_disable_device-0b(%r1)
-	lpsw   0			# execute what we have loaded
-
-#include "menu.S"
-
-	.endm
-
-#
-# The load descriptor is 32 bytes in length and contains 3 entries:
-#   offset 0  : a blocklist descriptor (fba/eckd, 64 bit)
-#   offset 23 : a type (8 bit)
-#   offset 24 : an address (64 bit)
-# The meaning of the address and the validity of the blocklst
-# depends on the type.
-#   type = 1 : load binary, blocklist valid, address = load address
-#   type = 2 : load psw, blocklist invalid, address = PSW
-#
-	.macro blocklist_traverser
-# parameter
-#   %r2+%r3: blocklist head descriptor
-#   %r4    : device subchannel id
-#   %r5    : load address
-_load_blocklist:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      s      %r15,7f-0b(%r13)         # create stack frame
-1:	lr     %r12,%r4                 # save device subchannel id
-	lr     %r11,%r5                 # save load address
-	lr     %r8,%r2                  # save descriptor
-	lr     %r9,%r3
-	bas    %r14,_extract_length-0b(%r13)   # get length from descriptor
-	lr     %r10,%r2                 # save returned length
-	lr     %r2,%r8                  # reload descriptor to %r2/%r3
-	lr     %r3,%r9
-	lr     %r4,%r12                 # reload device id to %r4
-	l      %r5,9f-0b(%r13)          # get memory area for indirect block
-        bas    %r14,_load_direct-0b(%r13) # load indirect block
-	lr     %r9,%r10                 # (length / 8 - 1) = # direct descr.
-	srl    %r9,3
-	bctr   %r9,0
-	l      %r8,9f-0b(%r13)
-2:	clc    0(8,%r8),8f-0b(%r13)     # test block descriptor
-	be     6f-0b(%r13)              # descriptor == 0 -> done
-	lm     %r2,%r3,0(%r8)           # pass block descriptor
-	bas    %r14,_is_zero_block-0b(%r13)    # test for special 0 descriptor
-	ltr    %r2,%r2                  # is it a hole to fill with 0?
-	bne    4f-0b(%r13)              # no, normal block descriptor
-	lm     %r2,%r3,0(%r8)           # pass block descriptor
-	bas    %r14,_extract_length-0b(%r13)   # get length from descriptor
-	lr     %r3,%r2                  # move length to an odd register
-	lr     %r2,%r11                 # move address to an even register
-	alr    %r11,%r3                 # add length to load address
-	slr    %r5,%r5                  # set length of source to zero
-3:	mvcle  %r2,%r4,0                # clear storage
-	bo     3b-0b(%r13)	
-	b      5f-0b(%r13)
-4:	lm     %r2,%r3,0(%r8)           # pass block descriptor
-	lr     %r4,%r12                 # pass device subchannel id
-        lr     %r5,%r11                 # pass load address
-        bas    %r14,_load_direct-0b(%r13) # load indirect block
-	lr     %r11,%r2                 # move updated load address
-5:	la     %r8,8(%r8)               # next descriptor
-	bct    %r9,2b-0b(%r13)
-	lm     %r2,%r3,0(%r8)           # load continuation descriptor
-	lr     %r4,%r12                 # move device id for next round
-	lr     %r5,%r11			# move load address for next round
-	clc    0(8,%r8),8f-0b(%r13)     # test continuation descriptor
-	bne    1b-0b(%r13)              # != 0 -> load next indirect block
-6:      lr     %r2,%r11                 # return updated load address
-	lm     %r6,%r15,120(%r15)
-        br     %r14
-7:      .long  96
-8:      .long  0,0
-9:      .long  0x8200                   # memory address for indirect blocks
-
-        .endm
-
-	.macro device_fn
-#
-# Enable I/O on the ipl device. 
-#   %r2 : device subchannel id
-# Return:
-#   %r2 : lpum of subchannel
-#
-_enable_device:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      s      %r15,4f-0b(%r13)
-	lr     %r1,%r2
-	l      %r2,7f-0b(%r13)          # set panik code early
-        stsch  5f-0b(%r13)
-	brc    1,3f		        # panic if not operational
-        oi     5f-0b+5(%r13),0x80       # enable subchannel
-	lhi    %r6,256			# r6 retry counter
-1: # modify subchannel
-        msch   5f-0b(%r13)
-	brc    6,2f        		# status pending or busy
-	brc    1,3f		        # panic if not operational
-	lctl   %c6,%c6,6f-0b(%r13)      # enable all interrupt classes
-	sr     %r2,%r2
-	ic     %r2,10+5f-0b(%r13)	# return lpum in r2
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-2: # clear status and retry
-	tsch   __LC_IRB
-	brc    1,3f		        # panic if not operational
-	brct   %r6,1b			# retry
-3: # panic
-	b      _panik-0b(%r13)          # panic
-4:	.long  96
-	.align 8
-5:	.fill  64,1,0
-6:	.long  0xff000000               # CR6 initial value
-7:      .long  EENABLE_DEV
-
-#
-# Disable I/O on the ipl device.
-#   %r2 : device subchannel id
-#
-_disable_device:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      s      %r15,4f-0b(%r13)
-	lr     %r1,%r2
-	l      %r2,6f-0b(%r13)          # set panik code early
-	lctl   %c6,%c6,5f-0b(%r13)      # disable all interrupt classes
-        stsch  5f-0b(%r13)
-	brc    1,3f			# panic if not operational
-        ni     5f-0b+5(%r13),0x7F       # disable subchannel
-	lhi    %r6,256			# r6 retry counter
-1: # modify subchannel
-        msch   5f-0b(%r13)
-	brc    6,2f			# status pending or busy
-	brc    1,3f			# panic if not operational
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-2: # clear status and retry
-	tsch   __LC_IRB
-	brc    1,3f			# panic if not operational
-	brct   %r6,1b
-3: # panic
-	b      _panik-0b(%r13)          # panic
-4:	.long  96
-        .align 8
-5:	.long  0x00000000               # CR6 (all interrupts classes disabled)
-6:      .long  EDISABLE_DEV
-	.endm	
-
-	.macro io_subroutines
-
-
-__LC_IO_NEW_PSW		= 0x78
-__LC_SUBCHANNEL_ID	= 0xb8
-
-#
-# Wait for I/O interrupt.
-#
-# Wait until status for the specified subchannel is available.
-#
-#   %r2 : subchannel id
-#   %r3 : address of irb
-#
-
-_wait_for_int:
-	lr     %r1,%r2
-	basr   %r4,0			# get base register
-0:
-	mvc    __LC_IO_NEW_PSW(8),4f-0b(%r4) # set i/o new psw
-1: # wait
-	lpsw   3f-0b(%r4)
-2: # continue
-	tsch   0(%r3)			# get status
-	brc    4,1b			# if cc=1 goto wait
-	br     %r14			# return
-        .align 8
-3:
-	.long  0x020a0000,0x80000000+1b	# enabled wait psw
-4:
-	.long  0x00080000,0x80000000+2b	# io new psw
-
-#
-# Start I/O
-#
-# Attempt to start I/O defined by ORB on specified subchannel. Retry I/O
-# 256 times per path (recommended error recovery procedure for IFCCs) unless
-# a permanent path error condition is indicated. Try all paths twice to try to
-# work around "link flapping" (paths going down once each in the same order as
-# they are tried). Perform CLEAR SUBCHANNEL when switching paths to clear any
-# improper subchannel status.
-#
-#   %r2 : subchannel id
-#   %r3 : address of orb
-#   %r4 : address of irb
-#
-_ssch:
-	stm    %r6,%r15,24(%r15)
-	basr   %r13,0			# get base register
-0:
-	ahi    %r15,-96			# create stack frame
-	lr     %r6,%r2			# r6:  sid
-	lr     %r7,%r3			# r7:  orb
-	lr     %r8,%r4			# r8:  irb
-	sr     %r9,%r9			# r9:  initial lpm
-	ic     %r9,.Llpm-0b(%r13)
-	l      %r10,.Lmask-0b(%r13)	# r10: path mask
-1: # restart_all
-	lhi    %r11,256			# r11: retry counter
-2: # restart
-	stc    %r9,6(%r7)		# store initial lpm in orb
-	ltr    %r9,%r9			# if non-zero initial lpm
-	jne    3f			# then use initial lpm
-	stc    %r10,6(%r7)		# else use current path mask
-3: # gotlpm
-	lr     %r1,%r6			# get sid
-	ssch   0(%r7)			# start subchannel
-	brc    1,7f			# if cc==3 goto next_path
-	brc    7,6f                     # if cc!=0 goto retry
-4: # wait_for_int_loop
-	lr     %r2,%r6			# get sid
-	lr     %r3,%r8			# get irb
-	bras   %r14,_wait_for_int	# wait for interrupt
-	jnz    9f			# if cc!=0 goto panic
-	tm     0(%r8),0x3		# test irb deferred cc
-	brc    1,7f			# if cc==3 goto next_path
-	jz     5f			# if cc==0 goto no_stctl_check
-	tm     3(%r8),0x10		# test irb status control
-	jnz    6f			# if alert goto retry
-5: # no_stctl_check
-	tm     9(%r8),0xff		# test irb subchannel status
-	jnz    6f			# if status!=0 goto retry
-	tm     8(%r8),0xf3		# test irb unusual device status
-	jnz    6f			# if status!=0 goto retry
-	tm     8(%r8),0x4		# test irb device end
-	jz     4b			# if !device_end goto wait_for_int_loop
-	lm     %r6,%r15,120(%r15)
-	br     %r14			# return
-
-6: # retry
-	lr     %r1,%r6			# get sid
-	tsch   0(%r8)			# clear status if necessary
-	brct   %r11,2b			# if --retries>0 goto restart
-7: # next_path
-	ltr    %r9,%r9			# if initial lpm != 0
-	jnz    8f			# then goto noshift
-	srl    %r10,1			# path_mask >>= 1
-	ltr    %r10,%r10		# if path_mask==0
-	jz     9f			# then goto panic
-8: # noshift
-	sr     %r9,%r9			# clear initial lpm
-	lr     %r1,%r6			# get sid
-	csch				# clear subchannel
-	brc    7,9f			# if cc!=0 goto panic
-	lr     %r2,%r6			# get sid
-	lr     %r3,%r8			# get irb
-	bras   %r14,_wait_for_int	# wait for interrupt
-	j      1b			# goto restart_all
-9: # panic
-	l      %r2,.Lerrno-0b(%r13)	# get error code
-	bras   %r14,_panik		# panic
-
-.Lerrno:
-	.long  ESSCH
-.Lmask:
-	.long  0x8080
-.Llpm:
-	.byte  0x00
-	.align 2
-
-#
-# Panik routine. Loads a disabled wait psw
-#   %r2 : panik code
-#
-_panik:
-	basr   %r1,0
-0:	st     %r2,1f-0b+4(%r1)         # store code in address part of psw
-	lpsw   1f-0b(%r1)
-	.align 8
-1:	.long  0x000a0000,0x00000000
-        .endm
--- /dev/null
+++ b/zipl/boot/eckd.h
@@ -0,0 +1,42 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * DASD ECKD specific functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ *
+ */
+
+#ifndef ECKD_H
+#define ECKD_H
+
+#include "stage2.h"
+
+/* CCW COMMANDS */
+#define DASD_ECKD_CCW_SEEK		0x07
+#define DASD_ECKD_CCW_TIC		0x08
+#define DASD_ECKD_CCW_SEARCH		0x31
+#define DASD_ECKD_CCW_READ_MT		0x86
+
+struct ch_t {
+	uint16_t cyl;
+	uint16_t head;
+} __packed;
+
+struct chr_t {
+	uint16_t cyl;
+	uint16_t head;
+	uint8_t record;
+} __packed __aligned(8);
+
+struct seek_arg {
+	uint16_t zeroes;
+	struct ch_t ch;
+} __packed __aligned(8);
+
+struct indirect_block {
+	uint64_t *block;
+} __packed;
+
+#endif /* ECKD_H */
--- a/zipl/boot/eckd0.S
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-#  Ipl stage 0 loader
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Antoinette Kaschner (anto@de.ibm.com),
-#
-#  startup for ipl at address 0
-#  second stage boot loader is loaded to 0x2000 and starts at 0x2008
-
-# The first 24 bytes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
-# The 1st CCW is used to read IPL2 record.
-# The 2nd CCW is a TIC to the end of the IPL2 record to a read.
-
-	.org   0x0
-	.globl _start
-_start:
-	.long  0x00080000,0x80002008           # PSW :the first 24 byte are loaded by IPL 
-        .long  0x06000218,0x60000090           # read IPL record 2  
-        .long  0x08000228,0x00000000           # TIC to seek/search/tic/read at end of IPL2   
-
-
-
--- /dev/null
+++ b/zipl/boot/eckd0_cdl.S
@@ -0,0 +1,20 @@
+#
+# IPL stage 0 loader for ECKD Compatible Disk Layout (CDL)
+#
+# Copyright IBM Corp. 2001, 2012
+# Author(s): Antoinette Kaschner (anto@de.ibm.com)
+#            Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Startup for IPL at address 0
+# Second stage boot loader is loaded to 0x2000 and starts at 0x2018
+#
+# The first 24 bytes are loaded by IPL to addresses 0-23 (PSW and two CCWs).
+# The 1st CCW reads stage 1 IPL record.
+# The 2nd CCW tics to the loaded stage 1 IPL record.
+#
+	.org   0x0
+	.globl _start
+_start:
+	.long  0x00080000,0x80002018 # PSW :the first 24 byte are loaded by IPL
+	.long  0x06000018,0x60000068 # read IPL record 2
+	.long  0x08000018,0x00000000 # TIC to stage 1
--- /dev/null
+++ b/zipl/boot/eckd0_ldl.S
@@ -0,0 +1,21 @@
+#
+# IPL stage 0 loader for ECKD Linux Disk Layout (LDL)
+#
+# Copyright IBM Corp. 2001, 2012
+# Author(s): Antoinette Kaschner (anto@de.ibm.com)
+#            Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Startup for IPL at address 0
+# Second stage boot loader is loaded to 0x2000 and starts at 0x2018
+#
+# The first 24 bytes are loaded by IPL to addresses 0-23 (PSW and two CCWs).
+# The 1st CCW rewinds to record zero (read record zero)
+# The 2nd CCW reads stage 1 IPL record (re-read record 1) and continues with
+# command chaining at address 0x18
+#
+	.org   0x0
+	.globl _start
+_start:
+	.long  0x00080000,0x80002018 # PSW :the first 24 byte are loaded by IPL
+	.long  0x16002000,0x60000016 # Read record zero
+	.long  0x06000000,0x60000080 # Read IPL record 1 again
--- a/zipl/boot/eckd1.S
+++ b/zipl/boot/eckd1.S
@@ -1,35 +1,36 @@
 #
-#  Ipl stage 1 loader
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Antoinette Kaschner (anto@de.ibm.com),
+# IPL stage 1 loader for ECKD
 #
-#  startup for ipl at address 0
-#  second stage boot loader is loaded to 0x2000 and starts at 0x2008
+# Copyright IBM Corp. 2001, 2012
+# Author(s): Antoinette Kaschner (anto@de.ibm.com)
+#            Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Stage 1 is loaded to 0x18-0x80 and is used to load stage 1b (two blocks) with
+# seek/search/tic/read CCWs. After stage 1b is loaded we tic to it.
+
+	.globl _start
+_start:
+	.long  0x07000000+.Lseek1,0x60000006    # seek 1
+.Lsearch1:
+	.long  0x31000000+.Lseek1+2,0x60000005  # search
+	.long  0x08000000+.Lsearch1,0x00000000  # tic back to search until found
+	.long  0x06000000,0x40000000            # read
+
+	.long  0x07000000+.Lseek2,0x60000006    # seek 2
+.Lsearch2:
+	.long  0x31000000+.Lseek2+2,0x60000005  # search
+	.long  0x08000000+.Lsearch2,0x00000000  # tic back to search until found
+	.long  0x06000000,0x40000000            # read
+.Ltick:
+	.long  0x08000000,0x00000000            # tic to stage 1b
+.Lseek1:
+	.long  0x00000000,0x00000000            # seekarg 1
+.Lseek2:
+	.long  0x00000000,0x00000000            # seekarg 2
 
-# The first 24 bytes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
-# IPL1 record TICs to IPL2 record at offset X'68' .Byte 0 to 68 of IPL2 contains boot load data.
-# The seek/search/tic/read CCWs at the end of IPL2 record reads  record 2 on disk into storage at
-# location X200.	 
-	
-	
-		.org   0x18
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x00000000,0x00000000           # contains boot load data 
-	.long  0x07600006,0x00000000+.Lseek    # seek  
-.Lsearch:	
-	.long  0x31600005,0x00000000+.Lseek+2  # search
-	.long  0x08000000,0x00000000+.Lsearch  # tic back to search until found
-	.long  0x06200090,0x00000200           # read record 2 into storage
- .Lseek:
-	.long  0x00000000,0x00000200           # seekargument for cyl 0 hd 0 rec 2   
+	.long  0x00000000,0x00000000            # bootinfo
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
+.Lend:
--- a/zipl/boot/eckd1a.S
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-#  Ipl stage 1a loader classic version 
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Antoinette Kaschner (anto@de.ibm.com),
-#
-#  startup for ipl at address 0
-#  second stage boot loader is loaded to 0x2000 and starts at 0x2008
-
-# The first 24 bytes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
-# Byte 234 to 730 of IPL2 contains 
-# seek/search/tic/read CCWs , starting with reading record 4.	 
-	
-	
-	.globl _start
-_start:
-	.long  0x00000000,0x00000000            # bootlist data 
-	.long  0x00000000,0x00000000
-	.long  0x07000000+.Lseek1,0x60000006    # seek
-.Lsearch1:		
-	.long  0x31000000+.Lseek1+2,0x60000005  # search
-	.long  0x08000000+.Lsearch1,0x00000000  # tic back to search until found
-	.long  0x06000000,0x40000000            # read
-	.long  0x07000000+.Lseek2,0x60000006    # seek
-.Lsearch2:		
-	.long  0x31000000+.Lseek2+2,0x60000005  # search
-	.long  0x08000000+.Lsearch2,0x00000000  # tic back
-	.long  0x06000000,0x40000000            # read
-	.long  0x07000000+.Lseek3,0x60000006    # seek
-.Lsearch3:
-	.long  0x31000000+.Lseek3+2,0x60000005  # search
-	.long  0x08000000+.Lsearch3,0x00000000  # tic back
-	.long  0x06000000,0x40000000            # read
-	.long  0x07000000+.Lseek4,0x60000006    # seek
-.Lsearch4:
-	.long  0x31000000+.Lseek4+2,0x60000005  # search
-	.long  0x08000000+.Lsearch4,0x00000000  # tic back
-	.long  0x06000000,0x40000000            # read
-	.long  0x07000000+.Lseek5,0x60000006    # seek
-.Lsearch5:	                                                 
-	.long  0x31000000+.Lseek5+2,0x60000005  # search
-	.long  0x08000000+.Lsearch5,0x00000000  # tic back 
-	.long  0x06000000,0x40000000            # read     
-	.long  0x07000000+.Lseek6,0x60000006    # seek
-.Lsearch6:	                                                 
-	.long  0x31000000+.Lseek6+2,0x60000005  # search
-        .long  0x08000000+.Lsearch6,0x00000000  # tic back 
-        .long  0x06000000,0x40000000            # read     
-	.long  0x07000000+.Lseek7,0x60000006    # seek
-.Lsearch7:	                                                 
-	.long  0x31000000+.Lseek7+2,0x60000005  # search
-        .long  0x08000000+.Lsearch7,0x00000000  # tic back 
-        .long  0x06000000,0x40000000            # read     
-	.long  0x07000000+.Lseek8,0x60000006    # seek
-.Lsearch8:	                                                 
-	.long  0x31000000+.Lseek8+2,0x60000005  # search
-        .long  0x08000000+.Lsearch8,0x00000000  # tic back 
-        .long  0x06000000,0x40000000            # read     				
-.Lseek1:
-	.long  0x00000000,0x00000400           # seekargument for cyl 0 hd 0 rec 4   
-.Lseek2:
-	.long  0x00000000,0x00000000
-.Lseek3:	
-	.long  0x00000000,0x00000000
-.Lseek4:	
-	.long  0,0
-.Lseek5:	
-	.long  0,0
-.Lseek6:				
-	.long  0,0
-.Lseek7:
-	.long  0,0
-.Lseek8:	
-	.long  0,0	
-
-.Lend:
-
-
-
-
--- a/zipl/boot/eckd1b.S
+++ b/zipl/boot/eckd1b.S
@@ -1,37 +1,184 @@
 #
-#  Ipl stage 1b loader new disk layout
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Antoinette Kaschner (anto@de.ibm.com),
+# IPL stage 1b loader for ECKD
+#
+# Copyright IBM Corp. 2012
+#
+# Author(s): Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Stage 1b is loaded to 0xe000-0xe400 and is used to load stage 2 with
+# seek/search/tic/read CCWs. Currently stage 1b can load up to 16
+# blocks and therefore 8 KiB stage 2 code with 512 byte block size.
 #
-#  startup for ipl at address 0
-#  second stage boot loader is loaded to 0x2000 and starts at 0x2008
 
-# The first 24 bytes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
-# IPL1 record TICs to IPL2 record at offset X'218' .Byte 218 to 362 of IPL2 contains 
-# seek/search/tic/read CCWs .	 
-	
-	
 	.globl _start
 _start:
-	.long  0,0                             # bootlist data
+	.long  0x07000000+.Lseek1,0x60000006     # seek
+.Lsearch1:
+	.long  0x31000000+.Lseek1+2,0x60000005   # search
+	.long  0x08000000+.Lsearch1,0x00000000   # tic back until found
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek2,0x60000006     # seek
+.Lsearch2:
+	.long  0x31000000+.Lseek2+2,0x60000005   # search
+	.long  0x08000000+.Lsearch2,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek3,0x60000006     # seek
+.Lsearch3:
+	.long  0x31000000+.Lseek3+2,0x60000005   # search
+	.long  0x08000000+.Lsearch3,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek4,0x60000006     # seek
+.Lsearch4:
+	.long  0x31000000+.Lseek4+2,0x60000005   # search
+	.long  0x08000000+.Lsearch4,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek5,0x60000006     # seek
+.Lsearch5:
+	.long  0x31000000+.Lseek5+2,0x60000005   # search
+	.long  0x08000000+.Lsearch5,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek6,0x60000006     # seek
+.Lsearch6:
+	.long  0x31000000+.Lseek6+2,0x60000005   # search
+	.long  0x08000000+.Lsearch6,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek7,0x60000006     # seek
+.Lsearch7:
+	.long  0x31000000+.Lseek7+2,0x60000005   # search
+	.long  0x08000000+.Lsearch7,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek8,0x60000006     # seek
+.Lsearch8:
+	.long  0x31000000+.Lseek8+2,0x60000005   # search
+	.long  0x08000000+.Lsearch8,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek9,0x60000006     # seek
+.Lsearch9:
+	.long  0x31000000+.Lseek9+2,0x60000005   # search
+	.long  0x08000000+.Lsearch9,0x00000000   # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek10,0x60000006    # seek
+.Lsearch10:
+	.long  0x31000000+.Lseek10+2,0x60000005  # search
+	.long  0x08000000+.Lsearch10,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek11,0x60000006    # seek
+.Lsearch11:
+	.long  0x31000000+.Lseek11+2,0x60000005  # search
+	.long  0x08000000+.Lsearch11,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek12,0x60000006    # seek
+.Lsearch12:
+	.long  0x31000000+.Lseek12+2,0x60000005  # search
+	.long  0x08000000+.Lsearch12,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek13,0x60000006    # seek
+.Lsearch13:
+	.long  0x31000000+.Lseek13+2,0x60000005  # search
+	.long  0x08000000+.Lsearch13,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek14,0x60000006    # seek
+.Lsearch14:
+	.long  0x31000000+.Lseek14+2,0x60000005  # search
+	.long  0x08000000+.Lsearch14,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek15,0x60000006    # seek
+.Lsearch15:
+	.long  0x31000000+.Lseek15+2,0x60000005  # search
+	.long  0x08000000+.Lsearch15,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek16,0x60000006    # seek
+.Lsearch16:
+	.long  0x31000000+.Lseek16+2,0x60000005  # search
+	.long  0x08000000+.Lsearch16,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek17,0x60000006    # seek
+.Lsearch17:
+	.long  0x31000000+.Lseek17+2,0x60000005  # search
+	.long  0x08000000+.Lsearch17,0x00000000  # tic back until found
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek18,0x60000006    # seek
+.Lsearch18:
+	.long  0x31000000+.Lseek18+2,0x60000005  # search
+	.long  0x08000000+.Lsearch18,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek19,0x60000006    # seek
+.Lsearch19:
+	.long  0x31000000+.Lseek19+2,0x60000005  # search
+	.long  0x08000000+.Lsearch19,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek20,0x60000006    # seek
+.Lsearch20:
+	.long  0x31000000+.Lseek20+2,0x60000005  # search
+	.long  0x08000000+.Lsearch20,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek21,0x60000006    # seek
+.Lsearch21:
+	.long  0x31000000+.Lseek21+2,0x60000005  # search
+	.long  0x08000000+.Lsearch21,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek22,0x60000006    # seek
+.Lsearch22:
+	.long  0x31000000+.Lseek22+2,0x60000005  # search
+	.long  0x08000000+.Lsearch22,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek23,0x60000006    # seek
+.Lsearch23:
+	.long  0x31000000+.Lseek23+2,0x60000005  # search
+	.long  0x08000000+.Lsearch23,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+	.long  0x07000000+.Lseek24,0x60000006    # seek
+.Lsearch24:
+	.long  0x31000000+.Lseek24+2,0x60000005  # search
+	.long  0x08000000+.Lsearch24,0x00000000  # tic back
+	.long  0x06000000,0x40000000             # read
+.Lseek1:
+	.long  0,0
+.Lseek2:
+	.long  0,0
+.Lseek3:
+	.long  0,0
+.Lseek4:
+	.long  0,0
+.Lseek5:
+	.long  0,0
+.Lseek6:
+	.long  0,0
+.Lseek7:
+	.long  0,0
+.Lseek8:
+	.long  0,0
+.Lseek9:
+	.long  0,0
+.Lseek10:
+	.long  0,0
+.Lseek11:
+	.long  0,0
+.Lseek12:
+	.long  0,0
+.Lseek13:
+	.long  0,0
+.Lseek14:
+	.long  0,0
+.Lseek15:
+	.long  0,0
+.Lseek16:
+	.long  0,0
+.Lseek17:
+	.long  0,0
+.Lseek18:
+	.long  0,0
+.Lseek19:
+	.long  0,0
+.Lseek20:
+	.long  0,0
+.Lseek21:
+	.long  0,0
+.Lseek22:
+	.long  0,0
+.Lseek23:
+	.long  0,0
+.Lseek24:
 	.long  0,0
-	.long  0x07000000+.Lseek,0x60000006    # seek  
-.Lsearch:	
-	.long  0x31000000+.Lseek+2,0x60000005  # search
-	.long  0x08000000+.Lsearch,0x00000000  # tic back to search until found
-	.long  0x06002000,0x60000000           # read record 4 into storage
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x60000000
-	.long  0x06000000,0x20000000 
-	  
-		
- .Lseek:
-	.long  0x00000000,0x00000400           # seekargument for cyl 0 hd 0 rec 4   
+.org 1024 # Stage 1b should have 1024 byte
+.Lend:
--- a/zipl/boot/eckd2.S
+++ /dev/null
@@ -1,124 +0,0 @@
-
-#
-#  Second stage boot loader for ckd/eckd devices.
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s):	 Martin Schwidefsky (schwidefsky@de.ibm.com),
-#                Antoinette Kaschner (anto@de.ibm.com),
-#
-# An ckd/eckd  loadlist  entry is 8 bytes in length and contains 3 entries:
-#   offset 0 :	 C C H H R  ( cyl head record )
-#   offset 5 :	 record length (16 bit)
-#   offset 7 :	 number of records(8 bit)
-
-STAGE2_DESC = 0x218
-
-#include "common.S"
-	
-# expand the common start code from iplcommon.s
-        stage2_start
-	
-# expand blocklist traversing code from iplcommon.s
-        blocklist_traverser
-	
-#
-# expand enable/disable routines
-        device_fn
-
-# parameter
-#   %r2+%r3: blocklist descriptor
-# returns
-#   %r2    : number of bytes (blocksize * number of blocks)
-_extract_length:
-	lr     %r2,%r3
-	sll    %r2,8
-	srl    %r2,16
-	sll    %r3,24
-	srl    %r3,24
-	la     %r3,1(%r3)
-	msr    %r2,%r3
-	br     %r14
-
-# parameter
-#   %r2+%r3: blocklist descriptor
-# returns
-#   %r2    : == 0 for normal block descriptor
-#            != 0 for zero block descriptor
-_is_zero_block:
-	srl    %r3,24
-	or     %r2,%r3
-	br     %r14
-
-# parameter
-#   %r2+%r3:	 recordlist descriptor  CCHHRLLn
-#   %r4    :	 device subchannel id
-#   %r5    :	 load address
-_load_direct:	
-        stm    %r6,%r15,24(%r15)        # save callers register
-        basr   %r13,0                   # base register
-.Lbase:	
-	s      %r15,.Lc96-.Lbase(%r13)  # new save area address
-        lr     %r12,%r5                 # save load address
-        lr     %r11,%r4                 # save subchannel id
-	stm    %r2,%r3,.Lsearch-.Lbase(%r13)         # get listdescriptor into search argument
-        slr    %r10,%r10                # clear reg 10
-	icm    %r10,1,.Lsearch+7-.Lbase(%r13)        # get record  number
-	la     %r10,1(%r10)             # add 1 to prevent negative value
-        slr    %r9,%r9                  # clear reg 9
-	icm    %r9,3,.Lsearch+5-.Lbase(%r13)       # get record size
-	sth    %r9,.Lread+2-.Lbase(%r13)  # store record size in read ccb
-        l      %r1,.Lprd-.Lbase(%r13)       # load address of ccw area
-        mvc    0(24,%r1),.Lccws-.Lbase(%r13)     # copy seek/search/tic ccws to chain
-	la     %r8,8(%r1)               # get address of search command
-	st     %r8,20(%r1)               # store  search address in tic	
-        la     %r1,24(%r1)              # advance ccw chain pointer
-	slr    %r3,%r3
-        b      .Llpst-.Lbase(%r13)
-.Lloop:
-	oi     1(%r1),0x40              # set command chain bit
-        la     %r1,8(%r1)               # update ccw pointer
-.Llpst:	
-	mvc    0(8,%r1),.Lread-.Lbase(%r13)    # copy read ccw to chain
-        st     %r12,4(,%r1)             # store load address to read ccw
-        alr    %r12,%r9                 # add record size to load address
-        bct    %r10,.Lloop-.Lbase(%r13)
-        ni     1(%r1),0xbf              # clear command chain bit
-        la     %r3,.Lorb-.Lbase(%r13)   # pass address of orb
-        la     %r4,.Lirb-.Lbase(%r13)   # and pass address of irb
-	lr     %r2,%r11                 # pass subchannel id
-        bas    %r14,_ssch-.Lbase(%r13)  # read records
-.Lexit:
-        lr     %r2,%r12                 # return updated load address
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-.Lc1:	   .long  1
-.Lc96:	  .long  96
-.Lc65535:	
-        .long  65535
-.Lprd:  .long  0x4000
-        .align 8
-.Lccws:	
-        .long 0x07600006,0x00000000+.Lseekarg	     # seek for CYL and TRK
-.Lsrch:	
-        .long 0x31600005,0x00000000+.Lsearch        # search for record
-	
-        .long 0x08000000,0x00000000                 # tic
-.Lread:	
-        .long 0x86200000,0x00000000                 # read record into storage
-	
-.Lseekarg:
-	.word 0x0000                    # seek argument  
-                                        # format 00CCHH
-.Lsearch:	
-	.long 0x00000000,0x00000000     # search argument
-	#  format CCHHRLLn       	
-
-        .align 8   
-.Lirb:  .fill  64,1,0
-.Lorb:  .long  0x00000000,0x0080ff00,0x4000,0
-
-# expand io subroutines from iplcommon.s
-        io_subroutines
-
-	# boot menu parameter area follows
-	menu_param_area
-
--- /dev/null
+++ b/zipl/boot/eckd2.c
@@ -0,0 +1,97 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Subroutines for ECKD disks.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "stage2.h"
+#include "eckd.h"
+#include "s390.h"
+
+int extract_length(void *data)
+{
+	struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
+
+	return blockptr->size * (blockptr->blockct + 1);
+}
+
+int is_zero_block(void *data)
+{
+	struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
+
+	return blockptr->cyl  || blockptr->head || blockptr->sec;
+}
+
+void * load_direct(disk_blockptr_t *data, struct subchannel_id subchannel_id,
+	    void *load_addr)
+{
+	struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
+	struct ccw1 *ccws;
+	unsigned long record_size;
+	struct seek_arg seek_addr;
+	struct chr_t search_arg;
+	int record_number;
+	struct irb *irb;
+	struct orb orb;
+	int i = 3;
+
+	irb = (struct irb *)&S390_lowcore.irb;
+
+	memset(irb, 0, sizeof(struct irb));
+	memset(&orb, 0, sizeof(struct orb));
+	memset(&seek_addr, 0, sizeof(struct ch_t));
+	memset(&search_arg, 0, sizeof(struct chr_t));
+
+	ccws = (struct ccw1 *)get_zeroed_page();
+
+	/* initialise SEEK, SEARCH and TIC CCW*/
+	ccws[0].cmd_code = DASD_ECKD_CCW_SEEK;
+	ccws[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+	ccws[0].count = 6;
+	seek_addr.ch.cyl = blockptr->cyl;
+	seek_addr.ch.head = blockptr->head;
+	ccws[0].cda = (uint32_t) (unsigned long) &seek_addr;
+
+	record_number = blockptr->blockct;
+	record_size = blockptr->size;
+
+	ccws[1].cmd_code = DASD_ECKD_CCW_SEARCH;
+	ccws[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+	ccws[1].count = 5;
+	search_arg.cyl = blockptr->cyl;
+	search_arg.head = blockptr->head;
+	search_arg.record = blockptr->sec;
+	ccws[1].cda = (uint32_t) (unsigned long) &search_arg;
+
+	ccws[2].cmd_code = DASD_ECKD_CCW_TIC;
+	ccws[2].flags = 0;
+	ccws[2].count = 0;
+	ccws[2].cda = (uint32_t) (unsigned long) &ccws[1];
+
+	/* initialise READ CCWs */
+	while (1) {
+		ccws[i].cmd_code = DASD_ECKD_CCW_READ_MT;
+		ccws[i].flags = CCW_FLAG_SLI;
+		ccws[i].count = record_size;
+		ccws[i].cda = (uint32_t) (unsigned long) load_addr;
+
+		record_number--;
+		load_addr += record_size;
+		i++;
+
+		if (record_number >= 0)
+			ccws[i-1].flags |= CCW_FLAG_CC;
+		else
+			break;
+	}
+	orb.fmt = 1;
+	orb.cpa = (uint32_t) (unsigned long) ccws;
+
+	start_io(subchannel_id, irb, &orb);
+
+	free_page((unsigned long)ccws);
+	return load_addr;
+}
--- a/zipl/boot/eckd2dump.S
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- *  Dump boot loader for 3380/3390 DASDs
- *    Copyright IBM Corp. 2001, 2006.
- *    Author(s): Michael Holzheu  <holzheu@de.ibm.com>
- *               Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *               
- * Uses extern functions:            
- *  - _panik
- *  - _enable_device
- *  - _take_dump
- *
- * Functions:
- *  - _dump_mem
- */
-
-#include "dumpcommon.S"
-#if defined(__s390x__)
-#define USE_64BIT_SCLP
-#endif
-#include "sclp.S"
-
-/* General defines */
-
-#define IPL_BS 0x2000
-#define BLOCKS_PER_WRITE 64                    /* makes 256K with 4K blksize */
-
-################################################################################
-# Function entry point at 0x2000 (not used for dump) is called with C linkage
-#   %r2-%r3: load descriptor
-#   %r3    : device subchannel id
-#   %r4    : load address
-################################################################################
-
-#if defined(__s390x__)
-dump_magic:  .long 0x5a45434b, 0x44363402 # "ZECKD64", version 2
-#else
-dump_magic:  .long 0x5a45434b, 0x44333102 # "ZECKD31", version 2
-#endif
-
-#if defined(__s390x__)
-
-
-/******************************** 64 BIT **************************************/
-
-
-################################################################################
-# Program execution of the second stage boot loader starts at 0x2008
-################################################################################
-
-        .globl _start
-_start: 
-        basr  %r13,0
-.Linit_base:
-        la    %r9,0
-        st    %r9,.Ldh_arch-.Linit_base(%r13) # init arch 
-        l     %r15,1f-.Linit_base(%r13)       # load end of stack address
-        la    %r7,0
-        tm    __LC_ARCH_MODE_ID(%r9),0x01     # check arch mode
-        bnz   .Larch_64-.Linit_base(%r13)
-
-        /* 32 bit store status */
-
-        l     %r14,.Lstore_status_32-.Linit_base(%r13)
-        basr  %r14,%r14
-        la    %r10,ARCH_S390_ID
-        st    %r10,.Ldh_arch-.Linit_base(%r13)
-
-.Larch_64:
-        la    %r7,2                             # first try code 2:
-        la    %r6,0                             # 64 bit psws are restored
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-        bc    8,.Lswitched_64-.Linit_base(%r13) # order accepted ?
-        la    %r7,1                             # code 2 failed - try code 1
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-.Lswitched_64:
-        sam64                                   # switch to 64 bit addr mode
-        basr   %r13,0
-0:      llgf   %r15,1f-0b(%r13)                 # load end of stack address
-        
-        llgf   %r10,.Ldh_arch-0b(%r13)
-        cghi   %r10,ARCH_S390_ID
-        be     .Larch_32-0b(%r13)
-
-        /* 64 bit store status */
-
-        llgf   %r14,.Lstore_status_64-0b(%r13)
-        basr   %r14,%r14
-        lghi   %r10,ARCH_S390X_ID
-        st     %r10,.Ldh_arch-0b(%r13)
-
-.Larch_32:
-        llgf   %r2,IPL_SC                   # load ipl device subchannel id
-        llgf   %r14,.Lenable_device_64-0b(%r13)
-        basr   %r14,%r14
-        bas    %r14,_get_device_characteristics_64-0b(%r13)
-        llgf   %r5,.Ldev_blk_size-0b(%r13)  # get blocksize
-        stcm   %r5,3,.Lwrccw+2-0b(%r13)     # store blocksize into wr template
-        stcm   %r5,3,.Llodata+14-0b(%r13)   # store blocksize into lodata
-        llgf   %r14,.Ltake_dump_64-0b(%r13)
-        basr   %r14,%r14
-1:      .long  0x10000-128                  # end of stack
-
-################################################################################
-# Get the device characteristics:
-#  - no parameters
-#
-# Get device characteristics from zipl parameters (at 0x218)
-# The following parameter format is expected 2x8 byte:
-#
-# struct eckd_dump_param {
-#       uint32_t        start_blk;
-#       uint32_t        end_blk;
-#       uint16_t        blocksize;
-#       uint8_t.        num_heads;
-#       uint8_t.        bpt;
-#       char            reserved[4];
-# } __attribute((packed));
-################################################################################
-
-_get_device_characteristics_64:
-        stmg   %r6,%r15,48(%r15)
-        basr   %r13,0                   # base register
-0:      aghi   %r15,-200                # create stack frame
-
-        mvc    .Ldev_start_blk-0b(4,%r13),0x218(%r0)
-        mvc    .Ldev_end_blk-0b(4,%r13),0x21c(%r0)
-        mvc    .Ldev_blk_size-0b+2(2,%r13),0x220(%r0)
-        mvc    .Ldev_nr_hds-0b+3(1,%r13),0x222(%r0)
-        mvc    .Ldev_bpt-0b+3(1,%r13),0x223(%r0)
-        lmg    %r6,%r15,248(%r15)
-        br     %r14
-
-################################################################################
-# Dump memory
-#  -no parameters
-################################################################################
-
-_dump_mem_64:    
-        stmg   %r6,%r15,48(%r15)
-        basr   %r13,0                         # base register
-0:      aghi   %r15,-200                      # create stack frame
-
-	# init progress bar
-
-	bras %r14,_init_print_progress_64
-
-        # calculate bytes per write (blksize * blwr)
-
-        llgf    %r11,.Ldev_blk_size-0b(%r13)
-        mh      %r11,.Lblocks_per_write-0b(%r13)
-        st      %r11,.Lbytes_per_write-0b(%r13)
-
-# write header
-
-.Lheaders:                                    # write dump headers
-        llgf    %r11,.Ldev_start_blk-0b(%r13) # start block
-
-        lgr     %r2,%r11
-        lghi    %r3,HEADER_PAGE_START
-        lghi    %r4,HEADER_SIZE
-        srda    %r4,32                        # shift ==> 64 bit number        
-        llgf    %r6,.Ldev_blk_size-0b(%r13)   # get blocksize
-
-        dr      %r4,%r6                       # nr of blocks for header = 
-                                              # HEADER_SIZE / BLOCKSIZE = r5
-        lgr     %r4,%r5
-        lgr     %r12,%r5                      # save nr of blocks        
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-        ar      %r11,%r12                     # update block counter
-
-.Lmemory:                                     # write memory
-
-# write memory
-
-        lghi    %r10,0                        # start at address 0
-.Lmloop:        
-        lghi    %r4,BLOCKS_PER_WRITE          # write so many blocks at a time
-        lgr     %r2,%r11                      # restore r2
-        lgr     %r3,%r10                      # restore r3
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-        llgf    %r2,.Lbytes_per_write-0b(%r13)
-        agr     %r10,%r2                      # update data address
-        aghi    %r11,BLOCKS_PER_WRITE         # skip to next block
-
-	lgr     %r2,%r10                      # print progress to console
-	bras    %r14,_print_progress_64
-
-        lg      %r3,.Ldh_mem_size-0b(%r13)    # get memsize
-        clgr    %r10,%r3                      # enough ?
-        bl      .Lmloop-0b(%r13)              # branch if r10 < r3
-
-# write end marker
-
-.lendmarker:                                  # terminate dump file
-        lghi    %r4,1                         # write endmaker with one block
-        stck    .Ld_end_time-0b(%r13)         # store end time
-        lgr     %r2,%r11                      # restore r2
-        la      %r3,.Ld_endmarker-0b(%r13)    # address of dump end marker
-        lghi    %r4,1                         # write 4k at a time
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-
-        lmg     %r6,%r15,248(%r15)
-        br      %r14                          # return to caller
-.Lbytes_per_write:  .long 0x00000000
-.Lblocks_per_write: .word BLOCKS_PER_WRITE
-
-################################################################################
-# This function writes a block number given in r2 to disk
-#  -r2:  number of first block to write ( input by caller )
-#        We start counting with Block Nr 0 !!!
-#  -r3:  address to write data from ( input by caller )
-#  -r4:  number of blocks to write ( input by caller )
-################################################################################
-
-_writeblock_64:
-        stmg    %r6,%r15,48(%r15)
-        basr    %r13,0                        # base register
-0:      aghi    %r15,-200                     # create stack frame
-
-        # check if blocks are within range:
-
-        lgr     %r11,%r2
-        agr     %r11,%r4                      # End block
-        llgf    %r12,.Ldev_end_blk-0b(%r13)
-        clgr    %r11,%r12                     # End block < dev_end_blk ?
-        bl      1f-0b(%r13)                   # no
-        la      %r2,EMEM                      # if yes panik
-        llgf    %r14,.Lpanik_64-0b(%r13)
-        basr    %r14,%r14 
-        
-1:      la      %r12,.Ldeccw-0b(%r13)
-        st      %r12,8+.Lorb-0b(%r13)         # store cpaddr to orb
-        la      %r12,.Lwrccw-0b(%r13) 
-        oi      1(%r12),0x40                  # set CC in wr template
-        oi      1(%r12),0x04                  # enable indirect data addressing 
-        la      %r10,.Lida_list-0b(%r13)      # pointer to ida list
-
-        # setup new pgc psw for finding invalid pages
-
-        mvc     .Lold_pgc_psw-0b(16,%r13),464(%r0)      # save old psw
-        mvc     464(16,%r0),.Lpage_invalid_psw-0b(%r13) # setup pgm check new
-
-        # first setup the write channel program
-
-        lgr     %r11,%r4                      # save number of blocks
-
-        llgf    %r6,.Ldev_bpt-0b(%r13)        # load bpt to r6
-        llgf    %r7,.Ldev_nr_hds-0b(%r13)     # load heads to r7
-        la      %r5,.Lwrloop-0b(%r13)
-        br      %r5 
-        
-2:      # loop for number of block (nbl) time  
-
-        # switch to next write CCW
-
-        llgf    %r5,.Ldev_blk_size-0b(%r13)
-        agr     %r3,%r5                       # add blksize to destination addr
-        aghi    %r12,8                        # add sizeof(ccw) to base address
-        aghi    %r10,8                        # next element in ida list
-        mvc     0(8,%r12),.Lwrccw-0b(%r13)    # copy template to this ccw
-
-.Lwrloop:       
-
-        # build up next write CCW
-
-        l       %r9,0(%r3)                    # test page
-        lgr     %r9,%r3
-        b       .Lpage_ok-0b(%r13) 
-.Lpage_invalid:
-	lghi    %r9,ZERO_PAGE_START
-
-.Lpage_ok:
-        stg     %r9,0(%r10)                   # store target addr to idalist
-
-        st      %r10,4(%r12)                  # store ida addr to this ccw
-        bct     %r4,2b-0b(%r13)               # decrement no of blks still to do
-        ni      1(%r12),0x3f                  # no command chaining for last ccw
-
-        # write CCWs are setup now               
-
-        lgr     %r4,%r11                      # restore number of blocks
-        stcm    %r4,3,.Llodata+2-0b(%r13)     # store number of blocks to lodata
-
-        # compute end block 
-
-        agr     %r4,%r2                       # r4: ebl = blk + nbl 
-        bctr    %r4,0                         # decrement r4 (last blk touched)        
-        
-        # compute start track and start block on track
-
-        srda    %r2,32                        # shift ==> 64 bit number 
-        dr      %r2,%r6                       # trk = blk / bpt, bot = blk % bpt 
-                                              # r3: trk, r2: bot
-        la      %r2,1(%r2)                    # bot++ ( we start counting at 1 )
-        stcm    %r2,1,.Llodata+12-0b(%r13)    # store bot to lodata
-
-        # compute start cylinder and head
-
-        xr      %r2,%r2                       # clear bot                  
-        dr      %r2,%r7                       # cy=trk / heads, hd=trk % heads
-                                              # r3: cy, r2: hd
-
-        lgr     %r8,%r3                       # r8=upper 12 bits of cylinder
-        srl     %r8,16                        # are coded into heads:
-        sll     %r8,4                         # c0c1c2h0 (2 byte)
-
-        sll     %r3,16                        # combine to CCHH in r3
-        or      %r3,%r2
-        or      %r3,%r8                       # add upper 12 bits
-        st      %r3,.Ldedata+8-0b(%r13)       # store cchh to dedata
-        st      %r3,.Llodata+4-0b(%r13)       # store cchh to lodata
-        st      %r3,.Llodata+8-0b(%r13)       # store cchh to lodata
-
-        # compute end track and end block on track
-
-        lgr     %r11,%r5                      # save r5
-        srda    %r4,32                        # shift ==> 64 bit number
-        dr      %r4,%r6                       # tr2 = ebl / bpt
-                                              # r5: tr2, r4: bot2
-        # compute end cylinder and head
-
-        xr      %r4,%r4                       # cy2=tr2/heads, hd2=hd2 % heads
-        dr      %r4,%r7                       # r5: cy2, r4: hd2
-
-        lgr     %r8,%r5                       # r8=upper 12 bits of cylinder
-        srl     %r8,16                        # are coded into heads:
-        sll     %r8,4                         # c0c1c2h0 (2 byte)
-        or      %r4,%r8
-
-        stcm    %r5,3,.Ldedata+12-0b(%r13)    # store cy2 to dedata
-        stcm    %r4,3,.Ldedata+14-0b(%r13)    # store hd2 to dedata
-        lgr     %r5,%r11                      # restore r5
-
-        # CCWs are setup now, arent they?
-
-        llgf    %r2,IPL_SC                    # subchannel id
-        la      %r3,.Lorb-0b(%r13)
-        la      %r4,.Ltmp_data-0b(%r13)       # irb
-        la      %r5,10                        # initialize retries
-
-        bas     %r14,_ssch_64-0b(%r13)        # start I/O
-
-        mvc     464(16,%r0),.Lold_pgc_psw-0b(%r13) # restore pgm check new
-        lmg     %r6,%r15,248(%r15)
-        br      %r14                          # return to caller
-.align 8
-.Lorb:
-        .long 0x0049504c,0x0082ff00
-        .long 0x00000000,0x00000000
-.Ldedata:
-        .long 0x80c00000,0x00000000
-        .long 0x00000000,0x00000000
-.Llodata:
-        .long 0x01800001,0x00000000
-        .long 0x00000000,0x03000000
-        .long 0x12345678,0x00000000
-.align 8
-.Lida_list:
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-.Lpage_invalid_psw:
-        .long 0x00000001,0x80000000,0x00000000,0x00000000 + .Lpage_invalid
-.Lold_pgc_psw:
-        .long 0x0,0x0,0x0,0x0 
-
-################################################################################
-# expand Macros
-################################################################################
-
-	hex_to_ebcdic
-	print_progress_64
-        dump_common_store_status_32
-        dump_common_fn_64
-        dump_io_subroutines_64
-        dump_header
-	dump_messages
-	tmp_data
-	sclp_base
-	sclp_print
-	sclp_read_info
-
-# extern functions
- 
-.Lpanik_64:
-        .long      _panik_64
-.Lenable_device_64:
-        .long      _enable_device_64
-.Ltake_dump_64:
-        .long      _take_dump_64
-.Lstore_status_32:
-        .long      _store_status_32
-.Lstore_status_64:
-        .long      _store_status_64
-
-
-
-
-
-#else /* __s390x__ */
-
-
-
-/******************************** 32 BIT **************************************/
-
-
-################################################################################
-# Program execution of the second stage boot loader starts at 0x2008
-################################################################################
-
-        .globl _start
-_start: basr   %r13,0
-0:      l      %r15,1f-0b(%r13)             # load end of stack address
-
-        tm    __LC_ARCH_MODE_ID,0x01        # check arch mode
-        bz   .Larch_31-0b(%r13)
-        la    %r10,ARCH_S390X_ID
-        st    %r10,.Ldh_arch-0b(%r13)
-
-.Larch_31:
-        l      %r11,IPL_SC                  # load ipl device subchannel id
-        lr     %r2,%r11
-        l      %r14,.Lenable_device_32-0b(%r13)
-        basr   %r14,%r14
-        bas    %r14,_get_device_characteristics_32-0b(%r13)
-        l      %r5,.Ldev_blk_size-0b(%r13)  # get blocksize
-        stcm   %r5,3,.Lwrccw+2-0b(%r13)     # store blocksize into wr template
-        stcm   %r5,3,.Llodata+14-0b(%r13)   # store blocksize into lodata
-        l      %r14,.Ltake_dump_32-0b(%r13)
-        basr   %r14,%r14
-1:      .long  0x10000-96                   # end of stack
-
-
-################################################################################
-# Get the device characteristics:
-#  - no parameters
-#
-# Get device characteristics from zipl parameters (at 0x218)
-# The following parameter format is expected 2x8 byte:
-#
-# struct eckd_dump_param {
-#       uint32_t        start_blk;
-#       uint32_t        end_blk;
-#       uint16_t        blocksize;
-#       uint8_t.        num_heads;
-#       uint8_t.        bpt;
-#       char            reserved[4];
-# } __attribute((packed));
-################################################################################
-
-_get_device_characteristics_32:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      s      %r15,.Lc96-0b(%r13)      # create stack frame
-        mvc    .Ldev_start_blk-0b(4,%r13),0x218(%r0)
-        mvc    .Ldev_end_blk-0b(4,%r13),0x21c(%r0)
-        mvc    .Ldev_blk_size-0b+2(2,%r13),0x220(%r0)
-        mvc    .Ldev_nr_hds-0b+3(1,%r13),0x222(%r0)
-        mvc    .Ldev_bpt-0b+3(1,%r13),0x223(%r0)
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-
-################################################################################
-# Dump memory
-#  - no parameters
-################################################################################
-
-_dump_mem_32:    
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                         # base register
-0:      s      %r15,.Lc96-0b(%r13)            # create stack frame
-
-	# init progress bar
-
-	bras %r14,_init_print_progress_32
-
-        # calculate bytes per write (blksize * blwr)
-
-        l       %r11,.Ldev_blk_size-0b(%r13)
-        mh      %r11,.Lblocks_per_write-0b(%r13)
-        st      %r11,.Lbytes_per_write-0b(%r13)
-
-# write header
-
-.Lheaders:                                    # write dump headers
-        l       %r11,.Ldev_start_blk-0b(%r13) # start block
-
-        lr      %r2,%r11
-        lhi     %r3,HEADER_PAGE_START
-        lhi     %r4,HEADER_SIZE
-        srda    %r4,32                        # shift ==> 64 bit number        
-        l       %r6,.Ldev_blk_size-0b(%r13)   # get blocksize
-
-        dr      %r4,%r6                       # nr of blocks for header = 
-                                              # HEADER_SIZE / BLOCKSIZE = r5
-        lr      %r4,%r5
-        lr      %r12,%r5                      # save nr of blocks        
-        bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-        ar      %r11,%r12                     # update block counter
-
-.Lmemory:                                     # write memory
-
-# write memory
-
-        la      %r10,0                        # start at address 0
-
-.Lmloop:        
-        la      %r4,BLOCKS_PER_WRITE          # write so many blocks at a time
-        lr      %r2,%r11                      # restore r2
-        lr      %r3,%r10                      # restore r3
-        bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-        l       %r2,.Lbytes_per_write-0b(%r13)
-        ar      %r10,%r2                      # update data address
-        ah      %r11,.Lblocks_per_write-0b(%r13) # skip to next block
-
-	lr      %r2,%r10                      # print progress to console
-	bras    %r14,_print_progress_32
-
-        l       %r3,.Ldh_mem_size+4-0b(%r13)  # get memsize
-        clr     %r10,%r3                      # enough ?
-        bl      .Lmloop-0b(%r13)              # branch if r10 < r3
-
-# write end marker
-
-.lendmarker:                                  # terminate dump file
-        la      %r4,1                         # write endmaker with one block
-        stck    .Ld_end_time-0b(%r13)         # store end time
-        lr      %r2,%r11                      # restore r2
-        la      %r3,.Ld_endmarker-0b(%r13)    # address of dump end marker
-        la      %r4,1                         # write 4k at a time
-        bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-
-        lm      %r6,%r15,120(%r15)
-        br      %r14                          # return to caller
-.Lbytes_per_write:  .long 0x00000000
-.Lblocks_per_write: .word BLOCKS_PER_WRITE
-
-################################################################################
-# This function writes a block number given in r2 to disk
-#  -r2:   number of first block to write ( input by caller )
-#         We start counting with Block Nr 0 !!!
-#  -r3:   address to write data from ( input by caller )
-#  -r4:   number of blocks to write ( input by caller )
-################################################################################
-
-_writeblock_32:
-        stm     %r6,%r15,24(%r15)
-        basr    %r13,0                        # base register
-0:      s       %r15,.Lc96-0b(%r13)           # create stack frame
-
-        # check if blocks are within range:
-        
-        lr      %r11,%r2
-        ar      %r11,%r4                      # End block
-        l       %r12,.Ldev_end_blk-0b(%r13)
-        clr     %r11,%r12                     # End block < dev_end_blk ?
-        bl      1f-0b(%r13)                   # no
-        la      %r2,EMEM                      # if yes panik
-        l       %r14,.Lpanik_32-0b(%r13)
-        basr    %r14,%r14 
-        
-1:      la      %r12,.Ldeccw-0b(%r13)
-        st      %r12,8+.Lorb-0b(%r13)         # store cpaddr to orb
-        la      %r12,.Lwrccw-0b(%r13) 
-        oi      1(%r12),0x40                  # set CC in wr template
-
-	# setup new pgc psw for finding invalid pages
-
-	mvc     .Lold_pgc_psw-0b(8,%r13),104(%r0)      # save old psw
-	mvc     104(8,%r0),.Lpage_invalid_psw-0b(%r13) # setup pgm check new
-
-        # first setup the write channel program
-
-        lr      %r11,%r4                      # save number of blocks
-
-        l       %r6,.Ldev_bpt-0b(%r13)        # load bpt to r6
-        l       %r7,.Ldev_nr_hds-0b(%r13)     # load heads to r7
-        la      %r5,.Lwrloop-0b(%r13)
-        br      %r5 /* FIXME */
-        
-2:      # loop for number of block (nbl) time  
-
-        # switch to next write CCW
-
-        l       %r5,.Ldev_blk_size-0b(%r13)
-        ar      %r3,%r5                       # add blksize to destination addr
-        ah      %r12,.Lccw_size-0b(%r13)      # add sizeof(ccw) to base address
-        mvc     0(8,%r12),.Lwrccw-0b(%r13)    # copy template to this ccw
-	
-.Lwrloop:       
-	l       %r9,0(%r3)                    # test page
-	lr      %r9,%r3
-	b       .Lpage_ok-0b(%r13)
-.Lpage_invalid:
-	lhi     %r9,ZERO_PAGE_START
-.Lpage_ok:
-        # build up next write CCW
-
-        st      %r9,4(%r12)                   # store target addr to this ccw
-        bct     %r4,2b-0b(%r13)               # decrement no of blks still to do
-        ni      1(%r12),0x3f                  # no command chaining for last ccw
-
-        # write CCWs are setup now               
-
-        lr      %r4,%r11                      # restore number of blocks
-        stcm    %r4,3,.Llodata+2-0b(%r13)     # store number of blocks to lodata
-
-        # compute end block 
-
-        ar      %r4,%r2                       # r4: ebl = blk + nbl 
-        bctr    %r4,0                         # decrement r4 (last blk touched)        
-        
-        # compute start track and start block on track
-
-        srda    %r2,32                        # shift ==> 64 bit number 
-        dr      %r2,%r6                       # trk = blk / bpt, bot = blk % bpt 
-                                              # r3: trk, r2: bot
-        la      %r2,1(%r2)                    # bot++ ( we start counting at 1 )
-        stcm    %r2,1,.Llodata+12-0b(%r13)    # store bot to lodata
-
-        # compute start cylinder and head
-
-        xr      %r2,%r2                       # clear bot                  
-        dr      %r2,%r7                       # cy=trk / heads, hd=trk % heads
-                                              # r3: cy, r2: hd
-
-        lr      %r8,%r3                       # r8=upper 12 bits of cylinder
-        srl     %r8,16                        # are coded into heads:
-        sll     %r8,4                         # c0c1c2h0 (2 byte)
-
-        sll     %r3,16                        # combine to CCHH in r3
-        or      %r3,%r2
-        or      %r3,%r8                       # add upper 12 bits
-        st      %r3,.Ldedata+8-0b(%r13)       # store cchh to dedata
-        st      %r3,.Llodata+4-0b(%r13)       # store cchh to lodata
-        st      %r3,.Llodata+8-0b(%r13)       # store cchh to lodata
-
-        # compute end track and end block on track
-
-        lr      %r11,%r5                      # save r5
-        srda    %r4,32                        # shift ==> 64 bit number
-        dr      %r4,%r6                       # tr2 = ebl / bpt
-                                              # r5: tr2, r4: bot2
-        # compute end cylinder and head
-
-        xr      %r4,%r4                       # cy2=tr2/heads, hd2=hd2 % heads
-        dr      %r4,%r7                       # r5: cy2, r4: hd2
-
-        lr      %r8,%r5                       # r8=upper 12 bits of cylinder
-        srl     %r8,16                        # are coded into heads:
-        sll     %r8,4                         # c0c1c2h0 (2 byte)
-        or      %r4,%r8
-
-        stcm    %r5,3,.Ldedata+12-0b(%r13)    # store cy2 to dedata
-        stcm    %r4,3,.Ldedata+14-0b(%r13)    # store hd2 to dedata
-        lr      %r5,%r11                      # restore r5
-
-        # CCWs are setup now, arent they?
-
-        l       %r2,IPL_SC                    # subchannel id
-        la      %r3,.Lorb-0b(%r13)
-        la      %r4,.Ltmp_data-0b(%r13)       # irb
-        la      %r5,10                        # initialize retries
-
-        bas     %r14,_ssch_32-0b(%r13)        # start I/O
-
-        mvc     104(8,%r0),.Lold_pgc_psw-0b(%r13) # restore pgm check new
-
-        lm      %r6,%r15,120(%r15)
-        br      %r14                          # return to caller
-.Lccw_size:
-        .word 0x8
-.align 8
-.Lorb:
-        .long 0x0049504c,0x0080ff00           # intparm is " IPL"
-        .long 0x00000000,0x00000000
-.Ldedata:
-        .long 0x80c00000,0x00000000
-        .long 0x00000000,0x00000000
-.Llodata:
-        .long 0x01800001,0x00000000
-        .long 0x00000000,0x03000000
-        .long 0x12345678,0x00000000
-.Lpage_invalid_psw:
-	.long  0x00080000,0x80000000 + .Lpage_invalid
-.Lold_pgc_psw:
-        .long 0x0,0x0
-
-################################################################################
-# expand Macros
-################################################################################
-
-	hex_to_ebcdic
-	print_progress_32
-        dump_common_fn_32
-        dump_io_subroutines_32
-	dump_messages
-        dump_header
-	tmp_data
-	sclp_base
-	sclp_print
-	sclp_read_info
-
-# extern functions
- 
-.Lpanik_32:
-        .long      _panik_32
-.Lenable_device_32:
-        .long      _enable_device_32
-.Ltake_dump_32:
-        .long      _take_dump_32
-
-#endif /* __s390x__ */
-
-
-################################################################################
-# DATA
-################################################################################
-
-.Lc96:  .long  96 # for creating stackframes
-
-# device characteristics
-.align 8
-.Ldev_blk_size:
-        .long  0x00000000
-.Ldev_nr_hds:
-        .long  0x00000000
-.Ldev_bpt:
-        .long  0x00000000
-.Ldev_start_blk:
-        .long  0x00000000
-.Ldev_end_blk:
-        .long  0x00000000
-
-
-
-#
-# CCWs
-#
-
-.align 8
-
-# channel program for one write
-
-.Ldeccw:
-        .long 0x63400010,0x00000000+.Ldedata     # define extent
-.Lloccw:
-        .long 0x47400010,0x00000000+.Llodata     # locate record
-.Lwrccw:
-        .long 0x8d000000,0x00000000              # update Key & data
-
-.org (IPL_BS - 8)
-.Lmem_upper_limit:
-        .long 0xffffffff,0xffffffff              # can be used for memsize=xxx
--- /dev/null
+++ b/zipl/boot/eckd2dump.c
@@ -0,0 +1,200 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common ECKD dump I/O functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include "eckd2dump.h"
+#include "stage2dump.h"
+#include "s390.h"
+#include "cio.h"
+#include "error.h"
+
+#define CMD_LOCATE_RECORD	0x47
+#define CMD_DEFINE_EXTEND	0x63
+#define CMD_READ		0x86
+#define CMD_WRITE		0x8d
+
+struct eckd_device device;
+
+/*
+ * Data for Locate Record CCW
+ */
+struct lodata {
+	uint8_t		op;
+	uint8_t		xx;
+	uint16_t	blk_count;
+	uint32_t	cchh1;
+	uint32_t	cchh2;
+	uint8_t		bot;
+	uint8_t		res2;
+	uint16_t	blk_size;
+	uint8_t		res3[0x18-0x10];
+} __packed;
+
+static struct lodata lodata = {
+	.op		= 0x01,
+	.xx		= 0x80,
+	.blk_count	= 0x0001,
+	.bot		= 0x03,
+};
+
+/*
+ * Data for Define Extend CCW
+ */
+struct dedata {
+	uint8_t		op;
+	uint8_t		xx;
+	uint8_t		res1[0x08-0x02];
+	uint32_t	cchh1;
+	uint32_t	cchh2;
+} __packed;
+
+static struct dedata dedata = {
+	.op		= 0x80,
+	.xx		= 0xc0,
+};
+
+/*
+ * ORB /IRB
+ */
+static struct orb orb = {
+	.intparm	= 0x0049504c,	/* Interruption Parameter */
+	.fmt		= 0x1,		/* Use format 1 CCWs */
+	.c64		= 0x1,		/* Use IDAs */
+	.lpm		= 0xff,		/* Logical path mask */
+};
+
+static struct irb irb;
+
+/*
+ * CCW program and IDA list
+ */
+struct ccw_program {
+	struct ccw1 deccw;
+	struct ccw1 loccw;
+	struct ccw1 wrccw[ECKD_BPWRT_MAX];
+	unsigned long ida_list[ECKD_BPWRT_MAX];
+} __packed __aligned(8);
+
+static struct ccw_program ccw_program;
+
+/*
+ * Setup IDA list for CCW program
+ */
+static void ccw_setup(uint8_t cmd, unsigned long addr, unsigned long blk_count,
+		      unsigned long zero_page)
+{
+	unsigned long i, *ida_list = ccw_program.ida_list;
+	struct ccw1 *ccw_list = ccw_program.wrccw;
+
+	for (i = 0; i < blk_count; i++) {
+		if (zero_page)
+			ida_list[i] = page_is_valid(addr) ? addr : zero_page;
+		else
+			ida_list[i] = addr;
+		ccw_list[i].cmd_code = cmd;
+		ccw_list[i].count = device.blk_size;
+		ccw_list[i].flags = CCW_FLAG_CC | CCW_FLAG_IDA;
+		ccw_list[i].cda = __pa32(&ida_list[i]);
+		addr += device.blk_size;
+	}
+	/* No command chaining for last CCW */
+	ccw_list[i - 1].flags &= ~CCW_FLAG_CC;
+}
+
+/*
+ * Read or write ECKD blocks
+ */
+static void io_block(uint8_t cmd, unsigned long blk, unsigned long addr,
+		     unsigned long blk_count, unsigned long zero_page)
+{
+	uint32_t trk, trk_end, cyl, cyl_end, bot, hd, hd_end, c0c1c2h0, down;
+	unsigned long blk_end;
+
+	if (blk >= device.blk_end)
+		panic(EMEM, "%s", "Device too small");
+
+	ccw_setup(cmd, addr, blk_count, zero_page);
+	lodata.blk_count = blk_count;
+	lodata.blk_size = device.blk_size;
+	blk_end = blk + blk_count - 1;
+
+	/* Compute start track and end block on track */
+	trk = blk / device.bpt;
+	bot = (blk % device.bpt) + 1;
+	/* Compute start cylinder and head */
+	cyl = trk / device.num_heads;
+	hd = trk % device.num_heads;
+
+	lodata.bot = (uint8_t) bot;
+
+	/* Upper 12 bits of cylinder are coded into heads: c0c1c2h0 (2 byte) */
+	c0c1c2h0 = cyl >> 16;
+	c0c1c2h0 <<= 4;
+
+	/* Combine to CCHH */
+	down = cyl << 16;
+
+	dedata.cchh1 = down | hd | c0c1c2h0;
+	lodata.cchh1 = down | hd | c0c1c2h0;
+	lodata.cchh2 = down | hd | c0c1c2h0;
+
+	/* Compute end track and end block on track */
+	trk_end = blk_end / device.bpt;
+	/* Compute end cylinder and head */
+	cyl_end = trk_end / device.num_heads;
+	hd_end = trk_end % device.num_heads;
+
+	/* Upper 12 bits of cylinder are coded into heads: c0c1c2h0 (2 byte) */
+	c0c1c2h0 = cyl_end >> 16;
+	c0c1c2h0 <<= 4;
+
+	/* Combine to CCHH */
+	down = cyl_end << 16;
+
+	dedata.cchh2 = down | hd_end | c0c1c2h0;
+	start_io(device.ssid, &irb, &orb);
+}
+
+/*
+ * Write data to given block address
+ */
+void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
+		unsigned long zero_page)
+{
+	lodata.op = 0x01; /* Indicate WRITE DATA operation */
+	dedata.op = 0x80; /* Permit update write operations */
+	io_block(CMD_WRITE, blk, addr, blk_count, zero_page);
+}
+
+/*
+ * Read data from given block address
+ */
+void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count)
+{
+	lodata.op = 0x06; /* Indicate READ DATA operation */
+	dedata.op = 0x40; /* Inhibit all write operations */
+	io_block(CMD_READ, blk, addr, blk_count, 0);
+}
+
+/*
+ * Init ECKD common
+ */
+void stage2dump_eckd_init(void)
+{
+	ccw_program.deccw.cmd_code = CMD_DEFINE_EXTEND;
+	ccw_program.deccw.flags = CCW_FLAG_CC;
+	ccw_program.deccw.count = 0x0010;
+	ccw_program.deccw.cda = __pa32(&dedata);
+
+	ccw_program.loccw.cmd_code = CMD_LOCATE_RECORD;
+	ccw_program.loccw.flags = CCW_FLAG_CC;
+	ccw_program.loccw.count = 0x0010;
+	ccw_program.loccw.cda = __pa32(&lodata);
+
+	orb.cpa = __pa32(&ccw_program);
+}
--- /dev/null
+++ b/zipl/boot/eckd2dump.h
@@ -0,0 +1,49 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common ECKD dump I/O functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+#ifndef ECKD2DUMP_H
+#define ECKD2DUMP_H
+
+#include "cio.h"
+
+#define ECKD_BPWRT_MAX 64
+
+struct eckd_device {
+	uint32_t blk_start;
+	uint32_t blk_end;
+	uint16_t blk_size;
+	uint8_t num_heads;
+	uint8_t bpt;
+	struct subchannel_id ssid;
+	uint16_t devno;
+};
+
+extern struct eckd_device device;
+
+/*
+ * Convert memory size to number of blocks
+ */
+static inline unsigned long m2b(unsigned long mem)
+{
+	return mem / device.blk_size;
+}
+
+/*
+ * Convert number of blocks to memory size
+ */
+static inline unsigned long b2m(unsigned long blk)
+{
+	return blk * device.blk_size;
+}
+
+void stage2dump_eckd_init();
+void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
+		unsigned long zero_page);
+void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count);
+
+#endif /* ECKD2DUMP_H */
--- /dev/null
+++ b/zipl/boot/eckd2dump_mv.c
@@ -0,0 +1,206 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Multi-volume ECKD DASD dump tool
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include "stage2dump.h"
+#include "eckd2dump.h"
+#include "error.h"
+
+#define MVDUMP_SIZE		0x3000	/* Size of dump record */
+#define MAX_DUMP_VOLUMES	32	/* Up to 32 dump volumes possible */
+
+/*
+ * Magic number at start of dump record
+ */
+uint64_t magic __attribute__((section(".stage2.head")))
+	= 0x5a4d554c54363403ULL; /* ZMULT64, version 3 */
+
+/*
+ * Parameter format for ECKD MV dumper (13 bytes):
+ *
+ * DDSS SSEE EEBN O
+ *
+ * - DD  : Devno of dump target
+ * - SSSS: Start block number of dump target
+ * - EEEE: End block number of dump target
+ * - B   : Blocksize of dump target (needs to be left-shifted by 8 bits)
+ * - N   : End Record Number
+ * - O   : Number of Heads of DASD
+ *
+ * We assume that the End Record Number is at track boundary.
+ * This allows us to determine the number of Blocks Per Track.
+ */
+struct mvdump_param {
+	uint16_t	devno;
+	uint32_t	blk_start;
+	uint32_t	blk_end;
+	uint8_t		blk_size;
+	uint8_t		bpt;
+	uint8_t		num_heads;
+} __packed;
+
+/*
+ * Provide storage for parameter table: 10 + 32*PTE_LENGTH = 426 bytes
+ * We take 512 bytes to match with struct mvdump_parm_table in include/boot.h
+ */
+struct mvdump_parm_table {
+	uint64_t	tod;
+	uint16_t	num_param;
+	struct mvdump_param param[MAX_DUMP_VOLUMES];
+	unsigned char	reserved[512 - sizeof(uint64_t) - sizeof(uint16_t) -
+			(MAX_DUMP_VOLUMES * sizeof(struct mvdump_param))];
+} __packed;
+
+static struct mvdump_parm_table mvdump_table
+	__attribute__((section(".eckd2dump_mv.tail")));
+
+static int volnr_current;
+
+/*
+ * Get device characteristics for current DASD device from zipl parameter block
+ */
+void dt_device_parm_setup(void)
+{
+	struct mvdump_param *param = &mvdump_table.param[volnr_current];
+
+	device.devno = param->devno;
+	device.blk_start = param->blk_start;
+	device.blk_end = param->blk_end;
+	device.blk_size = ((unsigned int) param->blk_size) << 8;
+	device.bpt = param->bpt;
+	device.num_heads = param->num_heads;
+	stage2dump_eckd_init();
+}
+
+/*
+ * Get subchannel ID for MV dump
+ */
+static int set_ssid_from_devno(uint16_t devno)
+{
+	struct subchannel_id ssid;
+	struct schib schib;
+
+	memset(&ssid, 0, sizeof(ssid));
+
+	ssid.one = 1;
+	ssid.sch_no = 0;
+	do {
+		if (store_subchannel(ssid, &schib) == 0) {
+			if (schib.pmcw.dev == devno) {
+				device.ssid = ssid;
+				break;
+			}
+		}
+		if (ssid.sch_no == 0xffff)
+			return -1;
+		ssid.sch_no++;
+	} while (1);
+	return 0;
+}
+
+/*
+ * Enable current DASD device
+ */
+void dt_device_enable(void)
+{
+	struct mvdump_param *param = &mvdump_table.param[volnr_current];
+
+	if (set_ssid_from_devno(param->devno) != 0)
+		panic(ENODEVNO, "%04x is undefined", param->devno);
+	io_irq_enable();
+	set_device(device.ssid, ENABLED);
+}
+
+/*
+ * Dump all memory to multiple DASD partitions
+ */
+void dt_dump_mem(void)
+{
+	unsigned long blk, addr, addr_end, blk_num, dev_mem_size, page;
+	struct mvdump_parm_table *mvdump_table_new;
+	struct df_s390_hdr *hdr_new;
+
+	dump_hdr->mvdump_sign = DF_S390_MAGIC;
+	dump_hdr->mvdump = 1;
+	addr = 0;
+
+	page = get_zeroed_page();
+	do {
+		printf("Dumping to: %04x", device.devno);
+
+		/*
+		 * Check whether parameter table on dump device has a valid
+		 * time stamp. The parameter table is located right behind
+		 * the dump tool, the corresponding block number is:
+		 *   MAGIC_BLOCK_OFFSET + (MVDUMP_TOOL_SIZE / blocksize)
+		 *   So dump tool starts on track 0, block 3
+		 */
+		mvdump_table_new = (void *) page;
+		readblock(3 + MVDUMP_SIZE / 0x1000,
+			  __pa(mvdump_table_new), m2b(0x1000));
+		/*
+		 * Check if time stamps match
+		 */
+		if (mvdump_table.tod != mvdump_table_new->tod)
+			panic(ENOTIME, "Inconsistent time stamps");
+
+		/*
+		 * Check if dump partition has a valid dump signature.
+		 * Bypass signature check if "--force" had been specified during
+		 * zipl -M.
+		 */
+		hdr_new = (void *) page;
+		if (!parm_tail.mvdump_force) {
+			readblock(device.blk_start, __pa(hdr_new), 1);
+			if (dump_hdr->magic != hdr_new->mvdump_sign)
+				panic(ENOSIGN, "Wrong signature");
+		}
+
+		/*
+		 * Write dump header
+		 */
+		blk = device.blk_start;
+		writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
+		blk += m2b(DF_S390_HDR_SIZE);
+
+		dev_mem_size = b2m(device.blk_end - blk + 1);
+		addr_end = MIN(dump_hdr->mem_size, addr + dev_mem_size);
+
+		/*
+		 * Write memory
+		 */
+		memset((void *) page, 0, PAGE_SIZE);
+		while (addr < addr_end) {
+			blk_num = MIN(ECKD_BPWRT_MAX, device.blk_end - blk + 1);
+			blk_num = MIN(m2b(addr_end - addr), blk_num);
+			writeblock(blk, addr, blk_num, page);
+			progress_print(addr);
+			blk += blk_num;
+			addr += b2m(blk_num);
+		}
+		if (addr == dump_hdr->mem_size)
+			break;
+		/*
+		 * Switch to next volume if available
+		 */
+		dump_hdr->volnr += 1;
+		volnr_current++;
+		if (dump_hdr->volnr >= mvdump_table.num_param)
+			panic(EMEM, "Device too small");
+		dt_device_parm_setup();
+		set_device(device.ssid, DISABLED);
+		dt_device_enable();
+	} while (1);
+	progress_print(addr);
+	/*
+	 * Write end marker
+	 */
+	df_s390_em_page_init(page);
+	writeblock(blk, page, 1, 0);
+	free_page(page);
+}
--- /dev/null
+++ b/zipl/boot/eckd2dump_sv.c
@@ -0,0 +1,83 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Single-volume ECKD DASD dump tool
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include "stage2dump.h"
+#include "eckd2dump.h"
+#include "error.h"
+
+/*
+ * Magic number at start of dump record
+ */
+uint64_t magic __attribute__((section(".stage2.head"))) =
+	0x5a45434b44363403ULL; /* "ZECKD64", version 3 */
+
+/*
+ * ECKD parameter block passed by zipl
+ */
+struct eckd_dump_param {
+	uint32_t blk_start;
+	uint32_t blk_end;
+	uint16_t blk_size;
+	uint8_t num_heads;
+	uint8_t bpt;
+	char reserved[4];
+} __packed;
+
+/*
+ * Get device characteristics from zipl parameter block
+ */
+void dt_device_parm_setup(void)
+{
+	struct eckd_dump_param *parm = (void *) __stage2_desc;
+
+	device.blk_start = parm->blk_start;
+	device.blk_end = parm->blk_end;
+	device.blk_size = parm->blk_size;
+	device.num_heads = parm->num_heads;
+	device.bpt = parm->bpt;
+	device.ssid = IPL_SC;
+	stage2dump_eckd_init();
+}
+
+/*
+ * Enable DASD device
+ */
+void dt_device_enable(void)
+{
+	io_irq_enable();
+	set_device(device.ssid, ENABLED);
+}
+
+/*
+ * Dump all memory to DASD partition
+ */
+void dt_dump_mem(void)
+{
+	unsigned long blk, addr, page;
+
+	blk = device.blk_start;
+	page = get_zeroed_page();
+
+	/* Write dump header */
+	writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
+	blk += m2b(DF_S390_HDR_SIZE);
+
+	/* Write memory */
+	for (addr = 0; addr < dump_hdr->mem_size; addr += b2m(ECKD_BPWRT_MAX)) {
+		writeblock(blk, addr, ECKD_BPWRT_MAX, page);
+		progress_print(addr);
+		blk += ECKD_BPWRT_MAX;
+	}
+	progress_print(addr);
+
+	/* Write end marker */
+	df_s390_em_page_init(page);
+	writeblock(blk, page, 1, 0);
+	free_page(page);
+}
--- a/zipl/boot/eckd2mvdump.S
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- *  Multi-volume dump tool for ECKD DASDs
- *    Copyright IBM Corp. 2008
- *    Author(s): Michael Holzheu  <holzheu@de.ibm.com>
- *               Frank Munzert <munzert@de.ibm.com>
- *               Holger Smolinski <Holger.Smolinski@de.ibm.com>
- */
-
-#include "dumpcommon.S"
-#if defined(__s390x__)
-#define USE_64BIT_SCLP
-#include "sclp.S"
-
-/* General defines */
-
-#define MVDUMP_TOOL_SIZE 0x2000  /* length of dump tool without parmtable */
-#define BLOCKS_PER_WRITE 64      /* makes 256K with 4Ki blksize           */
-#define PTE_LENGTH 13            /* length of parameter table entry       */
-#define MAGIC_BLOCK_OFFSET 3     /* dump tool starts on track 0, block 3  */
-
-################################################################################
-# Function entry point at 0x2000 (not used for dump) is called with C linkage
-#   %r2-%r3: load descriptor
-#   %r3    : device subchannel id
-#   %r4    : load address
-################################################################################
-
-dump_magic:  .long 0x5a4d554c, 0x54363402     # "ZMULT64", version 1
-
-/******************************** 64 BIT only**********************************/
-
-################################################################################
-# Program execution of the second stage boot loader starts at 0x2008
-################################################################################
-
-	.globl _start
-_start:
-	basr  %r13,0
-.Linit_base:
-	la    %r9,0
-	st    %r9,.Ldh_arch-.Linit_base(%r13) # init arch
-	l     %r15,1f-.Linit_base(%r13)       # load end of stack address
-	la    %r7,0
-	tm    __LC_ARCH_MODE_ID(%r9),0x01     # check arch mode
-	bnz   .Larch_64-.Linit_base(%r13)
-
-        /* 32 bit store status */
-
-	l     %r14,.Lstore_status_32-.Linit_base(%r13)
-	basr  %r14,%r14
-	la    %r10,ARCH_S390_ID
-	st    %r10,.Ldh_arch-.Linit_base(%r13)
-
-.Larch_64:
-	la    %r7,2                           # first try code 2:
-	la    %r6,0                           # 64 bit psws are restored
-	sigp  %r7,%r6,0x12                    # switch to 64 bit
-	bc    8,.Lswitched_64-.Linit_base(%r13) # order accepted ?
-	la    %r7,1                           # code 2 failed - try code 1
-	sigp  %r7,%r6,0x12                    # switch to 64 bit
-.Lswitched_64:
-	sam64                                 # switch to 64 bit addr mode
-	basr   %r13,0
-0:      llgf   %r15,5f-0b(%r13)               # load end of stack address
-
-	llgf   %r10,.Ldh_arch-0b(%r13)
-	cghi   %r10,ARCH_S390_ID
-	be     .Larch_32-0b(%r13)
-
-        /* 64 bit store status */
-
-	llgf   %r14,.Lstore_status_64-0b(%r13)
-	basr   %r14,%r14
-	lghi   %r10,ARCH_S390X_ID
-	st     %r10,.Ldh_arch-0b(%r13)
-
-.Larch_32:
-	lghi   %r2,0                          # provide input register
-	bras   %r14,_sclp_setup               # initialize sclp to write msg
-	lhi    %r2,PARAM_START                # point to parameter table
-	ahi    %r2,10                         # point to first table entry
-	st     %r2,.Lparam_ptr-0b(%r13)       # initialize table entry pointer
-	bas    %r14,_get_device_characteristics_64-0b(%r13)
-	lhi    %r2,CCW_CHAIN_START            # point to 1st CCW in chain
-	mvc    0(16,%r2),.Ldeccw-0b(%r13)     # move the first two CCWs
-	mvi    16(%r2),0x86                   # move opcode into 1st write CCW
-	llgf   %r14,.Ltake_dump_64-0b(%r13)
-	basr   %r14,%r14
-5:      .long  0x10000-128                    # end of stack
-
-################################################################################
-# Dump memory
-#  -no parameters
-################################################################################
-
-_dump_mem_64:
-	stmg   %r6,%r15,48(%r15)
-	basr   %r13,0                         # base register
-0:      aghi   %r15,-200                      # create stack frame
-
-	# init progress bar
-	bras %r14,_init_print_progress_64
-
-	# prepare dump header info
-	mvi     .Ldh_mvdump-0b(%r13),0x01     # store mvdump indicator
-
-.Lnextvol:
-	mvi    .Ldev_full_flag-0b(%r13),0     # reset "device full" indicator
-	# issue "Dumping to <devno>" status message
-	la     %r2,.Lmsg_dump2devno-0b(%r13)
-	bras   %r14,_sclp_print
-
-	# calculate bytes per write (blksize * blwr)
-	llgf    %r11,.Ldev_blk_size-0b(%r13)
-	mh      %r11,.Lblocks_per_write-0b(%r13)
-	st      %r11,.Lbytes_per_write-0b(%r13)
-
-	# calculate number of blocks required to store header
-	llgf    %r4,.Lheader_size-0b(%r13)
-	srda    %r4,32                        # shift ==> 64 bit number
-	llgf    %r6,.Ldev_blk_size-0b(%r13)   # get blocksize
-	dr      %r4,%r6                       # nr of blocks for header =
-                                              # HEADER_SIZE / BLOCKSIZE = r5
-
-# Check whether parameter table on dump device has a valid time stamp.
-# The parameter table is located right behind the dump tool, the corresponding
-# block number is:  MAGIC_BLOCK_OFFSET + (MVDUMP_TOOL_SIZE / blocksize)
-
-	mvi     .Llodata-0b(%r13),0x06        # indicate READ DATA operation
-	mvi     .Ldedata-0b(%r13),0x40        # inhibit all write operations
-	lghi    %r2,CCW_CHAIN_START           # point to 1st CCW in chain
-	mvi     16(%r2),0x86                  # move read opcode into CCW
-	lhi     %r2,MAGIC_BLOCK_OFFSET        # start block of dump tool
-	lgr     %r10,%r5                      # mvdumptool size = 0x2000
-	sll     %r10,1                        # (header size * 2)
-	ar      %r2,%r10                      # start block of parameter table
-	lghi    %r3,TMP_PAGE_START            # destination of read operation
-	lghi    %r4,1                         # number of blocks to read
-	bas     %r14,_ioblock_64-0b(%r13)     # read parameter table
-	lghi    %r3,TMP_PAGE_START            # destination of read operation
-	lghi    %r2,PARAM_START               # point to time stamp
-	clc     0(8,%r3),0(%r2)               # found identical time stamp?
-	be      .Lcheck_sign-0b(%r13)         # yes, check signature
-	# issue "Inconsistent time stamps" message and exit
-	la      %r2,.Lmsg_time_stamp-0b(%r13) # point to message
-	bras    %r14,_sclp_print              # print message
-	lghi    %r2,ENOTIME                   # inconsistent time stamps
-	b      _panik_64-0b(%r13)             # --> exit
-
-# Check whether dump partition has a valid dump signature.
-# Bypass signature check if --force had been specified during zipl -M
-# The dump signature is located at offset 512 relative to the partition start
-
-.Lcheck_sign:
-	larl    %r7,.Lforce
-	tm      1(%r7),0x01                   # was zipl --force specified?
-	bo      .Lheaders-0b(%r13)            # yes, skip signature check
-	llgf    %r2,.Ldev_start_blk-0b(%r13)  # start block of partition
-	lghi    %r3,TMP_PAGE_START            # destination of read operation
-	lgr     %r4,%r5                       # number of blocks for header
-	bas     %r14,_ioblock_64-0b(%r13)     # read start block
-	lghi    %r3,TMP_PAGE_START            # destination of read operation
-	clc     512(8,%r3),.Ldh_magic_number-0b(%r13) # did we find signature?
-	be      .Lheaders-0b(%r13)            # yes, write data to partition
-	# issue "Wrong signature" message and exit
-	la      %r2,.Lmsg_signature-0b(%r13)  # point to message
-	bras    %r14,_sclp_print              # print message
-	lghi    %r2,ENOSIGN                   # invalid signature
-	b      _panik_64-0b(%r13)             # --> exit
-
-# write header
-
-.Lheaders:                                    # write dump headers
-	mvi     .Llodata-0b(%r13),0x01        # indicate WRITE DATA operation
-	mvi     .Ldedata-0b(%r13),0x80        # permit update write operations
-	lghi    %r2,CCW_CHAIN_START           # point to 1st CCW in chain
-	mvi     16(%r2),0x8d                  # move write opcode into CCW
-
-	llgf    %r11,.Ldev_start_blk-0b(%r13) # start block
-
-	lgr     %r2,%r11
-	lghi    %r3,HEADER_PAGE_START
-	mvc     512(8,%r3),.Ldh_magic_number-0b(%r13) # preserve signature
-	lgr     %r4,%r5
-	lgr     %r12,%r5                      # save nr of blocks
-	bas     %r14,_ioblock_64-0b(%r13)     # write block to disk
-	ar      %r11,%r12                     # update block counter
-
-# write memory
-
-.Lmemory:                                     # write memory
-	lg      %r10,.Lmem_current-0b(%r13)   # current memory address
-.Lmloop:
-	cli     .Ldev_full_flag-0b(%r13),1    # no more space left on device?
-	bne     .Lmloop3-0b(%r13)             # no, just write to this one
-	stg     %r10,.Lmem_current-0b(%r13)   # yes, remember memory address
-	l       %r12,.Ldh_vol_nr-0b(%r13)     # get current volume number
-	ahi     %r12,1                        # increment volume number
-	st      %r12,.Ldh_vol_nr-0b(%r13)     # store next volume number
-	lghi    %r3,HEADER_PAGE_START
-	mvc     0(256,%r3),.Ldh_dumpheader-0b(%r13)
-	lhi     %r11,PARAM_START              #
-	ch      %r12,8(%r11)                  # last dump target?
-	bl      .Lmloop2-0b(%r13)             # no, initialize next target
-	lghi    %r2,EMEM                      # yes, all targets full
-	llgf    %r14,.Lpanik_64-0b(%r13)      #
-	basr    %r14,%r14
-.Lmloop2:
-	llgf    %r2,.Lparam_ptr-0b(%r13)      # yes, load parameter pointer
-	la      %r2,PTE_LENGTH(%r2)           # increment parm table pointer
-	st      %r2,.Lparam_ptr-0b(%r13)      # ... and store it back
-	bas     %r14,_get_device_characteristics_64-0b(%r13)
-	b       .Lnextvol-0b(%r13)            # write to next device
-.Lmloop3:
-	lghi    %r4,BLOCKS_PER_WRITE          # write so many blocks at a time
-	llgf    %r9,.Lbytes_per_write-0b(%r13)
-	lgr     %r2,%r11                      # load current block pointer
-	agr     %r2,%r4                       # increment block pointer
-	llgf    %r12,.Ldev_end_blk-0b(%r13)   # last block on dump target
-	clgr    %r2,%r12                      # block pointer < dev_end_blk ?
-	bl      .Lmloop4-0b(%r13)             # yes, write BLOCKS_PER_WRITE
-	mvi     .Ldev_full_flag-0b(%r13),1    # no, set "device is full"
-	lgr     %r4,%r12                      #
-	sgr     %r4,%r11                      #
-	aghi    %r4,1                         # number of remaining blocks
-	llgf    %r9,.Ldev_blk_size-0b(%r13)   #
-	mr      %r8,%r4                       #
-	lgr     %r3,%r9                       # number of remaining bytes
-	srl     %r9,12                        #
-	sll     %r9,12                        # enforce multiple of 4k
-	ltr     %r9,%r9                       # remaining bytes were less 4k?
-	bz      .Lmloop-0b(%r13)              # yes, don't write to this volume
-	sr      %r3,%r9                       # r3: remainder modulo 4k
-	lghi    %r2,0
-	d       %r2,.Ldev_blk_size-0b(%r13)
-	sr      %r4,%r3
-.Lmloop4:
-# At this point: r4: number of blocks we want to write
-#                r9: number of bytes we want to write
-	lg      %r2,.Ldh_mem_size-0b(%r13)    # memory size
-	sgr     %r2,%r10                      # bytes left to write
-	clgr    %r2,%r9                       # is it last chunk?
-	bh      .Lmloop5-0b(%r13)             # no, write whole chunk
-	lr      %r5,%r2                       # yes, prepare to write last chunk
-	lghi    %r4,0                         # re-init #blocks
-	d       %r4,.Ldev_blk_size-0b(%r13)   # quotient is bit 32-63 of r5
-	lr      %r4,%r5                       # #blocks left to write
-.Lmloop5:
-	lgr     %r2,%r11                      # restore r2
-	lgr     %r3,%r10                      # restore r3
-	bas     %r14,_ioblock_64-0b(%r13)     # write block to disk
-	agr     %r10,%r9                      # update data address
-	agr     %r11,%r4                      # skip to next block
-
-	lgr     %r2,%r10                      # print progress to console
-	bras    %r14,_print_progress_64
-
-	clg     %r10,.Ldh_mem_size-0b(%r13)   # whole memory size written?
-	bl      .Lmloop-0b(%r13)              # no, continue
-
-# write end marker
-
-.lendmarker:                                  # terminate dump file
-	stck    .Ld_end_time-0b(%r13)         # store end time
-	lgr     %r2,%r11                      # restore r2
-	lghi    %r3,TMP_PAGE_START
-	mvc     0(256,%r3),.Ld_endmarker-0b(%r13)
-					      # copy dump end marker to page
-					      # boundary
-	lghi    %r4,1                         # write endmarker with one block
-	bas     %r14,_ioblock_64-0b(%r13)     # write block to disk
-
-	lmg     %r6,%r15,248(%r15)
-	br      %r14                          # return to caller
-.Lbytes_per_write:  .long 0x00000000
-.Lheader_size:      .long HEADER_SIZE
-.Lblocks_per_write: .word BLOCKS_PER_WRITE
-
-################################################################################
-# Get the device characteristics:
-#  - r2: pointer to parameter table entry as written by zipl -M
-#
-# Pick up device characteristics from zipl parameter table (at PARAM_START).
-# The following parameter format is expected (13 bytes):
-#
-# DDSS SSEE EEBN O
-#
-# - DD  : Devno of dump target
-# - SSSS: Start block number of dump target
-# - EEEE: End block number of dump target
-# - B   : Blocksize of dump target (needs to be left-shifted by 8 bits)
-# - N   : End Record Number
-# - O   : Number of Heads of DASD
-#
-# We assume that the End Record Number is at track boundary.
-# This allows us to determine the number of Blocks Per Track.
-################################################################################
-
-_get_device_characteristics_64:
-	stmg   %r6,%r15,48(%r15)
-	basr   %r13,0                       # base register
-0:      aghi   %r15,-200                    # create stack frame
-
-	mvc    .Ldev_devno-0b(10,%r13),0(%r2) # copy devno, start_blk, end_blk
-	mvc    .Ldev_blk_size-0b+2(1,%r13),10(%r2)
-	mvc    .Ldev_end_rec-0b+3(1,%r13),11(%r2)
-	mvc    .Ldev_nr_hds-0b+3(1,%r13),12(%r2)
-
-	# Convert hexadecimal devno for "Dumping to <devno>" message
-	unpk   .Lmsg_devno-0b(5,%r13),0(3,%r2) # unpack devno into message text
-	la     %r1,.Ltrtab-0b(%r13)         # provide translation rule for...
-	ahi    %r1,-0xf0                    # ...hexadecimal characters
-	tr     .Lmsg_devno-0b(4,%r13),0(%r1)# translate devno in message text
-	mvi    .Lmsg_devno_end-0b(%r13),0x00# insert null into message
-
-	# Obtain subchannel number corresponding to devno
-	iilh   %r1,1                        # initialize subsys-ident word
-	iill   %r1,0                        # initialize subchannel number
-	lr     %r6,%r1                      # duplicate register
-	iill   %r6,0xffff                   # highest subchannel number
-.Lschloop:
-	stsch  .Ltmp_data-0b(%r13)          # try to obtain info for subchannel
-	bnz    .Lschnop-0b(%r13)            # sch not operational, try next
-	clc    .Ltmp_data-0b+6(2,%r13),0(%r2) # got right devno?
-	be     .Lschdone-0b(%r13)           # yes, we're done
-.Lschnop:
-	la     %r1,1(%r1)                   # increment subchannel number
-	cr     %r1,%r6                      # upper limit reached?
-	bnh    .Lschloop-0b(%r13)           # no, continue loop
-	# issue "<devno> is undefined" message and exit
-	mvi    .Lmsg_devno_end-0b(%r13),0x40# insert blank into message
-	la     %r2,.Lmsg_devno-0b(%r13)     # point to message
-	bras   %r14,_sclp_print             # print message
-	lghi   %r2,ENODEV                   # set error code
-	b      _panik_64-0b(%r13)           # exit
-.Lschdone:
-	st     %r1,.Ldev_ssid-0b(%r13)      # store subsys-identification word
-	lr     %r2,%r1                      # provide input register
-	llgf   %r14,.Lenable_device_64-0b(%r13)
-	basr   %r14,%r14
-	lhi    %r2,CCW_CHAIN_START          # point to 1st CCW in chain
-	l      %r5,.Ldev_blk_size-0b(%r13)  # get blocksize
-	stcm   %r5,3,18(%r2)                # store blocksize into 1st write CCW
-	stcm   %r5,3,.Llodata+14-0b(%r13)   # store blocksize into lodata
-	lmg    %r6,%r15,248(%r15)
-	br     %r14
-
-################################################################################
-# This function reads or writes a block number given in r2 to disk
-#  -r2:  number of first block to write ( input by caller )
-#        We start counting with Block Nr 0 !!!
-#  -r3:  address to write data from ( input by caller )
-#  -r4:  number of blocks to write ( input by caller )
-################################################################################
-
-_ioblock_64:
-	stmg    %r4,%r15,48(%r15)
-	basr    %r13,0                        # base register
-0:      aghi    %r15,-200                     # create stack frame
-
-	lghi    %r12,CCW_CHAIN_START
-	st      %r12,8+.Lorb-0b(%r13)         # store cpaddr to orb
-	la      %r12,16(%r12)                 # skip DE and LOC CCW
-	oi      1(%r12),0x44                  # set chain-command+ida flag
-	lghi    %r10,IDA_LIST_START           # pointer to ida list
-
-	# setup new pgc psw for finding invalid pages
-	mvc     .Lold_pgc_psw-0b(16,%r13),464(%r0)      # save old psw
-	mvc     464(16,%r0),.Lpage_invalid_psw-0b(%r13) # setup pgm check new
-
-        # first setup the write channel program
-	lgr     %r11,%r4                      # save number of blocks
-	llgf    %r6,.Ldev_end_rec-0b(%r13)    # load blocks per track to r6
-	llgf    %r7,.Ldev_nr_hds-0b(%r13)     # load heads to r7
-	la      %r5,.Lwrloop-0b(%r13)
-	br      %r5
-
-2:      # loop for number of block (nbl) time
-
-	# switch to next write CCW
-	llgf    %r5,.Ldev_blk_size-0b(%r13)
-	agr     %r3,%r5                       # add blksize to destination addr
-	mvc     8(8,%r12),0(%r12)             # copy ccw to next ccw
-	ahi     %r12,8                        # add sizeof(ccw) to base address
-	ahi     %r10,8                        # next element in ida list
-
-.Lwrloop:
-	# build up next write CCW
-	l       %r9,0(%r3)                    # test page
-	lgr     %r9,%r3
-	b       .Lpage_ok-0b(%r13)
-.Lpage_invalid:
-	lghi    %r9,ZERO_PAGE_START
-.Lpage_ok:
-	stg     %r9,0(%r10)                   # store target addr to idalist
-	st      %r10,4(%r12)                  # store ida addr to this ccw
-	bct     %r4,2b-0b(%r13)               # decrement no of blks still to do
-	ni      1(%r12),0x3f                  # no command chaining for last ccw
-
-	# write CCWs are setup now
-	lgr     %r4,%r11                      # restore number of blocks
-	stcm    %r4,3,.Llodata+2-0b(%r13)     # store number of blocks to lodata
-
-	# compute end block
-	agr     %r4,%r2                       # r4: ebl = blk + nbl
-	bctr    %r4,0                         # decrement r4 (last blk touched)
-
-	# compute start track and start block on track
-	srda    %r2,32                        # shift ==> 64 bit number
-	dr      %r2,%r6                       # trk = blk / bpt, bot = blk % bpt
-	                                      # r3: trk, r2: bot
-	la      %r2,1(%r2)                    # bot++ ( we start counting at 1 )
-	stcm    %r2,1,.Llodata+12-0b(%r13)    # store bot to lodata
-
-	# compute start cylinder and head
-	xr      %r2,%r2                       # clear bot
-	dr      %r2,%r7                       # cy=trk / heads, hd=trk % heads
-	                                      # r3: cy, r2: hd
-
-	lgr     %r8,%r3                       # r8=upper 12 bits of cylinder
-	srl     %r8,16                        # are coded into heads:
-	sll     %r8,4                         # c0c1c2h0 (2 byte)
-
-	sll     %r3,16                        # combine to CCHH in r3
-	or      %r3,%r2
-	or      %r3,%r8                       # add upper 12 bits
-	st      %r3,.Ldedata+8-0b(%r13)       # store cchh to dedata
-	st      %r3,.Llodata+4-0b(%r13)       # store cchh to lodata
-	st      %r3,.Llodata+8-0b(%r13)       # store cchh to lodata
-
-	# compute end track and end block on track
-	lgr     %r11,%r5                      # save r5
-	srda    %r4,32                        # shift ==> 64 bit number
-	dr      %r4,%r6                       # tr2 = ebl / bpt
-	                                      # r5: tr2, r4: bot2
-	# compute end cylinder and head
-	xr      %r4,%r4                       # cy2=tr2/heads, hd2=hd2 % heads
-	dr      %r4,%r7                       # r5: cy2, r4: hd2
-
-	lgr     %r8,%r5                       # r8=upper 12 bits of cylinder
-	srl     %r8,16                        # are coded into heads:
-	sll     %r8,4                         # c0c1c2h0 (2 byte)
-	or      %r4,%r8
-
-	stcm    %r5,3,.Ldedata+12-0b(%r13)    # store cy2 to dedata
-	stcm    %r4,3,.Ldedata+14-0b(%r13)    # store hd2 to dedata
-	lgr     %r5,%r11                      # restore r5
-
-	# CCWs are setup now, arent they?
-	llgf    %r2,.Ldev_ssid-0b(%r13)       # subchannel id
-	la      %r3,.Lorb-0b(%r13)
-	la      %r4,.Ltmp_data-0b(%r13)       # irb
-	la      %r5,10                        # initialize retries
-
-	bas     %r14,_ssch_64-0b(%r13)        # start I/O
-
-	mvc     464(16,%r0),.Lold_pgc_psw-0b(%r13) # restore pgm check new
-	lmg     %r4,%r15,248(%r15)
-	br      %r14                          # return to caller
-.align 8
-.Lorb:
-	.long 0x0049504c,0x0082ff00
-	.long 0x00000000,0x00000000
-.Ldedata:
-	.long 0x00c00000,0x00000000           # define extent parameters
-	.long 0x00000000,0x00000000
-.Llodata:
-	.long 0x00800001,0x00000000           # locate record parameters
-	.long 0x00000000,0x03000000
-	.long 0x12345678,0x00000000
-.align 8
-.Lpage_invalid_psw:
-	.long 0x00000001,0x80000000,0x00000000,0x00000000 + .Lpage_invalid
-.Lold_pgc_psw:
-	.long 0x0,0x0,0x0,0x0
-
-################################################################################
-# expand Macros
-################################################################################
-
-	hex_to_ebcdic
-	print_progress_64
-	dump_common_store_status_32
-	dump_common_fn_64
-	dump_io_subroutines_64
-	dump_header
-	dump_messages
-	tmp_data
-	sclp_base
-	sclp_print
-	sclp_read_info
-
-# extern functions
-
-.Lpanik_64:
-	.long      _panik_64
-.Lenable_device_64:
-	.long      _enable_device_64
-.Ltake_dump_64:
-	.long      _take_dump_64
-.Lstore_status_32:
-	.long      _store_status_32
-.Lstore_status_64:
-	.long      _store_status_64
-
-################################################################################
-# DATA
-################################################################################
-
-.Lc96:  .long  96 # for creating stackframes
-
-# device characteristics
-.align 8
-# Do *not* permutate the sequence of the following three definitions
-.Ldev_devno:
-	.short 0x0000
-.Ldev_start_blk:
-	.long  0x00000000
-.Ldev_end_blk:
-	.long  0x00000000
-.Ldev_blk_size:
-	.long  0x00000000
-.Ldev_nr_hds:
-	.long  0x00000000
-.Ldev_end_rec:
-	.long  0x00000000
-.Ldev_full_flag:
-	.short 0x0000
-.Ldev_ssid:
-	.long  0x00000000
-
-.Lparam_ptr:
-	.long  0x00000000
-.Lmem_current:
-	.long  0x00000000,0x00000000
-
-#
-# CCWs
-#
-.align 8
-
-# channel program for one write
-.Ldeccw:
-	.long 0x63400010,0x00000000+.Ldedata     # define extent
-.Lloccw:
-	.long 0x47400010,0x00000000+.Llodata     # locate record
-
-# Translation table
-.Ltrtab:
-	.long 0xf0f1f2f3,0xf4f5f6f7,0xf8f98182,0x83848586
-
-#
-# Messages
-#
-
-# "Dumping to: 0000" and "0000 is undefined"
-.Lmsg_dump2devno:
-	.byte 0xc4, 0xa4, 0x94, 0x97, 0x89, 0x95, 0x87, 0x40
-	.byte 0xa3, 0x96, 0x7a, 0x40
-.Lmsg_devno:
-	.byte 0x00, 0x00, 0x00, 0x00
-.Lmsg_devno_end:
-	.byte 0x00
-	.byte 0x89, 0xa2, 0x40, 0xa4, 0x95, 0x84, 0x85, 0x86
-	.byte 0x89, 0x95, 0x85, 0x84
-	.byte 0x00
-# "Wrong signature"
-.Lmsg_signature:
-	.byte 0xe6, 0x99, 0x96, 0x95, 0x87, 0x40, 0xa2, 0x89
-	.byte 0x87, 0x95, 0x81, 0xa3, 0xa4, 0x99, 0x85
-	.byte 0x00
-# "Inconsistent time stamps"
-.Lmsg_time_stamp:
-	.byte 0xc9, 0x95, 0x83, 0x96, 0x95, 0xa2, 0x89, 0xa2
-	.byte 0xa3, 0x85, 0x95, 0xa3, 0x40, 0xa3, 0x89, 0x94
-	.byte 0x85, 0x40, 0xa2, 0xa3, 0x81, 0x94, 0x97, 0xa2
-	.byte 0x00
-
-.org (MVDUMP_TOOL_SIZE - 10)
-.Lforce:
-	.byte 0x00
-	.byte 0x00                            # is set to 0x01 by zipl -f
-.Lmem_upper_limit:
-	.long 0xffffffff,0xffffffff           # can be used for memsize=xxx
-# Provide storage for parameter table: 10 + 32*PTE_LENGTH = 426 bytes
-# We take 512 bytes to match with struct mvdump_parm_table in include/boot.h
-	.fill  512,1,0
-
-#else /* __s390x__ */
-	.globl _start
-_start:
-	basr  %r13,0                          # dummy data for 31-bit
-
-#endif
--- /dev/null
+++ b/zipl/boot/entry.S
@@ -0,0 +1,18 @@
+/*
+ *  Entry module for stage 2 stand-alone dump tools
+ *
+ *  Copyright IBM Corp. 2001, 2013
+ *  Author(s): Michael Holzheu  <holzheu@linux.vnet.ibm.com>
+ */
+
+#define __LC_SAVE_AREA_SYNC	0x200	/* Save area for interrupts */
+#define __LC_PGM_OLD_PSW	0x0150	/* Program check old PSW */
+
+.globl pgm_check_handler
+pgm_check_handler:
+	stmg	%r0,%r15,__LC_SAVE_AREA_SYNC
+	aghi	%r15,-200
+	larl	%r14,pgm_check_handler_fn
+	basr	%r14,%r14
+	lmg	%r0,%r15,__LC_SAVE_AREA_SYNC
+	lpswe	__LC_PGM_OLD_PSW(%r0)
--- /dev/null
+++ b/zipl/boot/error.h
@@ -0,0 +1,68 @@
+/*
+ * zipl boot loader error codes
+ *
+ * Copyright IBM Corp. 2012
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+/************************************************************************
+ * zipl boot loader error codes (use decimal range 4500-4549)
+ *
+ * The error numbers are ABI. Do not change them!
+ ************************************************************************/
+
+/* I/O error: Enabling the IPL device failed */
+#define EENABLE_DEV		0x00004500
+
+/* I/O error: Disabling the IPL device failed */
+#define EDISABLE_DEV		0x00004501
+
+/* I/O error: The start subchannel command failed */
+#define ESSCH			0x00004502
+
+/* Internal error: The IPL type is incorrect */
+#define EWRONGTYPE		0x00004510
+
+/* Internal error */
+#define EINTERNAL		0x00004511
+
+/* kdump: No operating system information was found */
+#define EOS_INFO_MISSING	0x00004520
+
+/* kdump: The checksum of the operating system information is incorrect */
+#define EOS_INFO_CSUM_FAILED	0x00004521
+
+/* kdump: The major version of the operating system information is too high */
+#define EOS_INFO_VERSION	0x00004522
+
+/* kdump: No crashkernel memory was defined */
+#define EOS_INFO_NOCRASHKERNEL	0x00004523
+
+/* kdump: HSA copy failed */
+#define EHSA_COPY_FAILED	0x00004524
+
+/************************************************************************
+ * The following codes are not ABI
+ ************************************************************************/
+
+#define ETIMEOUT       2
+
+/*
+ * Stand-alone dump
+ */
+#define OK		0x00000000  /* Dump completed successfully */
+#define EMEM		0x00004600  /* Device too small for dump */
+#define EDEVNOTSUP	0x00004601  /* Device not supported */
+#define EMEMCOUNT	0x00004602  /* Could not evaluate memory layout */
+
+/*
+ * Multi-volume dump
+ */
+#define ENODEVNO	0x00004603  /* The devno does not exist */
+#define ENOSIGN		0x00004604  /* No valid dump signature on device */
+#define ENOTIME		0x00004605  /* The zipl time stamps do not match */
+
+#endif /* ERROR_H */
--- /dev/null
+++ b/zipl/boot/fba.h
@@ -0,0 +1,56 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * DASD FBA specific functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ *
+ */
+
+#ifndef FBA_H
+#define FBA_H
+
+#include "error.h"
+#include "libc.h"
+#include "stage2.h"
+
+/* CCW COMMANDS */
+#define DASD_FBA_CCW_LOCATE	0x43
+#define DASD_FBA_CCW_LR	        0x06
+#define DASD_FBA_CCW_DE	        0x63
+#define DASD_FBA_CCW_WRITE	0x41
+#define DASD_FBA_CCW_READ	0x42
+
+#define MAX_BLOCKCT             128
+
+struct DE_fba_data {
+	struct {
+		unsigned char perm:2;   /* Permissions on this extent */
+		unsigned char zero:2;   /* Must be zero */
+		unsigned char da:1;     /* usually zero */
+		unsigned char diag:1;   /* allow diagnose */
+		unsigned char zero2:2;  /* zero */
+	} __packed mask;
+	uint8_t zero;              /* Must be zero */
+	uint16_t blk_size;         /* Blocksize */
+	uint32_t ext_loc;          /* Extent locator */
+	uint32_t ext_beg;          /* logical number of block 0 in extent */
+	uint32_t ext_end;          /* logical number of last block in extent */
+} __packed;
+
+struct LO_fba_data {
+	struct {
+		unsigned char zero:4;
+		unsigned char cmd:4;
+	} __packed operation;
+	uint8_t auxiliary;
+	uint16_t blk_ct;
+	uint32_t blk_nr;
+} __packed;
+
+struct indirect_block {
+	uint64_t *block;
+} __packed;
+
+#endif /* FBA_H */
--- a/zipl/boot/fba0.S
+++ b/zipl/boot/fba0.S
@@ -1,73 +1,46 @@
 #
-#  Ipl stage 0 loader
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+# IPL stage 0 and 1 loader for FBA
+#
+# Copyright IBM Corp. 2001, 2012
+# Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+#            Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Startup for IPL at address 0
+# Second stage boot loader is loaded to 0x2000 and starts at 0x2018
+#
+# The first 24 bytes are loaded by IPL to addresses 0-23 (PSW and two CCWs).
+# The CCWs on 8-23 are used as a continuation of the implicit IPL channel
+# program.
+# The 1st CCW reads block 0 again with READ IPL
+# The 2nd CCW tics to the re-loaded stage 1 IPL record.
 #
-#  startup for ipl at address 0
-#  second stage boot loader is loaded to 0x1000 and starts at 0x1008
-
-# The first 24 byes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
-# The CCWs on 8-23 are used as a continuation of the implicit ipl channel
-# program. The fba ipl loader only uses the CCW on 8-15 to load parts of the
-# the first block again starting from 0 (the reading starts again at block 0,
-# byte 0). 
-
 	.org   0x0
 	.globl _start
 _start:
-	.long  0x00080000,0x80002008           # The first 24 byte are loaded
-        .long  0x02000200,0x60000000+.Lend     # by ipl to addresses 0-23.
-        .long  0x08000000+.Ltic+512,0x40000000 # Tic to continuation
-	.long  0x00000000,0x02000000           # room for load descriptor
-        .long  0x00000000,0x00000000
-.Ltic:	.long  0x43000000+.Llo0+512,0x40000008 # locate record 0
-        .long  0x42002000,0x60000200           # bytes 0-512 of second stage
-	.long  0x43000000+.Llo1+512,0x40000008 # locate record 1
-	.long  0x42002200,0x60000200           # bytes 512-1024 of 2nd stage
-	.long  0x43000000+.Llo2+512,0x40000008 # locate record 2
-	.long  0x42002400,0x60000200           # bytes 1024-1536 of 2nd stage
-	.long  0x43000000+.Llo3+512,0x40000008 # locate record 3
-	.long  0x42002600,0x60000200           # bytes 1536-2048 of 2nd stage
-	.long  0x43000000+.Llo4+512,0x40000008 # locate record 4
-	.long  0x42002800,0x60000200           # bytes 2048-2560 of 2nd stage
-	.long  0x43000000+.Llo5+512,0x40000008 # locate record 5
-	.long  0x42002A00,0x60000200           # bytes 2560-3072 of 2nd stage
-	.long  0x43000000+.Llo6+512,0x40000008 # locate record 6
-	.long  0x42002C00,0x60000200           # bytes 3072-3584 of 2nd stage
-	.long  0x43000000+.Llo7+512,0x40000008 # locate record 7
-	.long  0x42002E00,0x60000200           # bytes 3584-4096 of 2nd stage
-	.long  0x43000000+.Llo8+512,0x40000008 # locate record 8
-	.long  0x42003000,0x60000200           # bytes 4096-4608 of 2nd stage
-	.long  0x43000000+.Llo9+512,0x40000008 # locate record 9
-	.long  0x42003200,0x60000200           # bytes 4608-5120 of 2nd stage
-	.long  0x43000000+.Llo10+512,0x40000008 # locate record 10
-	.long  0x42003400,0x60000200           # bytes 5120-5632 of 2nd stage
-	.long  0x43000000+.Llo11+512,0x40000008 # locate record 11
-	.long  0x42003600,0x60000200           # bytes 5632-6144 of 2nd stage
-	.long  0x43000000+.Llo12+512,0x40000008 # locate record 12
-	.long  0x42003800,0x60000200           # bytes 6144-6656 of 2nd stage
-	.long  0x43000000+.Llo13+512,0x40000008 # locate record 13
-	.long  0x42003A00,0x60000200           # bytes 6656-7168 of 2nd stage
-	.long  0x43000000+.Llo14+512,0x40000008 # locate record 14
-	.long  0x42003C00,0x60000200           # bytes 7168-7680 of 2nd stage
-	.long  0x43000000+.Llo15+512,0x40000008 # locate record 15
-	.long  0x42003E00,0x20000200           # bytes 7680-8192 of 2nd stage
+	.long  0x00080000,0x80002018		# The first 24 byte are loaded
+	.long  0x02000000,0x60000000+.Lend	# by ipl to addresses 0-23.
+	.long  0x08000000+.Ltic,0x40000000	# Tic to continuation
+#
+# Here starts stage 1
+#
+.Ltic:	.long  0x43000000+.Llo0,0x40000008	# locate record 0
+	.long  0x42000000,0x60000200		# bytes 0-512 of stage 1 ext
+	.long  0x43000000+.Llo1,0x40000008	# locate record 1
+	.long  0x42000000,0x60000200		# bytes 512-1024 of stage 1 ext
+	.long  0x08000000,0x00000000		# tic to stage 1b
 # offset 2 in .Llo[0-15]: block count (unsigned short) = 1
 # offset 4 in .Llo[0-15]: block number (unsigned long)
 .Llo0:	.long  0x06000001,0x00000000
 .Llo1:	.long  0x06000001,0x00000000
-.Llo2:	.long  0x06000001,0x00000000
-.Llo3:	.long  0x06000001,0x00000000
-.Llo4:	.long  0x06000001,0x00000000
-.Llo5:	.long  0x06000001,0x00000000
-.Llo6:	.long  0x06000001,0x00000000
-.Llo7:	.long  0x06000001,0x00000000
-.Llo8:	.long  0x06000001,0x00000000
-.Llo9:	.long  0x06000001,0x00000000
-.Llo10:	.long  0x06000001,0x00000000
-.Llo11:	.long  0x06000001,0x00000000
-.Llo12:	.long  0x06000001,0x00000000
-.Llo13:	.long  0x06000001,0x00000000
-.Llo14:	.long  0x06000001,0x00000000
-.Llo15:	.long  0x06000001,0x00000000
+
+	.long  0x00000000,0x00000000		# reserved
+	.long  0x00000000,0x00000000		# reserved
+	.long  0x00000000,0x00000000		# reserved
+	.long  0x00000000,0x00000000		# reserved
+
+	.long  0x00000000,0x02000000		# boot_info
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
+	.long  0x00000000,0x00000000
 .Lend:
--- /dev/null
+++ b/zipl/boot/fba1b.S
@@ -0,0 +1,90 @@
+#
+# IPL stage 1b loader for FBA
+#
+# Copyright IBM Corp. 2001, 2012
+#
+# Author(s): Michael Holzheu (holzheu@linux.vnet.ibm.com)
+#
+# Stage 1b is loaded to 0xe000-0xe400 and is used to load stage 2 with
+# locate record/read CCWs. Currently stage 1b can load up to 24
+# blocks and therefore 12 KiB stage 2 code with 512 byte block size.
+#
+	.org   0x0
+	.globl _start
+_start:
+	.long  0x43000000+.Llo0,0x40000008  # locate record 0
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo1,0x40000008  # locate record 1
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo2,0x40000008  # locate record 2
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo3,0x40000008  # locate record 3
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo4,0x40000008  # locate record 4
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo5,0x40000008  # locate record 5
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo6,0x40000008  # locate record 6
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo7,0x40000008  # locate record 7
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo8,0x40000008  # locate record 8
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo9,0x40000008  # locate record 9
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo10,0x40000008 # locate record 10
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo11,0x40000008 # locate record 11
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo12,0x40000008 # locate record 12
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo13,0x40000008 # locate record 13
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo14,0x40000008 # locate record 14
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo15,0x40000008 # locate record 15
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo16,0x40000008 # locate record 16
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo17,0x40000008 # locate record 17
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo18,0x40000008 # locate record 18
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo19,0x40000008 # locate record 19
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo20,0x40000008 # locate record 20
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo21,0x40000008 # locate record 21
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo22,0x40000008 # locate record 22
+	.long  0x42000000,0x60000200        # read
+	.long  0x43000000+.Llo23,0x40000008 # locate record 23
+	.long  0x42000000,0x20000200        # read
+# offset 2 in .Llo[0-15]: block count (unsigned short) = 1
+# offset 4 in .Llo[0-15]: block number (unsigned long)
+.Llo0:	.long  0x06000001,0x00000000
+.Llo1:	.long  0x06000001,0x00000000
+.Llo2:	.long  0x06000001,0x00000000
+.Llo3:	.long  0x06000001,0x00000000
+.Llo4:	.long  0x06000001,0x00000000
+.Llo5:	.long  0x06000001,0x00000000
+.Llo6:	.long  0x06000001,0x00000000
+.Llo7:	.long  0x06000001,0x00000000
+.Llo8:	.long  0x06000001,0x00000000
+.Llo9:	.long  0x06000001,0x00000000
+.Llo10:	.long  0x06000001,0x00000000
+.Llo11:	.long  0x06000001,0x00000000
+.Llo12:	.long  0x06000001,0x00000000
+.Llo13:	.long  0x06000001,0x00000000
+.Llo14:	.long  0x06000001,0x00000000
+.Llo15:	.long  0x06000001,0x00000000
+.Llo16:	.long  0x06000001,0x00000000
+.Llo17:	.long  0x06000001,0x00000000
+.Llo18:	.long  0x06000001,0x00000000
+.Llo19:	.long  0x06000001,0x00000000
+.Llo20:	.long  0x06000001,0x00000000
+.Llo21:	.long  0x06000001,0x00000000
+.Llo22:	.long  0x06000001,0x00000000
+.Llo23:	.long  0x06000001,0x00000000
+.org 1024 # Stage 1b should have 1024 byte
+.Lend:
--- a/zipl/boot/fba2.S
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-#  Second stage boot loader for fba devices.
-#    Copyright IBM Corp. 2001, 2006.
-#    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
-#
-
-#
-# An fba blocklist is 8 bytes in length and contains 3 entries:
-#   offset 0 : block number (32 bit)
-#   offset 4 : size of blocks (16 bit)
-#   offset 6 : number of blocks (16 bit) - 1
-#
-
-STAGE2_DESC = 0x218
-
-#include "common.S"
-
-# expand the common start code from iplcommon.s
-	stage2_start
-	
-# expand blocklist traversing code from iplcommon.s
-        blocklist_traverser
-
-# expand enable/disable routines
-	device_fn
-	
-# parameter
-#   %r2+%r3: blocklist descriptor
-# returns
-#   %r2    : number of bytes (blocksize * number of blocks)
-_extract_length:
-	lr     %r2,%r3
-	srl    %r2,16
-	sll    %r3,16
-	srl    %r3,16
-	la     %r3,1(%r3)
-	msr    %r2,%r3
-	br     %r14
-
-# parameter
-#   %r2+%r3: blocklist descriptor
-# returns
-#   %r2    : == 0 for normal block descriptor
-#            != 0 for zero block descriptor
-_is_zero_block:
-	br     %r14
-
-# parameter
-#   %r2+%r3: blocklist descriptor
-#   %r4    : device subchannel id
-#   %r5    : load address
-# returns
-#   %r2    : updated load address
-_load_direct:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-.Lbase:	s      %r15,.Lc96-.Lbase(%r13)  # create stack frame
-	lr     %r12,%r5                 # save load address
-	lr     %r11,%r4                 # save subchannel id
-	lr     %r10,%r3
-	n      %r10,.Lc65535-.Lbase(%r13)       # low word = number of blocks
-	la     %r10,1(%r10)             # add 1 to number of blocks
-	lr     %r9,%r3
-	srl    %r9,16                   # high word = size of blocks
-	lr     %r8,%r2                  # save block number
-.Lmain: # main loop
-	ltr    %r0,%r10                 # any blocks left ?
-	bnp    .Lexit-.Lbase(%r13)
-	cl     %r0,.Lc128-.Lbase(%r13)  # more than 128 blocks left ?
-	bnh    .Lblks-.Lbase(%r13)
-	l      %r0,.Lc128-.Lbase(%r13)  # limit to 128 blocks in one go
-.Lblks: sth    %r9,.Lde+2-.Lbase(%r13)  # store block size to define extent
-	st     %r8,.Lde+4-.Lbase(%r13)  # store start block to define extent
-        alr    %r8,%r0                  # increase start block
-	slr    %r10,%r0                 # reduce number of blocks left
-	lr     %r1,%r0
-	bctr   %r1,0                    # decrease number of blocks by 1
-	st     %r1,.Lde+12-.Lbase(%r13) # store last block to define extent
-	l      %r1,.Lprd-.Lbase(%r13)   # load address of ccw area
-	l      %r2,.Lplo-.Lbase(%r13)   # load address of locate area
-        mvc    0(8,%r1),.Lskde-.Lbase(%r13)     # copy DE ccw to chain
-	la     %r1,8(%r1)
-	slr    %r3,%r3
-        b      .Llpst-.Lbase(%r13)
-.Lloop:	oi     9(%r1),0x40              # set command chain bit
-	la     %r1,16(%r1)              # update ccw pointer
-	la     %r2,8(%r2)               # update locate pointer
-.Llpst:	mvc    0(16,%r1),.Lskrd-.Lbase(%r13)    # copy locate/read ccw to chain
-        mvc    0(8,%r2),.Lsklo-.Lbase(%r13)     # copy locate record skeleton
-	st     %r2,4(%r1)               # store locate record address to ccw
-	st     %r3,4(%r2)               # store logical block number to locate
-        sth    %r9,10(%r1)              # store block size to read ccw
-	st     %r12,12(%r1)             # store load address to read ccw
-	alr    %r12,%r9                 # add block size to load address
-        la     %r3,1(%r3)               # increase block counter
-	bct    %r0,.Lloop-.Lbase(%r13)
-	ni     9(%r1),0xbf              # clear command chain bit
-	lr     %r2,%r11                 # pass subchannel id
-	la     %r3,.Lorb-.Lbase(%r13)   # pass address of orb
-	la     %r4,.Lirb-.Lbase(%r13)   # and pass address of irb
-        bas    %r14,_ssch-.Lbase(%r13)  # read up to 128 blocks
-	b      .Lmain-.Lbase(%r13)
-.Lexit:	lr     %r2,%r12                 # return updated load address
-        lm     %r6,%r15,120(%r15)
-        br     %r14
-.Lc1:	.long  1
-.Lc96:	.long  96
-.Lc128:	.long  128
-.Lc65535:
-	.long  65535
-.Lprd:	.long  0x4000
-.Lplo:	.long  0x6000
-        .align 8
-.Lskrd:	.long  0x43400008,0x00000000    # locate ccw skeleton
-	.long  0x42200000,0x00000000    # read ccw skeleton
-.Lskde: .long  0x63400010,.Lde          # define extent ccw skeleton
-.Lsklo:	.long  0x06000001,0x00000000    # locate record skeleton
-# offset 2 in locate: block count, offset 4 in locate: block number
-.Lde:	.long  0x40000200,0x00000000    # offset 4 in DE: extent locator
-        .long  0x00000000,0x00000000    # offset 8 in DE: first logical block
-	                                # offset 12 in DE: last logical block
-.Lirb:	.fill  64,1,0
-.Lorb:	.long  0x00000000,0x0080ff00,0x4000,0
-
-# expand io subroutines from iplcommon.s
-	io_subroutines
-
-	# boot menu parameter area follows
-	menu_param_area
--- /dev/null
+++ b/zipl/boot/fba2.c
@@ -0,0 +1,122 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Subroutines for FBA disks.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "fba.h"
+#include "libc.h"
+#include "s390.h"
+
+int extract_length(void *data) {
+	struct linear_blockptr *blockptr = (struct linear_blockptr *)data;
+
+	return blockptr->size * (blockptr->blockct + 1);
+}
+
+int is_zero_block(void *data) {
+	struct linear_blockptr *blockptr = (struct linear_blockptr *)data;
+
+	return blockptr->blockno;
+}
+
+void *load_direct(disk_blockptr_t *data, struct subchannel_id subchannel_id,
+	    void *load_addr)
+{
+	struct linear_blockptr *blockptr = (struct linear_blockptr *)data;
+	struct DE_fba_data *de_data;
+	struct LO_fba_data *lo_data;
+	struct ccw1 *ccws;
+	unsigned long record_size;
+	int record_number;
+	struct orb orb;
+	struct irb *irb;
+	void *page;
+	int ccw_counter, lo_counter;
+
+	irb = (struct irb *)&S390_lowcore.irb;
+
+restart:
+	/*
+	 * allocate one page for:
+	 *    16 byte de_data
+	 *    128 * 8 Byte lo_data
+	 *    128 * 8 Byte ccws
+	 *
+	 * = 2064 Byte used
+	 */
+	page = (void *)get_zeroed_page();
+	de_data = (struct DE_fba_data *)page;
+	lo_data	= (struct LO_fba_data *)(page + sizeof(struct DE_fba_data));
+	ccws = (struct ccw1 *)(page + sizeof(struct DE_fba_data) +
+			       128 * sizeof(struct LO_fba_data));
+
+	ccw_counter = 0;
+	lo_counter = 0;
+	memset(irb, 0, sizeof(struct irb));
+	memset(&orb, 0, sizeof(struct orb));
+
+	if (blockptr->blockct > MAX_BLOCKCT) {
+		record_number = MAX_BLOCKCT - 1;
+		blockptr->blockct -= MAX_BLOCKCT;
+	} else {
+		record_number = blockptr->blockct;
+		blockptr->blockct -= record_number;
+	}
+
+	record_size = blockptr->size;
+
+	/* initialise DEFINE_EXTENT */
+	ccws[0].cmd_code = DASD_FBA_CCW_DE;
+	ccws[0].flags = CCW_FLAG_CC;
+	ccws[0].count = 16;
+	de_data->mask.perm = 0x1;
+	de_data->blk_size = blockptr->size;
+	de_data->ext_loc = blockptr->blockno;
+	ccws[0].cda = (uint32_t) (unsigned long) de_data;
+	ccw_counter++;
+
+	/* add 1 LO and 1 READ CCW per block */
+	while (1) {
+		/* initialise LOCATE_RECORD */
+		ccws[ccw_counter].cmd_code = DASD_FBA_CCW_LOCATE;
+		ccws[ccw_counter].flags = CCW_FLAG_CC;
+		ccws[ccw_counter].count = 8;
+		lo_data[lo_counter].operation.cmd = 0x6;
+		lo_data[lo_counter].blk_nr = lo_counter;
+		de_data->ext_end = lo_counter;
+		lo_data[lo_counter].blk_ct = 1;
+		ccws[ccw_counter].cda = (unsigned long) &lo_data[lo_counter];
+		lo_counter++;
+		ccw_counter++;
+
+		/* initialise READ_CCW */
+		ccws[ccw_counter].cmd_code = DASD_FBA_CCW_READ;
+		ccws[ccw_counter].count = record_size;
+		ccws[ccw_counter].cda = (uint32_t) (unsigned long) load_addr;
+		ccw_counter++;
+
+		blockptr->blockno++;
+		record_number--;
+		load_addr += record_size;
+
+		if (record_number >= 0)
+			ccws[ccw_counter-1].flags |= CCW_FLAG_CC;
+		else
+			break;
+	}
+
+	orb.fmt = 1;
+	orb.cpa = (uint32_t) (unsigned long) ccws;
+
+	start_io(subchannel_id, irb, &orb);
+	free_page((unsigned long)page);
+
+	if (blockptr->blockct > 0)
+		goto restart;
+
+	return load_addr;
+}
--- a/zipl/boot/fba2dump.S
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- *  Dump boot loader for FBA DASDs
- *    Copyright IBM Corp. 2004, 2006.
- *    Author(s): Michael Holzheu  <holzheu@de.ibm.com>
- *               
- * Uses extern functions:            
- *  - _panik
- *  - _enable_device
- *  - _take_dump
- *
- * Functions:
- *  - _dump_mem
- */
-
-#include "dumpcommon.S"
-#if defined(__s390x__)
-#define USE_64BIT_SCLP
-#endif
-#include "sclp.S"
-
-/* General defines */
-
-#define IPL_BS 0x2000
-#define BLOCKS_PER_WRITE 64 
-#define FBA_BLK_SIZE 0x200
-#define STAGE2_DESC 0x218
-
-################################################################################
-# Function entry point at 0x2000 (not used for dump) is called with C linkage
-#   %r2-%r3: load descriptor
-#   %r3    : device subchannel id
-#   %r4    : load address
-################################################################################
-
-#if defined(__s390x__)
-dump_magic:  .long 0x5a444642, 0x41363402 # ZDFBA64, version 2
-#else
-dump_magic:  .long 0x5a444642, 0x41333102 # ZDFBA31, version 2
-#endif
-
-#if defined(__s390x__)
-
-
-/******************************** 64 BIT **************************************/
-
-
-################################################################################
-# Program execution of the second stage boot loader starts at 0x2008
-################################################################################
-
-        .globl _start
-_start: 
-        basr  %r13,0
-.Linit_base:
-        la    %r9,0
-        st    %r9,.Ldh_arch-.Linit_base(%r13) # init arch 
-        l     %r15,1f-.Linit_base(%r13)       # load end of stack address
-        la    %r7,0
-        tm    __LC_ARCH_MODE_ID(%r9),0x01     # check arch mode
-        bnz   .Larch_64-.Linit_base(%r13)
-
-        /* 32 bit store status */
-
-        l     %r14,.Lstore_status_32-.Linit_base(%r13)
-        basr  %r14,%r14
-        la    %r10,ARCH_S390_ID
-        st    %r10,.Ldh_arch-.Linit_base(%r13)
-
-.Larch_64:
-        la    %r7,2                             # first try code 2:
-        la    %r6,0                             # 64 bit psws are restored
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-        bc    8,.Lswitched_64-.Linit_base(%r13) # order accepted ?
-        la    %r7,1                             # code 2 failed - try code 1
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-.Lswitched_64:
-        sam64                                   # switch to 64 bit addr mode
-        basr   %r13,0
-0:      llgf   %r15,1f-0b(%r13)                 # load end of stack address
-        
-        llgf   %r10,.Ldh_arch-0b(%r13)
-        cghi   %r10,ARCH_S390_ID
-        be     .Larch_32-0b(%r13)
-
-        /* 64 bit store status */
-
-        llgf   %r14,.Lstore_status_64-0b(%r13)
-        basr   %r14,%r14
-        lghi   %r10,ARCH_S390X_ID
-        st     %r10,.Ldh_arch-0b(%r13)
-
-.Larch_32:
-        llgf   %r2,IPL_SC                   # load ipl device subchannel id
-        llgf   %r14,.Lenable_device_64-0b(%r13)
-        basr   %r14,%r14
-        llgf   %r14,.Ltake_dump_64-0b(%r13)
-        basr   %r14,%r14
-1:      .long  0x10000-128                  # end of stack
-
-################################################################################
-# Dump memory
-#  -no parameters
-################################################################################
-
-_dump_mem_64:    
-        stmg   %r6,%r15,48(%r15)
-        basr   %r13,0                         # base register
-0:      aghi   %r15,-200                      # create stack frame
-
-        # init progress bar
-
-        bras %r14,_init_print_progress_64
-
-        # get start and end block
-
-	mvc    .Ldev_start_blk-0b(4,%r13),STAGE2_DESC+4
-	mvc    .Ldev_end_blk-0b(4,%r13),STAGE2_DESC+8+4
-
-        # setup define extend
-
-        l         %r7,.Ldev_end_blk-0b(%r13)
-        st        %r7,12+.Ldedata-0b(%r13)
-
-        # calculate bytes per write (blksize * blwr)
-
-        llgf    %r11,.Ldev_blk_size-0b(%r13)
-        mh      %r11,.Lblocks_per_write-0b(%r13)
-        st      %r11,.Lbytes_per_write-0b(%r13)
-
-# write header
-
-        llgf    %r11,.Ldev_start_blk-0b(%r13) # start block
-
-        lgr     %r2,%r11
-        lghi    %r3,HEADER_PAGE_START
-        lghi    %r4,HEADER_SIZE
-        srda    %r4,32                        # shift ==> 64 bit number        
-        llgf    %r6,.Ldev_blk_size-0b(%r13)   # get blocksize
-
-        dr      %r4,%r6                       # nr of blocks for header = 
-                                              # HEADER_SIZE / BLOCKSIZE = r5
-        lgr     %r4,%r5
-        lgr     %r12,%r5                      # save nr of blocks        
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-        ar      %r11,%r12                     # update block counter
-
-# write memory
-
-        lghi    %r10,0                        # start at address 0
-
-.Lmloop:        
-        lghi    %r4,BLOCKS_PER_WRITE          # write so many blocks at a time
-        lgr     %r2,%r11                      # restore r2
-        lgr     %r3,%r10                      # restore r3
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-        llgf    %r2,.Lbytes_per_write-0b(%r13)
-        agr     %r10,%r2                      # update data address
-        aghi    %r11,BLOCKS_PER_WRITE         # skip to next block
-
-        lgr     %r2,%r10                      # print progress to console
-        bras    %r14,_print_progress_64
-
-        lg      %r3,.Ldh_mem_size-0b(%r13)    # get memsize
-        clgr    %r10,%r3                      # enough ?
-        bl      .Lmloop-0b(%r13)              # branch if r10 < r3
-
-# write end marker
-
-.lendmarker:                                  # terminate dump file
-        stck    .Ld_end_time-0b(%r13)         # store end time
-        lgr     %r2,%r11                      # restore r2
-	lghi     %r3, TMP_PAGE_START
-	mvc     0(256,%r3),.Ld_endmarker-0b(%r13) # move to 4k boundary
-        lghi    %r4,1                         # write one block
-        bas     %r14,_writeblock_64-0b(%r13)  # write block to disk
-
-        lmg     %r6,%r15,248(%r15)
-        br      %r14                          # return to caller
-.Lbytes_per_write:  .long 0x00000000
-.Lblocks_per_write: .word BLOCKS_PER_WRITE
-
-################################################################################
-# This function writes a block number given in r2 to disk
-#  -r2:  number of first block to write ( input by caller )
-#        We start counting with Block Nr 0 !!!
-#  -r3:  address to write data from ( input by caller )
-#  -r4:  number of blocks to write ( input by caller )
-################################################################################
-
-_writeblock_64:
-        stmg    %r6,%r15,48(%r15)
-        basr    %r13,0                        # base register
-0:      aghi    %r15,-200                     # create stack frame
-
-        # check if blocks are within range:
-
-        lgr     %r11,%r2
-        agr     %r11,%r4                      # End block
-        llgf    %r12,.Ldev_end_blk-0b(%r13)
-        clr     %r11,%r12                     # End block < dev_end_blk ?
-        bl      1f-0b(%r13)                   # no
-        la      %r2,EMEM                      # if yes panik
-        llgf    %r14,.Lpanik_64-0b(%r13)
-        basr    %r14,%r14 
-        
-1:      la      %r12,.Ldeccw-0b(%r13)
-        st      %r12,8+.Lorb-0b(%r13)         # store cpaddr to orb
-        la      %r12,.Lwrccw-0b(%r13)
-        oi      1(%r12),0x04                  # enable indirect data addressing
-
-        #setup locate ccw
-        sth     %r4,2+.Llodata-0b(%r13)       # store number of blocks
-        st      %r2,4+.Llodata-0b(%r13)       # store first block
-
-        # setup write ccw
-        la      %r12,.Lwrccw-0b(%r13)
-        la      %r10,.Lida_list-0b(%r13)      # pointer to ida list
-        st      %r10,4+.Lwrccw-0b(%r13)       # store idal data address
-        lgr     %r7,%r4
-        mh      %r7,2+.Ldev_blk_size-0b(%r13)
-        sth     %r7,2+.Lwrccw-0b(%r13)        # store byte count
-
-	# setup idas
-
-	lgr	%r2,%r3                       # start address
-	lgr     %r3,%r7                       # byte count
-	lgr     %r4,%r10                      # address of ida list
-        bas     %r14,_create_ida_list_64-0b(%r13) # create ida list
-	
-        # CCWs are setup now, arent they?
-
-        llgf    %r2,IPL_SC                    # subchannel id
-        la      %r3,.Lorb-0b(%r13)
-        la      %r4,.Lirb-0b(%r13)
-        la      %r5,10                        # initialize retries
-
-        bas     %r14,_ssch_64-0b(%r13)        # start I/O
-
-        lmg     %r6,%r15,248(%r15)
-        br      %r14                          # return to caller
-.align 8
-.Lorb:
-        .long 0x0049504c,0x0082ff00
-        .long 0x00000000,0x00000000
-.Lirb:
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-.Ldedata:
-        .long 0xc0000200,0x00000000
-        .long 0x00000000,0x00001000
-.Llodata:
-        .long 0x01000000,0x00000000
-.align 8
-.Lida_list: # enough for 128 blocks a 512 byte
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-
-################################################################################
-# expand Macros
-################################################################################
-
-        hex_to_ebcdic
-        print_progress_64
-        dump_common_store_status_32
-        dump_common_fn_64
-        dump_io_subroutines_64
-        dump_idal_64
-        dump_messages
-        dump_header
-        tmp_data
-        sclp_base
-        sclp_print
-        sclp_read_info
-
-# extern functions
- 
-.Lpanik_64:
-        .long      _panik_64
-.Lenable_device_64:
-        .long      _enable_device_64
-.Ltake_dump_64:
-        .long      _take_dump_64
-.Lstore_status_32:
-        .long      _store_status_32
-.Lstore_status_64:
-        .long      _store_status_64
-
-
-
-
-
-#else /* __s390x__ */
-
-
-
-/******************************** 32 BIT **************************************/
-
-
-################################################################################
-# Program execution of the second stage boot loader starts at 0x2008
-################################################################################
-
-        .globl _start
-_start: basr   %r13,0
-0:      l      %r15,1f-0b(%r13)             # load end of stack address
-
-	tm    __LC_ARCH_MODE_ID,0x01        # check arch mode
-	bz   .Larch_31-0b(%r13)
-	la    %r10,ARCH_S390X_ID
-	st    %r10,.Ldh_arch-0b(%r13)
-
-.Larch_31:
-        l      %r11,IPL_SC                  # load ipl device subchannel id
-        lr     %r2,%r11
-        l      %r14,.Lenable_device_32-0b(%r13)
-        basr   %r14,%r14
-        l      %r14,.Ltake_dump_32-0b(%r13)
-        basr   %r14,%r14
-1:      .long  0x10000-96                   # end of stack
-
-
-################################################################################
-# Dump memory
-#  - no parameters
-################################################################################
-
-_dump_mem_32:    
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                         # base register
-0:      s      %r15,.Lc96-0b(%r13)            # create stack frame
-
-        # init progress bar
-
-        bras %r14,_init_print_progress_32
-
-        # get start and end block
-
-	mvc    .Ldev_start_blk-0b(4,%r13),STAGE2_DESC+4
-	mvc    .Ldev_end_blk-0b(4,%r13),STAGE2_DESC+8+4
-
-        # setup define extend
-
-	l         %r7,.Ldev_end_blk-0b(%r13)
-	st        %r7,12+.Ldedata-0b(%r13)
-
-        # calculate bytes per write (blksize * blwr)
-
-        l       %r11,.Ldev_blk_size-0b(%r13)
-        mh      %r11,.Lblocks_per_write-0b(%r13)
-        st      %r11,.Lbytes_per_write-0b(%r13)
-
-# write header
-        l       %r11,.Ldev_start_blk-0b(%r13) # start block
-
-        lr      %r2,%r11
-        lhi     %r3,HEADER_PAGE_START
-        lhi     %r4,HEADER_SIZE
-        srda    %r4,32                        # shift ==> 64 bit number        
-        l       %r6,.Ldev_blk_size-0b(%r13)   # get blocksize
-
-        dr      %r4,%r6                       # nr of blocks for header = 
-                                              # HEADER_SIZE / BLOCKSIZE = r5
-        lr      %r4,%r5
-        lr      %r12,%r5                      # save nr of blocks        
-        bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-        ar      %r11,%r12                     # update block counter
-
-# write memory
-
-        la      %r10,0                        # start at address 0
-
-.Lmloop:        
-        la      %r4,BLOCKS_PER_WRITE          # write so many blocks at a time
-        lr      %r2,%r11                      # restore r2
-        lr      %r3,%r10                      # restore r3
-        bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-        l       %r2,.Lbytes_per_write-0b(%r13)
-        ar      %r10,%r2                      # update data address
-        ah      %r11,.Lblocks_per_write-0b(%r13) # skip to next block
-
-        lr      %r2,%r10                      # print progress to console
-        bras    %r14,_print_progress_32
-
-        l       %r3,.Ldh_mem_size+4-0b(%r13)  # get memsize
-        clr     %r10,%r3                      # enough ?
-        bl      .Lmloop-0b(%r13)              # branch if r10 < r3
-
-# write end marker
-
-.lendmarker:                                  # terminate dump file
-        la      %r4,1                         # write endmaker with one block
-        stck    .Ld_end_time-0b(%r13)         # store end time
-        lr      %r2,%r11                      # restore r2
-	lhi     %r3, TMP_PAGE_START
-        mvc     0(256,%r3),.Ld_endmarker-0b(%r13) # move to 4k boundary
-        la      %r4,1                         # write 4k at a time
-	bas     %r14,_writeblock_32-0b(%r13)  # write block to disk
-
-        lm      %r6,%r15,120(%r15)
-        br      %r14                          # return to caller
-.Lbytes_per_write:  .long 0x00000000
-.Lblocks_per_write: .word BLOCKS_PER_WRITE
-
-################################################################################
-# This function writes a block number given in r2 to disk
-#  -r2:   number of first block to write ( input by caller )
-#         We start counting with Block Nr 0 !!!
-#  -r3:   address to write data from ( input by caller )
-#  -r4:   number of blocks to write ( input by caller )
-################################################################################
-
-_writeblock_32:
-        stm     %r6,%r15,24(%r15)
-        basr    %r13,0                        # base register
-0:      s       %r15,.Lc96-0b(%r13)           # create stack frame
-
-        # check if blocks are within range:
-        
-        lr      %r11,%r2
-        ar      %r11,%r4                      # End block
-        l       %r12,.Ldev_end_blk-0b(%r13)
-        clr     %r11,%r12                     # End block < dev_end_blk ?
-        bl      1f-0b(%r13)                   # no
-        la      %r2,EMEM                      # if yes panik
-        l       %r14,.Lpanik_32-0b(%r13)
-        basr    %r14,%r14 
-        
-1:      la      %r12,.Ldeccw-0b(%r13)
-        st      %r12,8+.Lorb-0b(%r13)         # store cpaddr to orb
-
-	#setup locate ccw
-	sth     %r4,2+.Llodata-0b(%r13)       # store number of blocks
-        st      %r2,4+.Llodata-0b(%r13)       # store first block
-
-	# setup write ccw
-        la      %r12,.Lwrccw-0b(%r13) 
-	oi      1(%r12),0x04                  # enable ida
-	la      %r10,.Lida_list-0b(%r13)      # pointer to ida list
-	st      %r10,4+.Lwrccw-0b(%r13)       # store data address
-	lr      %r7,%r4
-	mh      %r7,2+.Ldev_blk_size-0b(%r13)
-	sth     %r7,2+.Lwrccw-0b(%r13)        # store byte count 
-
-	# setup idas
-	lr      %r2,%r3                       # start address
-	lr      %r3,%r7                       # byte count
-        lr      %r4,%r10                      # address of ida list
-        bas     %r14,_create_ida_list_32-0b(%r13)  # create the list
-	
-        # CCWs are setup now, arent they?
-
-        l       %r2,IPL_SC                    # subchannel id
-        la      %r3,.Lorb-0b(%r13)
-        la      %r4,.Lirb-0b(%r13)
-        la      %r5,10                        # initialize retries
-
-        bas     %r14,_ssch_32-0b(%r13)        # start I/O
-
-        lm      %r6,%r15,120(%r15)
-        br      %r14                          # return to caller
-.Lccw_size:
-        .word 0x8
-.align 8
-.Lorb:
-        .long 0x0049504c,0x0080ff00           # intparm is " IPL"
-        .long 0x00000000,0x00000000
-.Lirb:
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-        .long 0x00000000,0x00000000
-.Ldedata:
-        .long 0xc0000200,0x00000000
-        .long 0x00000000,0x00001000
-.Llodata:
-        .long 0x01000000,0x00000000
-.align 8
-.Lida_list: # enough for 128 blocks a 512 byte
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-        .long 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
-
-################################################################################
-# expand Macros
-################################################################################
-
-        hex_to_ebcdic
-        print_progress_32
-        dump_common_fn_32
-        dump_io_subroutines_32
-        dump_idal_32
-        dump_messages
-        dump_header
-        tmp_data
-        sclp_base
-        sclp_print
-        sclp_read_info
-
-# extern functions
- 
-.Lpanik_32:
-        .long      _panik_32
-.Lenable_device_32:
-        .long      _enable_device_32
-.Ltake_dump_32:
-        .long      _take_dump_32
-
-#endif /* __s390x__ */
-
-
-################################################################################
-# DATA
-################################################################################
-
-.Lc96:  .long  96 # for creating stackframes
-
-# device characteristics
-.align 8
-.Ldev_start_blk:
-        .long  0x00000000
-.Ldev_end_blk:
-        .long  0x00000000
-.Ldev_blk_size:
-        .long  FBA_BLK_SIZE 
-
-#
-# CCWs
-#
-
-.align 8
-
-# channel program for one write
-
-.Ldeccw:
-        .long 0x63400010,0x00000000+.Ldedata     # define extent
-.Lloccw:
-        .long 0x43400008,0x00000000+.Llodata     # locate
-.Lwrccw:
-        .long 0x41200000,0x00000000              # write blocks
-
-.org (IPL_BS - 8)
-.Lmem_upper_limit:
-        .long 0xffffffff,0xffffffff              # can be used for memsize=xxx
--- /dev/null
+++ b/zipl/boot/fba2dump.c
@@ -0,0 +1,186 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Single-volume FBA DASD dump tool
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include "stage2dump.h"
+#include "error.h"
+#include "fba.h"
+
+#define BLK_PWRT	64	/* Blocks per write */
+#define BLK_SIZE	0x200	/* FBA block size */
+
+/*
+ * Magic number at start of dump record
+ */
+uint64_t magic __attribute__((section(".stage2.head")))
+	= 0x5a44464241363403ULL; /* ZDFBA64, version 3 */
+
+/*
+ * FBA dump device partition specification
+ */
+static struct {
+	unsigned int blk_start;
+	unsigned int blk_end;
+} device;
+
+/*
+ * ORB / IRB
+ */
+static struct orb orb = {
+	.intparm	= 0x0049504c,	/* Interruption Parameter */
+	.fmt		= 0x1,		/* Use format 1 CCWs */
+	.c64		= 0x1,		/* Use IDAs */
+	.lpm		= 0xff,		/* Logical path mask */
+};
+
+static struct irb irb;
+
+/*
+ * Data for Locate Record CCW
+ */
+static struct LO_fba_data lodata = {
+	.operation = {
+		.cmd = 0x1,
+	},
+};
+
+/*
+ * Data for Define Extend CCW
+ */
+static struct DE_fba_data dedata = {
+	.mask = {
+		.perm	= 0x3,
+	},
+	.blk_size	= 0x200,
+};
+
+/*
+ * CCW program and IDA list
+ */
+static struct {
+	struct ccw1 deccw;
+	struct ccw1 loccw;
+	struct ccw1 wrccw;
+	unsigned long ida_list[BLK_PWRT * BLK_SIZE / 4096];
+} ccw_program __aligned(8);
+
+/*
+ * FBA parameter block passed by zipl
+ */
+struct fba_dump_param {
+	uint32_t	res1;
+	uint32_t	blk_start;
+	uint32_t	res2;
+	uint32_t	blk_end;
+} __packed;
+
+/*
+ * Convert memory size to number of blocks
+ */
+static inline unsigned long m2b(unsigned long mem)
+{
+	return mem / BLK_SIZE;
+}
+
+/*
+ * Convert number of blocks to memory size
+ */
+static inline unsigned long b2m(unsigned long blk)
+{
+	return blk * BLK_SIZE;
+}
+
+/*
+ * Get device characteristics from zipl parameter block
+ */
+void dt_device_parm_setup(void)
+{
+	struct fba_dump_param *param = (void *) __stage2_desc;
+
+	device.blk_start = param->blk_start;
+	device.blk_end = param->blk_end;
+}
+
+/*
+ * Enable DASD device
+ */
+void dt_device_enable(void)
+{
+	io_irq_enable();
+	set_device(IPL_SC, ENABLED);
+}
+
+/*
+ * Write memory with number of blocks to start block
+ */
+static void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
+		       unsigned long zero_page)
+{
+	unsigned long blk_end;
+
+	blk_end = blk + blk_count;
+	if (blk_end >= device.blk_end)
+		panic(EMEM, "Device too small");
+	ccw_program.wrccw.count = b2m(blk_count);
+	lodata.blk_ct = blk_count;
+	lodata.blk_nr = blk;
+	create_ida_list(ccw_program.ida_list, b2m(blk_count), addr, zero_page);
+	start_io(IPL_SC, &irb, &orb);
+}
+
+/*
+ * Initialize the CCW program
+ */
+static void ccw_program_init(void)
+{
+	ccw_program.deccw.cmd_code = DASD_FBA_CCW_DE;
+	ccw_program.deccw.flags = CCW_FLAG_CC;
+	ccw_program.deccw.count = 0x0010;
+	ccw_program.deccw.cda = __pa32(&dedata);
+
+	ccw_program.loccw.cmd_code = DASD_FBA_CCW_LOCATE;
+	ccw_program.loccw.flags = CCW_FLAG_CC;
+	ccw_program.loccw.count = 0x0008;
+	ccw_program.loccw.cda = __pa32(&lodata);
+
+	ccw_program.wrccw.cmd_code = DASD_FBA_CCW_WRITE;
+	ccw_program.wrccw.flags = CCW_FLAG_IDA | CCW_FLAG_SLI;
+	ccw_program.wrccw.cda = __pa32(ccw_program.ida_list);
+
+	orb.cpa = __pa32(&ccw_program);
+	dedata.ext_end = device.blk_end;
+}
+
+/*
+ * Dump all memory to DASD partition
+ */
+void dt_dump_mem(void)
+{
+	unsigned long blk, addr, page;
+
+	ccw_program_init();
+	blk = device.blk_start;
+	page = get_zeroed_page();
+
+	/* Write dump header */
+	writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
+	blk += DF_S390_HDR_SIZE / BLK_SIZE;
+
+	/* Write memory */
+	for (addr = 0; addr < dump_hdr->mem_size; addr += b2m(BLK_PWRT)) {
+		writeblock(blk, addr, BLK_PWRT, page);
+		progress_print(addr);
+		blk += BLK_PWRT;
+	}
+	progress_print(addr);
+
+	/* Write end marker */
+	df_s390_em_page_init(page);
+	writeblock(blk, page, 1, 0);
+	free_page(page);
+}
--- /dev/null
+++ b/zipl/boot/head.S
@@ -0,0 +1,27 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Entry code for stage 2 and stage 3 boot loader
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu  <holzheu@linux.vnet.ibm.com>
+ *            Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+.section .text.start
+.globl _start
+_start:
+	basr	%r13,0
+0:	la	%r7,2				/* First try code 2: */
+	la	%r6,0				/* 64 bit psws are restored */
+	sigp	%r7,%r6,0x12			/* Switch to 64 bit */
+	bc	8,.Lswitched_64-0b(%r13)	/* Accepted ? */
+	la	%r7,1				/* Failed - try code 1 */
+	sigp	%r7,%r6,0x12			/* Switch to 64 bit */
+.Lswitched_64:
+	sam64					/* Switch to 64 bit addr mode */
+	basr	%r13,0
+1:	llgf	%r15,.Lstack-1b(%r13)		/* End of stack */
+	brasl	%r14,initialize
+.Lstack: .long  0x10000-160
+.previous
--- /dev/null
+++ b/zipl/boot/kdump.c
@@ -0,0 +1,37 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Stand-alone kdump support
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include "libc.h"
+#include "error.h"
+#include "menu.h"
+#include "kdump.h"
+#include "s390.h"
+
+void kdump_failed(unsigned long reason)
+{
+	panic(reason, "Dump failed: Check disabled wait code");
+}
+
+void os_info_check(struct os_info *os_info)
+{
+	if (os_info == NULL)
+		kdump_failed(EOS_INFO_MISSING);
+	if (((unsigned long) os_info) % PAGE_SIZE)
+		kdump_failed(EOS_INFO_MISSING);
+	if (!page_is_valid((unsigned long) os_info))
+		kdump_failed(EOS_INFO_MISSING);
+	if (os_info->magic != OS_INFO_MAGIC)
+		kdump_failed(EOS_INFO_MISSING);
+	if (csum_partial(&os_info->version_major, OS_INF0_CSUM_SIZE, 0) !=
+	    os_info->csum)
+		kdump_failed(EOS_INFO_CSUM_FAILED);
+	if (os_info->version_major > OS_INFO_VERSION_MAJOR_SUPPORTED)
+		kdump_failed(EOS_INFO_VERSION);
+	if (os_info->crashkernel_addr == 0)
+		kdump_failed(EOS_INFO_NOCRASHKERNEL);
+}
--- /dev/null
+++ b/zipl/boot/kdump.h
@@ -0,0 +1,43 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Stand-alone kdump definitions
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+
+#ifndef KDUMP_H
+#define KDUMP_H
+
+#include "libc.h"
+#include "s390.h"
+
+#define OS_INFO_VERSION_MAJOR_SUPPORTED	1
+#define OS_INFO_MAGIC			0x4f53494e464f535aULL /* OSINFOSZ */
+#define OS_INF0_CSUM_SIZE		4084
+
+#define OS_INFO_VMCOREINFO		0
+#define OS_INFO_REIPL_BLOCK		1
+
+struct os_info_entry {
+	uint64_t addr;
+	uint64_t size;
+	uint32_t csum;
+} __packed;
+
+struct os_info {
+	uint64_t magic;
+	uint32_t csum;
+	uint16_t version_major;
+	uint16_t version_minor;
+	uint64_t crashkernel_addr;
+	uint64_t crashkernel_size;
+	struct os_info_entry entry[2];
+	uint8_t reserved[4024];
+} __packed;
+
+void os_info_check(struct os_info *os_info);
+void kdump_failed(unsigned long reason);
+
+#endif /* KDUMP_H */
--- /dev/null
+++ b/zipl/boot/kdump2.c
@@ -0,0 +1,46 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Stand-alone kdump support (stage 2)
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include "libc.h"
+#include "stage2.h"
+#include "error.h"
+#include "menu.h"
+#include "kdump.h"
+
+static struct os_info **lc_os_info = ((struct os_info **)&S390_lowcore.os_info);
+
+/*
+ * Copy crashkernel memory from [0, crash size] to
+ * [crash base, crash base + crash size] if config_nr specifies a
+ * kdump boot menu entry.
+ *
+ * Parameter:
+ *   Config number (starts with 1)
+ */
+void kdump_stage2(unsigned long config_nr)
+{
+	struct os_info *os_info = *lc_os_info;
+	unsigned long crash_size;
+	void *crash_base;
+
+	if (!(__stage2_params.config_kdump & (0x1 << config_nr)))
+		return;
+	os_info_check(os_info);
+
+	/* Copy crashkernel memory */
+	crash_base = (void *) os_info->crashkernel_addr;
+	crash_size = os_info->crashkernel_size;
+	memcpy(crash_base, NULL, crash_size);
+	/*
+	 * Relocate OS info pointer if necessary (needed for stage 3)
+	 * If OS info is smaller than crash size then add crash base
+	 */
+	if (__pa(os_info) >= crash_size)
+		return;
+	*lc_os_info = (void *) __pa(os_info) + __pa(crash_base);
+}
--- /dev/null
+++ b/zipl/boot/kdump3.c
@@ -0,0 +1,108 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Stand-alone kdump support (stage 3)
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include "sclp_stage3.h"
+#include "stage3.h"
+#include "error.h"
+#include "kdump.h"
+#include "libc.h"
+
+static struct os_info **lc_os_info = (struct os_info **)&S390_lowcore.os_info;
+
+/*
+ * Copy memory from HSA and exit in case of an error
+ */
+static void copy_from_hsa(unsigned long dst, unsigned long src, int cnt)
+{
+	if (sclp_hsa_copy((void *) dst, 2 + src / PAGE_SIZE, cnt / PAGE_SIZE)) {
+		sclp_hsa_copy_exit();
+		kdump_failed(EHSA_COPY_FAILED);
+	}
+}
+
+/*
+ * Save lower memory to crash kernel memory and get crash base and size
+ */
+static void kdump_stage3_scsi(unsigned long *base, unsigned long *size)
+{
+	unsigned long os_info_addr, crash_base, crash_size, crash_end, hsa_page;
+	struct os_info *os_info;
+	unsigned long hsa_size;
+
+	hsa_page = get_zeroed_page();
+	sclp_hsa_copy_init((void *) hsa_page);
+	if (sclp_hsa_get_size(&hsa_size)) {
+		sclp_hsa_copy_exit();
+		kdump_failed(EHSA_COPY_FAILED);
+	}
+	/* Get OS info pointer from HSA lowcore */
+	copy_from_hsa(hsa_page, 0, PAGE_SIZE);
+	os_info_addr = *((unsigned long *) (hsa_page + __LC_OS_INFO));
+	/* If OS info is inside HSA, get it from there */
+	if (os_info_addr < hsa_size) {
+		copy_from_hsa(hsa_page, os_info_addr, PAGE_SIZE);
+		os_info = (void *) hsa_page;
+	} else {
+		os_info = (void *) os_info_addr;
+	}
+	os_info_check(os_info);
+	crash_base = os_info->crashkernel_addr;
+	crash_size = os_info->crashkernel_size;
+	crash_end = crash_base + crash_size;
+	/*
+	 * Copy [0, crash_size] to [crash_base, crash_base + crash_size] and
+	 * restore 1:1 memory from HSA
+	 */
+
+	/* copy [0, MIN(crash_size, hsa_size)] to [crash base, ...] from HSA */
+	copy_from_hsa(crash_base, 0, MIN(crash_size, hsa_size));
+	if (crash_size > hsa_size) {
+		/* Copy rest of crashkernel from real memory */
+		memcpy((void *) crash_base + hsa_size, (void *) hsa_size,
+		       crash_size - hsa_size);
+	} else {
+		/* Restore real memory above crash_size 1:1 from HSA */
+		copy_from_hsa(crash_size, crash_size,
+			      MIN(hsa_size, crash_base) - crash_size);
+	}
+	if (crash_end < hsa_size) {
+		/* Restore memory above crash end 1:1 from HSA */
+		copy_from_hsa(crash_end, crash_end, hsa_size -  crash_end);
+	}
+	sclp_hsa_copy_exit();
+	*base = __pa(crash_base);
+	*size = crash_size;
+}
+
+/*
+ * Get crash base and size from (stage 2 relocated) OS info lowcore pointer
+ */
+static void kdump_stage3_dasd(unsigned long *base, unsigned long *size)
+{
+	*base = (*lc_os_info)->crashkernel_addr;
+	*size = (*lc_os_info)->crashkernel_size;
+}
+
+/*
+ * Stage 3 kdump code
+ */
+void kdump_stage3(void)
+{
+	unsigned long crash_base, crash_size;
+
+	if (!(stage3_flags & STAGE3_FLAG_KDUMP))
+		return;
+	if (!(stage3_flags & STAGE3_FLAG_SCSI))
+		kdump_stage3_dasd(&crash_base, &crash_size);
+	else
+		kdump_stage3_scsi(&crash_base, &crash_size);
+
+	/* Register oldmem in kernel parameter area */
+	*((unsigned long *) OLDMEM_BASE) = crash_base;
+	*((unsigned long *) OLDMEM_SIZE) = crash_size;
+}
--- /dev/null
+++ b/zipl/boot/libc.c
@@ -0,0 +1,380 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Mini libc implementation
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ *            Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include <stdarg.h>
+#include "libc.h"
+#include "sclp.h"
+#include "error.h"
+
+extern char __heap_start[];
+extern char __heap_stop[];
+extern char __bss_start[];
+extern char __bss_stop[];
+extern char __ex_table_start[];
+extern char __ex_table_stop[];
+
+struct ex_table_entry {
+	int fault;
+	int target;
+};
+
+#define MEM_ALLOC_START	((unsigned long) __heap_start)
+#define MEM_ALLOC_CNT 4
+
+static uint8_t mem_page_alloc_vec[MEM_ALLOC_CNT];
+
+/*
+ * Initialize memory with value
+ */
+void *memset(void *s, int c, unsigned long n)
+{
+	char *xs;
+
+	xs = s;
+	while (n--)
+		*xs++ = c;
+	return s;
+}
+
+/*
+ * Copy memory
+ */
+void *memcpy(void *dest, const void *src, unsigned long n)
+{
+	const char *s = src;
+	char *d = dest;
+
+	while (n--)
+		*d++ = *s++;
+	return dest;
+}
+
+/*
+ * Copy string
+ */
+char *strcpy(char *dest, const char *src)
+{
+	const char *s = src;
+	char *d = dest;
+
+	while (*s)
+		*d++ = *s++;
+	*d = 0;
+	return dest;
+}
+
+/*
+ * Return string length
+ */
+int strlen(const char *s)
+{
+	int len = 0;
+
+	while (*s++)
+		len++;
+	return len;
+}
+
+/*
+ * Concatenate two strings
+ */
+char *strcat(char *dest, const char *src)
+{
+	strcpy(dest + strlen(dest), src);
+	return dest;
+}
+
+/*
+ * Compare two strings
+ */
+int strncmp(const char *s1, const char *s2, unsigned long count)
+{
+	while (count--)
+		if (*s1++ != *s2++)
+			return *(unsigned char *)(s1 - 1) -
+				*(unsigned char *)(s2 - 1);
+	return 0;
+}
+
+/*
+ * Convert number to string
+ *
+ * Parameters:
+ *
+ * - buf:   Output buffer
+ * - base:  Base used for formatting (e.g. 10 or 16)
+ * - val:   Number to format
+ * - zero:  If > 0, fill with leading zeros, otherwise use blanks
+ * - count: Minimum number of characters used for output string
+ */
+static int num_to_str(char *buf, int base, unsigned long val, int zero,
+		      unsigned long count)
+{
+	static const char conv_vec[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+					'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+	unsigned long num = 0, val_work = val, in_number = 1;
+	int i;
+
+	/* Count number of characters needed for number */
+	do {
+		num++;
+		val_work /= base;
+	} while (val_work);
+	/* Real character number overwrites count */
+	if (count < num)
+		count = num;
+	/* Format number */
+	for (i = count - 1; i >= 0; i--) {
+		if (in_number) {
+			buf[i] = conv_vec[val % base];
+			val /= base;
+			in_number = val ? 1 : 0;
+		} else {
+			buf[i] = zero ? '0' : ' ';
+		}
+	}
+	buf[count] = 0;
+	return count;
+}
+
+/*
+ * Convert string to string with indentation
+ */
+static int str_to_str(char *buf, const char *str, unsigned long count)
+{
+	unsigned long size;
+
+	size = strlen(str);
+	if (count < size)
+		count = size;
+	else
+		memset(buf, ' ', count - size);
+	strcpy(buf + (count - size), str);
+	return count;
+}
+
+/*
+ * Convert string to number with given base
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+	unsigned long val = 0;
+
+	while (isdigit(*nptr)) {
+		if (val != 0)
+			val *= base;
+		val += *nptr - '0';
+		nptr++;
+	}
+	if (endptr)
+		*endptr = (char *) nptr;
+	return val;
+}
+
+/*
+ * Convert ebcdic string to number with given base
+ */
+unsigned long ebcstrtoul(char *nptr, char **endptr, int base)
+{
+	unsigned long val = 0;
+
+	while (ebc_isdigit(*nptr)) {
+		if (val != 0)
+			val *= base;
+		val += *nptr - 0xf0;
+		nptr++;
+	}
+	if (endptr)
+		*endptr = (char *) nptr;
+	return val;
+}
+
+/*
+ * Convert string to number with given base
+ */
+static int sprintf_fmt(char type, char *buf, unsigned long val, int zero,
+		       int count)
+{
+	switch (type) {
+	case 's':
+		return str_to_str(buf, (const char *) val, count);
+	case 'x':
+		return num_to_str(buf, 16, val, zero, count);
+	case 'u':
+		return num_to_str(buf, 10, val, zero, count);
+	default:
+		libc_stop(EINTERNAL);
+	}
+	return 0;
+}
+
+/*
+ * Print formated string (va version)
+ */
+static void vsprintf(char *str, const char *fmt, va_list va)
+{
+	unsigned long val, zero, count;
+	char *fmt_next;
+
+	do {
+		if (*fmt == '%') {
+			fmt++;
+			if (*fmt == '0') {
+				zero = 1;
+				fmt++;
+			} else {
+				zero = 0;
+			}
+			/* No number found by strtoul: count=0 fmt_next=fmt */
+			count = strtoul(fmt, &fmt_next, 10);
+			fmt = fmt_next;
+			if (*fmt == 'l')
+				fmt++;
+			val = va_arg(va, unsigned long);
+			str += sprintf_fmt(*fmt, str, val, zero, count);
+			fmt++;
+		} else {
+			*str++ = *fmt++;
+		}
+	} while (*fmt);
+	*str = 0;
+}
+
+/*
+ * Write formated string to string
+ */
+void sprintf(char *str, const char *fmt, ...)
+{
+	va_list va;
+
+	va_start(va, fmt);
+	vsprintf(str, fmt, va);
+	va_end(va);
+}
+
+/*
+ * Print formated string
+ */
+void printf(const char *fmt, ...)
+{
+	char buf[81];
+	va_list va;
+
+	va_start(va, fmt);
+	vsprintf(buf, fmt, va);
+	sclp_print(buf);
+	va_end(va);
+}
+
+/*
+ * Allocate one zero page
+ */
+unsigned long get_zeroed_page(void)
+{
+	unsigned long addr;
+	int i;
+
+	for (i = 0; i < MEM_ALLOC_CNT; i++) {
+		if (mem_page_alloc_vec[i] != 0)
+			continue;
+		addr = MEM_ALLOC_START + i * PAGE_SIZE;
+		memset((void *) addr, 0, PAGE_SIZE);
+		mem_page_alloc_vec[i] = 1;
+		return addr;
+	}
+	libc_stop(EINTERNAL);
+}
+
+/*
+ * Free page
+ */
+void free_page(unsigned long addr)
+{
+	mem_page_alloc_vec[(addr - MEM_ALLOC_START) / PAGE_SIZE] = 0;
+}
+
+/*
+ * Program check handler
+ */
+void pgm_check_handler_fn(void)
+{
+	struct ex_table_entry *ex_table = (void *) __ex_table_start;
+	struct psw_t *psw_old = &S390_lowcore.program_old_psw;
+	int i, ex_table_cnt;
+	unsigned long fault, target;
+
+	ex_table_cnt = (__ex_table_stop - __ex_table_start)
+		/ sizeof(struct ex_table_entry);
+
+	for (i = 0; i < ex_table_cnt; i++) {
+		fault = __pa(&ex_table[i]) + ex_table[i].fault;
+		if (fault == psw_old->addr) {
+			target = __pa(&ex_table[i]) + ex_table[i].target;
+			psw_old->addr = target;
+			return;
+		}
+	}
+	libc_stop(psw_old->addr);
+}
+
+__attribute__ ((noinline)) void load_wait_psw(uint64_t psw_mask, struct psw_t *psw)
+{
+	struct psw_t wait_psw = { .mask = psw_mask, .addr = 0 };
+	struct psw_t old_psw, *wait_psw_ptr = &wait_psw;
+	unsigned long addr;
+
+	old_psw = *psw;
+	psw->mask = 0x0000000180000000ULL;
+	asm volatile(
+		"	larl	%[addr],.Lwait\n"
+		"       stg     %[addr],8(%[wait_psw_ptr])\n"
+		"       stg     %[addr],8(%[psw])\n"
+		"       lpswe	%[wait_psw]\n"
+		".Lwait:	\n"
+		: [addr] "=&d" (addr)
+		: [wait_psw] "Q" (wait_psw), [wait_psw_ptr] "a" (wait_psw_ptr),
+		  [psw] "a" (psw)
+		: "cc", "memory");
+	*psw = old_psw;
+}
+
+/*
+ * The libc startup function
+ */
+void initialize(void)
+{
+	struct psw_t *psw_pgm = &S390_lowcore.program_new_psw;
+
+	/* Setup program check handler */
+	psw_pgm->mask = 0x0000000180000000ULL;
+	psw_pgm->addr = (unsigned long) pgm_check_handler;
+
+	/* Clear bss section */
+	memset(__bss_start, 0, __bss_stop - __bss_start);
+	start();
+}
+
+/*
+ * Load disabled wait PSW with reason code in address field
+ */
+void libc_stop(unsigned long reason)
+{
+	struct psw_t psw;
+
+	psw.mask = 0x0002000080000000ULL;
+	psw.addr = reason;
+
+	asm volatile(
+		"	lpswe	 %[psw]\n"
+		: : [psw] "Q" (psw) : "cc"
+		);
+
+	while(1);
+}
--- /dev/null
+++ b/zipl/boot/libc.h
@@ -0,0 +1,103 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Mini libc implementation
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ *            Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+#ifndef LIBC_H
+#define LIBC_H
+
+#define NULL ((void *) 0)
+
+#define EPERM		 1	/* Operation not permitted */
+#define ENOENT		 2	/* No such file or directory */
+#define ESRCH		 3	/* No such process */
+#define EINTR		 4	/* Interrupted system call */
+#define EIO		 5	/* I/O error */
+#define ENXIO		 6	/* No such device or address */
+#define E2BIG		 7	/* Argument list too long */
+#define ENOEXEC		 8	/* Exec format error */
+#define EBADF		 9	/* Bad file number */
+#define ECHILD		10	/* No child processes */
+#define EAGAIN		11	/* Try again */
+#define ENOMEM		12	/* Out of memory */
+#define EACCES		13	/* Permission denied */
+#define EFAULT		14	/* Bad address */
+#define ENOTBLK		15	/* Block device required */
+#define EBUSY		16	/* Device or resource busy */
+#define EEXIST		17	/* File exists */
+#define EXDEV		18	/* Cross-device link */
+#define ENODEV		19	/* No such device */
+#define ENOTDIR		20	/* Not a directory */
+#define EISDIR		21	/* Is a directory */
+#define EINVAL		22	/* Invalid argument */
+#define ENFILE		23	/* File table overflow */
+#define EMFILE		24	/* Too many open files */
+#define ENOTTY		25	/* Not a typewriter */
+
+#define MIB	(1024ULL * 1024)
+
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+
+#include "s390.h"
+
+void printf(const char *, ...);
+void sprintf(char *, const char *, ...);
+void *memcpy(void *, const void *, unsigned long);
+void *memset(void *, int c, unsigned long);
+char *strcat(char *, const char *);
+int strncmp(const char *, const char *, unsigned long);
+unsigned long strtoul(const char *, char **, int);
+unsigned long ebcstrtoul(char *, char **, int);
+int strlen(const char *);
+char *strcpy(char *, const char *);
+unsigned long get_zeroed_page(void);
+void free_page(unsigned long);
+void initialize(void);
+void libc_stop(unsigned long) __attribute__((noreturn));
+void start(void);
+void pgm_check_handler(void);
+void load_wait_psw(uint64_t, struct psw_t *);
+void pgm_check_handler_fn(void);
+
+static inline int isdigit(int c)
+{
+	return (c >= '0') && (c <= '9');
+}
+
+static inline int isspace(char c)
+{
+	return (c == 32) || (c >= 9 && c <= 13);
+}
+
+static inline int ebc_isspace(char c)
+{
+	return (c == 0x40) || (c == 0x05) || (c == 0x15) || (c == 0x25) ||
+		(c == 0x0b) || (c == 0x0c) || (c == 0x0d);
+}
+
+static inline int ebc_isdigit(char c)
+{
+	return (c >= 0xf0) && (c <= 0xf9);
+}
+
+static inline int ebc_isupper(char c)
+{
+	return (c >= 0xC1 && c <= 0xC9) || (c >= 0xD1 && c <= 0xD9) ||
+		(c >= 0xE2 && c <= 0xE9);
+}
+
+static inline  char ebc_tolower(char c)
+{
+	if (ebc_isupper(c))
+		c -= 0x40;
+	return c;
+}
+
+#endif /* LIBC_H */
--- /dev/null
+++ b/zipl/boot/menu.c
@@ -0,0 +1,194 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Bootmenu Subroutines
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "sclp.h"
+#include "menu.h"
+#include "libc.h"
+
+static const char *msg_econfig = "Error: undefined configuration\n";
+
+static void menu_prompt(int timeout)
+{
+	if (timeout)
+		printf("Please choose (default will boot in %u seconds):",
+		       timeout);
+	else
+		printf("Please choose:");
+}
+
+static int menu_read(void)
+{
+	char *temp_area =  (char *)get_zeroed_page();
+	uint16_t *configs = __stage2_params.config;
+	int timeout, rc, i, count = 0;
+	char *endptr;
+	int value;
+
+	timeout = __stage2_params.timeout;
+
+	while (1) {
+		/* print prompt */
+		menu_prompt(timeout);
+
+		/* wait for input or timeout */
+		while (count == 0) {
+			rc = sclp_read(timeout, temp_area, &count);
+			if (rc != 0) {
+				/* timeout or error during read, boot default */
+				value = 0;
+				goto out_free_page;
+			}
+			/* disable timeout in case of retry */
+			timeout = 0;
+		}
+
+		if (count > LINE_LENGTH)
+			count = LINE_LENGTH;
+
+		/* input under zVM needs to be converted to lower case */
+		if (is_zvm())
+			for (i = 0; i < count; i++)
+				temp_area[i] = ebc_tolower(temp_area[i]);
+		value = ebcstrtoul((char *)temp_area, &endptr, 10);
+
+		if ((endptr != temp_area) && (value < BOOT_MENU_ENTRIES - 1) &&
+		    (configs[value] != 0)) {
+			/* valid config found - finish */
+			break;
+		} else {
+			/* no valid config retry */
+			printf(msg_econfig);
+			count = 0;
+		}
+	}
+
+	if (temp_area + count > endptr)
+		memcpy((void *)COMMAND_LINE_EXTRA, endptr,
+		       (temp_area + count - endptr));
+out_free_page:
+	free_page((unsigned long) temp_area);
+	return value;
+}
+
+static int menu_list(void)
+{
+	uint16_t *configs = __stage2_params.config;
+	char *name;
+	int i;
+
+	for (i = 0; i < BOOT_MENU_ENTRIES; i++) {
+		if (configs[i] == 0)
+			continue;
+		name = configs[i] + ((void *)&__stage2_params);
+		printf("%s\n", name);
+		if (i == 0)
+			printf("\n");
+	}
+
+	return 0;
+}
+
+/*
+ * Interpret loadparm
+ *
+ * Parameter
+ *     value - to store configuration number
+ *
+ * Return
+ *     0 - found number to boot, stored in value
+ *     1 - print prompt
+ *     2 - nothing found
+ */
+static int menu_param(unsigned long *value)
+{
+	char loadparm[PARAM_SIZE];
+	char *endptr;
+	int i;
+
+	if (!sclp_param(loadparm))
+		*value = ebcstrtoul(loadparm, &endptr, 10);
+
+	/* got number, done */
+	if (endptr != loadparm)
+		return NUMBER_FOUND;
+
+	/* no number, check for keyword */
+	i = 0;
+	/* skip leading whitespaces */
+	while (ebc_isspace(loadparm[i]) && (i < PARAM_SIZE))
+		i++;
+
+	if (!strncmp(&loadparm[i], "PROMPT", 6)) {
+		*value = 0;
+		return PRINT_PROMPT;
+	}
+
+	return NOTHING_FOUND;
+}
+
+int menu(void)
+{
+	uint16_t *configs = __stage2_params.config;
+	unsigned long value = 0;
+	char *cmd_line_extra;
+	char endstring[15];
+	int rc;
+
+	cmd_line_extra = (char *)COMMAND_LINE_EXTRA;
+	rc = sclp_setup(SCLP_INIT);
+	if (rc)
+		/* sclp setup failed boot default */
+		goto boot;
+
+	memset(cmd_line_extra, 0, COMMAND_LINE_SIZE);
+	rc = menu_param(&value);
+	if (rc == 0) {
+		/* got number from loadparm, boot it */
+		goto boot;
+	} else if (rc == 1 && value == 0) {
+		/* keyword "prompt", show menu */
+	} else if (__stage2_params.flag == 0) {
+		/* menu disabled, boot default */
+		value = 0;
+		goto boot;
+	}
+
+	/* print banner */
+	printf("%s\n", ((void *)&__stage2_params) + __stage2_params.banner);
+
+	/* print config list */
+	menu_list();
+
+	if (is_zvm())
+		printf("Note: VM users please use '#cp vi vmsg <input>'\n");
+
+	value = menu_read();
+
+	/* sanity - value too big */
+	if (value > BOOT_MENU_ENTRIES)
+		panic(EINTERNAL, "%s", msg_econfig);
+
+boot:
+	/* sanity - config entry not valid */
+	if (configs[value] == 0)
+		panic(EINTERNAL, "%s", msg_econfig);
+
+	printf("Booting %s\n",
+	       (char *)(configs[value] +
+			(void *)&__stage2_params + TEXT_OFFSET));
+
+	/* append 'BOOT_IMAGE=<num>' to parmline */
+	sprintf(endstring, " BOOT_IMAGE=%u", value);
+	if ((strlen(cmd_line_extra) + strlen(endstring)) < COMMAND_LINE_SIZE)
+		strcat(cmd_line_extra, endstring);
+
+	sclp_setup(SCLP_DISABLE);
+
+	return value;
+}
--- /dev/null
+++ b/zipl/boot/menu.h
@@ -0,0 +1,41 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Bootmenu Subroutines
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include "stage2.h"
+
+/* address of extra command line */
+#define COMMAND_LINE_EXTRA	        (0xA000-0x400)
+
+/* max command line length */
+#define COMMAND_LINE_SIZE	        896
+#define BOOT_MENU_ENTRIES		63
+#define LINE_LENGTH                     80
+#define PARAM_SIZE                      8
+#define TEXT_OFFSET                     4
+
+#define NUMBER_FOUND                    0
+#define PRINT_PROMPT                    1
+#define NOTHING_FOUND                   2
+
+struct boot_stage2_params {
+	uint16_t flag;
+	uint16_t timeout;
+	uint16_t banner;
+	uint16_t config[BOOT_MENU_ENTRIES];
+	uint64_t config_kdump;
+} __packed;
+
+extern struct boot_stage2_params __stage2_params;
+
+int menu();
+
+#endif /* MENU_H */
--- /dev/null
+++ b/zipl/boot/s390.h
@@ -0,0 +1,374 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * System z specific functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ *            Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+#ifndef S390_H
+#define S390_H
+
+#include "libc.h"
+#include "../../include/zt_common.h"
+
+#define __packed __attribute__((packed))
+#define __aligned(x) __attribute__((aligned(x)))
+#define __pa32(x) ((uint32_t)(unsigned long)(x))
+#define __pa(x) ((unsigned long)(x))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+/*
+ * Helper macro for exception table entries
+ */
+#define EX_TABLE(_fault, _target)	\
+	".section .ex_table,\"a\"\n"	\
+	".align	4\n"			\
+	".long	(" #_fault ") - .\n"	\
+	".long	(" #_target ") - .\n"	\
+	".previous\n"
+
+struct psw_t {
+	uint64_t mask;
+	uint64_t addr;
+} __aligned(8);
+
+struct _lowcore {
+	uint8_t	pad_0x0000[0x0014-0x0000];	/* 0x0000 */
+	uint32_t	ipl_parmblock_ptr;		/* 0x0014 */
+	uint8_t	pad_0x0018[0x0080-0x0018];	/* 0x0018 */
+	uint32_t	ext_params;			/* 0x0080 */
+	uint16_t	ext_cpu_addr;			/* 0x0084 */
+	uint16_t	ext_int_code;			/* 0x0086 */
+	uint16_t	svc_ilc;			/* 0x0088 */
+	uint16_t	svc_code;			/* 0x008a */
+	uint16_t	pgm_ilc;			/* 0x008c */
+	uint16_t	pgm_code;			/* 0x008e */
+	uint32_t	data_exc_code;			/* 0x0090 */
+	uint16_t	mon_class_num;			/* 0x0094 */
+	uint16_t	per_perc_atmid;			/* 0x0096 */
+	uint64_t	per_address;			/* 0x0098 */
+	uint8_t	exc_access_id;			/* 0x00a0 */
+	uint8_t	per_access_id;			/* 0x00a1 */
+	uint8_t	op_access_id;			/* 0x00a2 */
+	uint8_t	ar_access_id;			/* 0x00a3 */
+	uint8_t	pad_0x00a4[0x00a8-0x00a4];	/* 0x00a4 */
+	uint64_t	trans_exc_code;			/* 0x00a8 */
+	uint64_t	monitor_code;			/* 0x00b0 */
+	uint16_t	subchannel_id;			/* 0x00b8 */
+	uint16_t	subchannel_nr;			/* 0x00ba */
+	uint32_t	io_int_parm;			/* 0x00bc */
+	uint32_t	io_int_word;			/* 0x00c0 */
+	uint8_t	pad_0x00c4[0x00c8-0x00c4];	/* 0x00c4 */
+	uint32_t	stfl_fac_list;			/* 0x00c8 */
+	uint8_t	pad_0x00cc[0x00e8-0x00cc];	/* 0x00cc */
+	uint32_t	mcck_interruption_code[2];	/* 0x00e8 */
+	uint8_t	pad_0x00f0[0x00f4-0x00f0];	/* 0x00f0 */
+	uint32_t	external_damage_code;		/* 0x00f4 */
+	uint64_t	failing_storage_address;	/* 0x00f8 */
+	uint8_t	pad_0x0100[0x0110-0x0100];	/* 0x0100 */
+	uint64_t	breaking_event_addr;		/* 0x0110 */
+	uint8_t	pad_0x0118[0x0120-0x0118];	/* 0x0118 */
+	struct psw_t	restart_old_psw;		/* 0x0120 */
+	struct psw_t	external_old_psw;		/* 0x0130 */
+	struct psw_t	svc_old_psw;			/* 0x0140 */
+	struct psw_t	program_old_psw;		/* 0x0150 */
+	struct psw_t	mcck_old_psw;			/* 0x0160 */
+	struct psw_t	io_old_psw;			/* 0x0170 */
+	uint8_t	pad_0x0180[0x01a0-0x0180];	/* 0x0180 */
+	struct psw_t	restart_psw;			/* 0x01a0 */
+	struct psw_t	external_new_psw;		/* 0x01b0 */
+	struct psw_t	svc_new_psw;			/* 0x01c0 */
+	struct psw_t	program_new_psw;		/* 0x01d0 */
+	struct psw_t	mcck_new_psw;			/* 0x01e0 */
+	struct psw_t	io_new_psw;			/* 0x01f0 */
+
+	/* Save areas. */
+	uint64_t	save_area_sync[8];		/* 0x0200 */
+	uint64_t	save_area_async[8];		/* 0x0240 */
+	uint64_t	save_area_restart[1];		/* 0x0280 */
+	uint8_t	pad_0x0288[0x0290-0x0288];	/* 0x0288 */
+
+	/* Return psws. */
+	struct psw_t	return_psw;			/* 0x0290 */
+	struct psw_t	return_mcck_psw;		/* 0x02a0 */
+
+	/* CPU accounting and timing values. */
+	uint64_t	sync_enter_timer;		/* 0x02b0 */
+	uint64_t	async_enter_timer;		/* 0x02b8 */
+	uint64_t	mcck_enter_timer;		/* 0x02c0 */
+	uint64_t	exit_timer;			/* 0x02c8 */
+	uint64_t	user_timer;			/* 0x02d0 */
+	uint64_t	system_timer;			/* 0x02d8 */
+	uint64_t	steal_timer;			/* 0x02e0 */
+	uint64_t	last_update_timer;		/* 0x02e8 */
+	uint64_t	last_update_clock;		/* 0x02f0 */
+	uint64_t	int_clock;			/* 0x02f8 */
+	uint64_t	mcck_clock;			/* 0x0300 */
+	uint64_t	clock_comparator;		/* 0x0308 */
+
+	/* Current process. */
+	uint64_t	current_task;			/* 0x0310 */
+	uint64_t	thread_info;			/* 0x0318 */
+	uint64_t	kernel_stack;			/* 0x0320 */
+
+	/* Interrupt, panic and restart stack. */
+	uint64_t	async_stack;			/* 0x0328 */
+	uint64_t	panic_stack;			/* 0x0330 */
+	uint64_t	restart_stack;			/* 0x0338 */
+
+	/* Restart function and parameter. */
+	uint64_t	restart_fn;			/* 0x0340 */
+	uint64_t	restart_data;			/* 0x0348 */
+	uint64_t	restart_source;			/* 0x0350 */
+
+	/* Address space pointer. */
+	uint64_t	kernel_asce;			/* 0x0358 */
+	uint64_t	user_asce;			/* 0x0360 */
+	uint64_t	current_pid;			/* 0x0368 */
+
+	/* SMP info area */
+	uint32_t	cpu_nr;				/* 0x0370 */
+	uint32_t	softirq_pending;		/* 0x0374 */
+	uint64_t	percpu_offset;			/* 0x0378 */
+	uint64_t	vdso_per_cpu_data;		/* 0x0380 */
+	uint64_t	machine_flags;			/* 0x0388 */
+	uint64_t	ftrace_func;			/* 0x0390 */
+	uint64_t	gmap;				/* 0x0398 */
+	uint8_t	pad_0x03a0[0x0400-0x03a0];	/* 0x03a0 */
+
+	/* Interrupt response block. */
+	uint8_t	irb[64];			/* 0x0400 */
+
+	/* Per cpu primary space access list */
+	uint32_t	paste[16];			/* 0x0440 */
+
+	uint8_t	pad_0x0480[0x0e00-0x0480];	/* 0x0480 */
+
+	/*
+	 * 0xe00 contains the address of the IPL Parameter Information
+	 * block. Dump tools need IPIB for IPL after dump.
+	 * Note: do not change the position of any fields in 0x0e00-0x0f00
+	 */
+	uint64_t	ipib;				/* 0x0e00 */
+	uint32_t	ipib_checksum;			/* 0x0e08 */
+	uint64_t	vmcore_info;			/* 0x0e0c */
+	uint8_t	pad_0x0e14[0x0e18-0x0e14];	/* 0x0e14 */
+	uint64_t	os_info;			/* 0x0e18 */
+	uint8_t	pad_0x0e20[0x0f00-0x0e20];	/* 0x0e20 */
+
+	/* Extended facility list */
+	uint64_t	stfle_fac_list[32];		/* 0x0f00 */
+	uint8_t	pad_0x1000[0x11b8-0x1000];	/* 0x1000 */
+
+	/* 64 bit extparam used for pfault/diag 250: defined by architecture */
+	uint64_t	ext_params2;			/* 0x11B8 */
+	uint8_t	pad_0x11c0[0x1200-0x11C0];	/* 0x11C0 */
+
+	/* CPU register save area: defined by architecture */
+	uint64_t	floating_pt_save_area[16];	/* 0x1200 */
+	uint64_t	gpregs_save_area[16];		/* 0x1280 */
+	struct psw_t	psw_save_area;			/* 0x1300 */
+	uint8_t	pad_0x1310[0x1318-0x1310];	/* 0x1310 */
+	uint32_t	prefixreg_save_area;		/* 0x1318 */
+	uint32_t	fpt_creg_save_area;		/* 0x131c */
+	uint8_t	pad_0x1320[0x1324-0x1320];	/* 0x1320 */
+	uint32_t	tod_progreg_save_area;		/* 0x1324 */
+	uint32_t	cpu_timer_save_area[2];		/* 0x1328 */
+	uint32_t	clock_comp_save_area[2];	/* 0x1330 */
+	uint8_t	pad_0x1338[0x1340-0x1338];	/* 0x1338 */
+	uint32_t	access_regs_save_area[16];	/* 0x1340 */
+	uint64_t	cregs_save_area[16];		/* 0x1380 */
+	uint8_t	pad_0x1400[0x1800-0x1400];	/* 0x1400 */
+
+	/* Transaction abort diagnostic block */
+	uint8_t	pgm_tdb[256];			/* 0x1800 */
+
+	/* align to the top of the prefix area */
+	uint8_t	pad_0x1900[0x2000-0x1900];	/* 0x1900 */
+} __packed;
+
+#define S390_lowcore (*((struct _lowcore *) 0))
+
+#define __LC_IPLDEV		0x0c6c
+#define __LC_OS_INFO		0x0e18
+
+#define PAGE_SIZE		4096
+
+void panic_notify(unsigned long reason);
+
+#define panic(reason, x...) \
+do { \
+	printf(x); \
+	panic_notify(reason); \
+	libc_stop(reason); \
+} while (0)
+
+#define CHUNK_READ_WRITE	0
+#define CHUNK_READ_ONLY		1
+
+static inline int tprot(unsigned long addr)
+{
+	int rc = -EFAULT;
+
+	asm volatile(
+		"       tprot   0(%1),0\n"
+		"0:     ipm     %0\n"
+		"       srl     %0,28\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (rc) : "a" (addr) : "cc");
+	return rc;
+}
+
+static inline int page_is_valid(unsigned long addr)
+{
+	int rc;
+
+	rc = tprot(addr);
+	return (rc == CHUNK_READ_WRITE) || (rc == CHUNK_READ_ONLY);
+}
+
+static inline uint32_t csum_partial(const void *buf, int len, uint32_t sum)
+{
+	register unsigned long reg2 asm("2") = (unsigned long) buf;
+	register unsigned long reg3 asm("3") = (unsigned long) len;
+
+	asm volatile(
+		"0:     cksm    %0,%1\n"        /* do checksum on longs */
+		"       jo      0b\n"
+		: "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
+	return sum;
+}
+
+#define __ctl_store(array, low, high) ({		    \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
+	asm volatile(					    \
+		"	stctg	%1,%2,%0\n"		    \
+		: "=Q" (*(addrtype *)(&array))		    \
+		: "i" (low), "i" (high));		    \
+})
+
+#define __ctl_load(array, low, high) ({			    \
+	typedef struct { char _[sizeof(array)]; } addrtype; \
+	asm volatile(					    \
+		"	lctlg	%1,%2,%0\n"			\
+		: : "Q" (*(addrtype *)(&array)),		\
+		  "i" (low), "i" (high));			\
+})
+
+/*
+ * DIAG 308 support
+ */
+enum diag308_subcode {
+	DIAG308_REL_HSA = 2,
+	DIAG308_IPL	= 3,
+	DIAG308_DUMP	= 4,
+	DIAG308_SET	= 5,
+	DIAG308_STORE	= 6,
+};
+
+static inline int diag308(unsigned long subcode, void *addr)
+{
+	register unsigned long _addr asm("0") = (unsigned long) addr;
+	register unsigned long _rc asm("1") = 0;
+
+	asm volatile(
+		"	diag	%0,%2,0x308\n"
+		"0:\n"
+		: "+d" (_addr), "+d" (_rc)
+		: "d" (subcode) : "cc", "memory");
+	return _rc;
+}
+
+/*
+ * Signal Processor
+ */
+#define SIGP_STOP_AND_STORE_STATUS	9
+
+#define SIGP_CC_ORDER_CODE_ACCEPTED	0
+#define SIGP_CC_BUSY			2
+
+static inline int sigp(uint16_t addr, uint8_t order, uint32_t parm,
+		       uint32_t *status)
+{
+	register unsigned int reg1 asm ("1") = parm;
+	int cc;
+
+	asm volatile(
+		"	sigp	%1,%2,0(%3)\n"
+		"	ipm	%0\n"
+		"	srl	%0,28\n"
+		: "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc");
+	if (status && cc == 1)
+		*status = reg1;
+	return cc;
+}
+
+/*
+ * Store CPU address
+ */
+static inline unsigned short stap(void)
+{
+	unsigned short cpu_address;
+
+	asm volatile("stap %0" : "=m" (cpu_address));
+	return cpu_address;
+}
+
+/*
+ * Program the clock comparator
+ */
+static inline void set_clock_comparator(uint64_t time)
+{
+	asm volatile("sckc %0" : : "Q" (time));
+}
+
+/*
+ * Program the CPU timer
+ */
+static inline void set_cpu_timer(uint64_t timer)
+{
+	asm volatile("spt %0" : : "Q" (timer));
+}
+
+/*
+ * Get current time (store clock)
+ */
+static inline unsigned long long get_tod_clock(void)
+{
+	unsigned long long clk;
+
+	asm volatile("stck %0" : "=Q" (clk) : : "cc");
+	return clk;
+}
+
+/*
+ * Get ID of current CPU
+ */
+struct cpuid {
+	unsigned int version:8;
+	unsigned int ident:24;
+	unsigned int machine:16;
+	unsigned int unused:16;
+} __packed __aligned(8);
+
+static inline void get_cpu_id(struct cpuid *ptr)
+{
+	asm volatile("stidp %0" : "=Q" (*ptr));
+}
+
+/*
+ * Check if we run under z/VM
+ */
+static inline int is_zvm(void)
+{
+	struct cpuid cpuid;
+
+	get_cpu_id(&cpuid);
+	return cpuid.version == 0xff;
+}
+
+#endif /* S390_H */
--- a/zipl/boot/sclp.S
+++ /dev/null
@@ -1,675 +0,0 @@
-#
-# s390-tools/zipl/boot/sclp.S
-#   Mini SCLP driver.
-#
-# Copyright IBM Corp. 2004, 2006.
-#
-# Author(s): Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-#
-
-#ifdef USE_64BIT_SCLP
-LC_EXT_NEW_PSW		= 0x1b0			# addr of ext int handler
-PSW_SIZE                = 16
-#else
-LC_EXT_NEW_PSW		= 0x58			# addr of ext int handler
-PSW_SIZE                = 8
-#endif
-LC_EXT_INT_PARAM	= 0x80			# addr of ext int parameter
-LC_EXT_INT_CODE		= 0x86			# addr of ext int code
-
-SCCB_ADDR		= 0x8000		# addr of sccb work area
-
-SCCB_LENGTH		= 0			# offset of length field
-SCCB_RESPONSE		= 6			# offset of response field
-SCCB_DATA		= 8			# offset of data
-SCCB_PARAM		= 24			# offset of load parameter
-
-EVBUF_LENGTH		= 0			# offset of length field
-EVBUF_TYPE		= 2			# offset of type field
-EVBUF_DATA		= 6			# offset of data
-
-GDS_ID_MDSMU		= 0x1310		# vector keys and ids
-GDS_ID_CPMSU		= 0x1212
-GDS_ID_TextCmd		= 0x1320
-GDS_KEY_SelfDefTextMsg	= 0x31
-
-
-.macro sclp_base
-
-#
-# Subroutine which waits synchronously until either an external interruption
-# or a timeout occurs.
-#
-# Parameters:
-#   R2  = 0 for no timeout, non-zero for timeout in (approximated) seconds
-#
-# Returns:
-#   R2  = 0 on interrupt, 2 on timeout
-#   R3  = external interruption parameter if R2=0
-#
-
-_sclp_wait_int:
-	stm    %r6,%r15,24(%r15)		# save registers
-
-	basr   %r13,0				# get base register
-.LbaseS1:
-	ahi    %r15,-96				# create stack frame
-
-	la     %r8,LC_EXT_NEW_PSW		# register int handler
-	mvc    .LoldpswS1-.LbaseS1(PSW_SIZE,%r13),0(%r8)
-	mvc    0(PSW_SIZE,%r8),.LextpswS1-.LbaseS1(%r13)
-
-	lhi    %r6,0x0200			# cr mask for ext int (cr0.54)
-	ltr    %r2,%r2
-	jz     .LsetctS1
-
-	ahi    %r6,0x0800			# cr mask for clock int (cr0.52)
-
-	stck   .LtimeS1-.LbaseS1(%r13)		# initiate timeout
-	al     %r2,.LtimeS1-.LbaseS1(%r13)
-	st     %r2,.LtimeS1-.LbaseS1(%r13)
-	sckc   .LtimeS1-.LbaseS1(%r13)
-
-.LsetctS1:
-	stctl  %c0,%c0,.LctlS1-.LbaseS1(%r13)	# enable required interrupts
-	l      %r0,.LctlS1-.LbaseS1(%r13)
-	lhi    %r1,~(0x200 | 0x800)		# clear old values
-	nr     %r1,%r0
-	or     %r1,%r6				# set new value
-	st     %r1,.LctlS1-.LbaseS1(%r13)
-	lctl   %c0,%c0,.LctlS1-.LbaseS1(%r13)
-	st     %r0,.LctlS1-.LbaseS1(%r13)
-	lhi    %r2,2				# return code for timeout
-
-.LloopS1:
-#ifdef USE_64BIT_SCLP
-	lpswe  .LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
-#else
-	lpsw   .LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
-#endif
-
-.LwaitS1:
-	lh     %r7,LC_EXT_INT_CODE
-	chi    %r7,0x1004			# timeout?
-	je     .LtimeoutS1
-	chi    %r7,0x2401			# service int?
-	jne    .LloopS1
-
-	sr     %r2,%r2
-	l      %r3,LC_EXT_INT_PARAM
-
-.LtimeoutS1:
-	lctl   %c0,%c0,.LctlS1-.LbaseS1(%r13)	# restore interrupt setting
-
-	# restore old handler
-	mvc    0(PSW_SIZE,%r8),.LoldpswS1-.LbaseS1(%r13)
-
-	lm     %r6,%r15,120(%r15)		# restore registers
-
-	br     %r14				# return to caller
-
-	.align 8
-
-#ifdef USE_64BIT_SCLP
-.LoldpswS1:
-	.long  0, 0, 0, 0			# old ext int PSW
-.LextpswS1:
-	.long  0x00000001, 0x80000000, 0x00000000, 0x00000000+.LwaitS1	# PSW to handle ext int
-.LwaitpswS1:
-	.long  0x01020001, 0x80000000, 0x00000000, 0x00000000+.LloopS1	# PSW to wait for ext int
-
-#else
-.LoldpswS1:
-	.long  0, 0				# old ext int PSW
-.LextpswS1:
-	.long  0x00080000, 0x80000000+.LwaitS1	# PSW to handle ext int
-.LwaitpswS1:
-	.long  0x010a0000, 0x00000000+.LloopS1	# PSW to wait for ext int
-
-#endif
-.LtimeS1:
-	.quad  0				# current time
-.LctlS1:
-	.long  0				# CT0 contents
-
-
-#
-# Subroutine to synchronously issue a service call.
-#
-# Parameters:
-#   R2  = command word
-#   R3  = sccb address
-#
-# Returns:
-#   R2  = 0 on success, 1 on failure
-#   R3  = sccb response code if R2 = 0
-#
-
-_sclp_servc:
-	stm    %r6,%r15,24(%r15)		# save registers
-	ahi    %r15,-96				# create stack frame
-
-	lr     %r6,%r2				# save command word
-	lr     %r7,%r3				# save sccb address
-
-.LretryS2:
-	lhi    %r2,1				# error return code
-
-	.insn  rre,0xb2200000,%r6,%r7		# servc
-	brc    1,.LendS2			# exit if not operational
-	brc    8,.LnotbusyS2			# go on if not busy
-
-	sr     %r2,%r2				# wait until no longer busy
-	bras   %r14,_sclp_wait_int
-
-	j      .LretryS2			# retry
-
-.LnotbusyS2:
-	sr     %r2,%r2				# wait until result
-	bras   %r14,_sclp_wait_int
-
-	sr     %r2,%r2
-	lh     %r3,SCCB_RESPONSE(%r7)
-
-.LendS2:
-	lm     %r6,%r15,120(%r15)		# restore registers
-
-	br     %r14
-
-
-#
-# Subroutine to set up the SCLP interface.
-#
-# Parameters:
-#   R2  = 0 to activate, non-zero to deactivate
-#
-# Returns:
-#   R2  = 0 on success, non-zero on failure
-#
-
-_sclp_setup:
-	entry_linkage
-
-	basr   %r13,0				# get base register
-.LbaseS3:
-
-	l      %r6,.LsccbS0-.LbaseS3(%r13)	# prepare init mask sccb
-	mvc    0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
-
-	ltr    %r2,%r2				# initialization?
-	jz     .LdoinitS3			# go ahead
-
-	# clear masks
-	xc     .LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
-
-.LdoinitS3:
-	l      %r2,.LwritemaskS3-.LbaseS3(%r13)	# get command word
-	lr     %r3,%r6				# get sccb address
-	bras   %r14,_sclp_servc			# issue service call
-
-	ltr    %r2,%r2				# servc successful?
-	jnz    .LerrorS3
-
-	chi    %r3,0x20				# write mask successful?
-	jne    .LerrorS3
-
-	# check masks
-	la     %r2,.LinitmaskS3-.LinitsccbS3(%r6)
-
-	l      %r1,0(%r2)			# receive mask ok?
-	n      %r1,12(%r2)
-	cl     %r1,0(%r2)
-	jne    .LerrorS3
-
-	l      %r1,4(%r2)			# send mask ok?
-	n      %r1,8(%r2)
-	cl     %r1,4(%r2)
-	sr     %r2,%r2
-	je     .LendS3
-
-.LerrorS3:
-	lhi    %r2,1				# error return code
-
-.LendS3:
-	exit_linkage
-
-	br     %r14
-
-.LwritemaskS3:
-	.long  0x00780005			# SCLP command for write mask
-.LinitsccbS3:
-	.word  .LinitendS3-.LinitsccbS3
-	.byte  0,0,0,0
-	.word  0
-	.word  0
-	.word  4
-.LinitmaskS3:
-	.long  0x80000000
-	.long  0x40000000
-	.long  0
-	.long  0
-.LinitendS3:
-
-.endm # sclp_base
-
-.macro sclp_print
-
-#
-# Subroutine which prints a given text to the SCLP console.
-#
-# Parameters:
-#   R2  = address of nil-terminated EBCDIC text
-#
-# Returns:
-#   R2  = 0 on success, 1 on failure
-#
-
-_sclp_print:
-	entry_linkage
-
-	basr   %r13,0				# get base register
-.LbaseS4:
-
-	l      %r8,.LsccbS0-.LbaseS4(%r13)	# prepare write data sccb
-	mvc    0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
-
-	la     %r7,.LmtoS4-.LwritesccbS4(%r8)	# current mto addr
-	sr     %r0,%r0
-.LinitmtoS4:
-	# initialize mto
-	mvc    0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
-	lhi    %r6,.LmtoendS4-.LmtoS4		# current mto length
-
-.LloopS4:
-	ic     %r0,0(%r2)			# get character
-	ahi    %r2,1
-
-	ltr    %r0,%r0				# end of string?
-	jz     .LfinalizemtoS4
-
-	chi    %r0,0x15				# end of line (NL)?
-	jz     .LfinalizemtoS4
-
-	stc    %r0,0(%r6,%r7)			# copy to mto
-	ahi    %r6,1
-	j      .LloopS4
-
-.LfinalizemtoS4:
-	sth    %r6,0(%r7)			# update mto length
-
-	lh     %r9,.LmdbS4-.LwritesccbS4(%r8)	# update mdb length
-	ar     %r9,%r6
-	sth    %r9,.LmdbS4-.LwritesccbS4(%r8)
-
-	lh     %r9,.LevbufS4-.LwritesccbS4(%r8)	# update evbuf length
-	ar     %r9,%r6
-	sth    %r9,.LevbufS4-.LwritesccbS4(%r8)
-
-	lh     %r9,0(%r8)			# update sccb length
-	ar     %r9,%r6
-	sth    %r9,0(%r8)
-
-	ar     %r7,%r6				# update current mto adress
-	ltr    %r0,%r0				# more characters?
-	jnz    .LinitmtoS4
-
-	l      %r2,.LwritedataS4-.LbaseS4(%r13)	# write data
-	lr     %r3,%r8
-	bras   %r14,_sclp_servc
-
-	ltr    %r2,%r2				# servc successful?
-	jnz    .LendS4
-
-	chi    %r3,0x20				# write data successful?
-	je     .LendS4
-
-	lhi    %r2,1				# error return code
-
-.LendS4:
-	exit_linkage
-
-	br     %r14
-
-.LwritedataS4:
-	.long  0x00760005			# SCLP command for write data
-.LwritesccbS4:
-	# sccb
-	.word  .LmtoS4-.LwritesccbS4
-	.byte  0
-	.byte  0,0,0
-	.word  0
-
-	# evbuf
-.LevbufS4:
-	.word  .LmtoS4-.LevbufS4
-	.byte  0x02
-	.byte  0
-	.word  0
-
-.LmdbS4:
-	# mdb
-	.word  .LmtoS4-.LmdbS4
-	.word  1
-	.long  0xd4c4c240
-	.long  1
-
-	# go
-.LgoS4:
-	.word  .LmtoS4-.LgoS4
-	.word  1
-	.long  0
-	.byte  0,0,0,0,0,0,0,0
-	.byte  0,0,0
-	.byte  0
-	.byte  0,0,0,0,0,0,0
-	.byte  0
-	.word  0
-	.byte  0,0,0,0,0,0,0,0,0,0
-	.byte  0,0,0,0,0,0,0,0
-	.byte  0,0,0,0,0,0,0,0
-
-.LmtoS4:
-	.word  .LmtoendS4-.LmtoS4
-	.word  4
-	.word  0x1000
-	.byte  0
-	.byte  0,0,0
-.LmtoendS4:
-
-.endm # sclp_print
-
-.macro sclp_read
-
-#
-# Subroutine which reads text from the SCLP console.
-#
-# Parameters:
-#   R2  = 0 for no timeout, non-zero for timeout in (approximated) seconds
-#   R3  = destination address for input
-#
-# Returns:
-#   R2  = 0 on input, 1 on failure, 2 on timeout
-#   R3  = length of input data
-#
-
-_sclp_read:
-	stm    %r6,%r15,24(%r15)		# save registers
-
-	basr   %r13,0				# get base register
-.LbaseS5:
-	ahi    %r15,-96				# create stack frame
-
-	l      %r9,.LsccbS0-.LbaseS5(%r13)	# get sccb address
-
-	lr     %r10,%r2				# save timeout
-	lr     %r11,%r3				# save destination address
-
-.LretryS5:
-	# prepare sccb
-	mvc    0(.LreadevbufS5-.LreadsccbS5,%r9),.LreadsccbS5-.LbaseS5(%r13)
-
-	l      %r2,.LreaddataS5-.LbaseS5(%r13)	# read data
-	lr     %r3,%r9
-	bras   %r14,_sclp_servc
-
-	ltr    %r2,%r2				# servc successful?
-	jnz    .LendS5
-
-	chi    %r3,0x20				# read event data successful?
-	je     .LprocessS5			# process input
-
-	chi    %r3,0x60f0			# no buffer?
-	lhi    %r2,1
-	jne    .LendS5				# anything else is an error
-
-	lr     %r2,%r10				# wait for input or timeout
-	bras   %r14,_sclp_wait_int
-
-	ltr    %r2,%r2				# got int?
-	jz     .LretryS5
-	j      .LendS5				# just timeout
-
-.LprocessS5:
-	la     %r1,SCCB_DATA(%r9)		# get event data end address
-	ah     %r1,EVBUF_LENGTH(%r1)
-	st     %r1,.LendarrayS5-.LbaseS5(%r13)
-
-	la     %r9,EVBUF_DATA+SCCB_DATA(%r9)	# get event data address
-
-	lr     %r3,%r11				# current dest address
-	sr     %r8,%r8				# current level
-
-.LloopS5:
-	chi    %r8,-4				# at end of buffer?
-	je     .LsuccessS5
-
-	# at end of vector?
-	c      %r9,.LendarrayS5-.LbaseS5(%r8,%r13)
-	jl     .LcontinueS5
-
-	ahi    %r8,-4				# go up one level
-	j      .LloopS5
-.LcontinueS5:
-
-	chi    %r8,8				# check for subvector
-	jh     .LsubvectorS5
-
-	lh     %r6,0(%r9)			# get vector length
-	lh     %r0,2(%r9)			# get vector ID
-	lhi    %r7,4				# vector header is 4 bytes
-
-	j      .LprocessvecS5
-
-.LsubvectorS5:
-	sr     %r6,%r6				# get subvector length
-	ic     %r6,0(%r9)
-
-	sr     %r0,%r0				# get subvector key
-	ic     %r0,1(%r9)
-
-	lhi    %r7,2				# subvector header is 2 bytes
-
-.LprocessvecS5:
-	cr     %r6,%r7				# check for empty vector?
-	je     .LendprocessS5
-
-	# check for matching vector
-	c      %r0,.LkeyarrayS5-.LbaseS5(%r8,%r13)
-	jne    .LendprocessS5
-
-	chi    %r8,16				# check for text vector
-	je     .LcopytextS5
-
-	ahi    %r8,4				# go down one level
-
-	lr     %r0,%r9				# get end address for vector
-	ar     %r0,%r6
-	st     %r0,.LendarrayS5-.LbaseS5(%r8,%r13)
-
-	ar     %r9,%r7				# skip header
-	j      .LloopS5
-
-.LcopytextS5:
-	sr     %r6,%r7				# get length without header
-	ar     %r9,%r7				# get addr after header
-	sr     %r0,%r0
-
-.LcopyloopS5:
-	ic     %r0,0(%r9)			# copy text to dest
-	stc    %r0,0(%r3)
-
-	ahi    %r9,1
-	ahi    %r3,1
-	brct   %r6,.LcopyloopS5
-
-.LendprocessS5:
-	ar     %r9,%r6				# continue with next vector
-	j      .LloopS5
-
-.LsuccessS5:
-	sr     %r2,%r2
-	sr     %r3,%r11
-
-.LendS5:
-	lm     %r6,%r15,120(%r15)		# restore registers
-
-	br     %r14
-
-.LreaddataS5:
-	.long  0x00770005			# SCLP command for read data
-.LendarrayS5:
-	.long  0,0,0,0,0			# end addr array for read
-.LkeyarrayS5:
-	.long  GDS_ID_MDSMU			# vector ID/key array for read
-	.long  GDS_ID_CPMSU
-	.long  GDS_ID_TextCmd
-	.long  GDS_KEY_SelfDefTextMsg
-	.long  0x30
-.LreadsccbS5:
-	.word  0x1000
-	.byte  0
-	.byte  0,0,0
-	.word  0
-.LreadevbufS5:
-
-.endm # sclp_read
-
-.macro sclp_read_info
-
-#
-# Subroutine to perform sclp read info.
-#
-# Parameters:
-#   none
-#
-# Returns:
-#   R2  = address of sccb on success, 0 on failure
-#
-
-_sclp_read_info:
-	entry_linkage
-
-	basr   %r13,0				# get base register
-.LbaseS6:
-
-	lr     %r8,%r2				# save dest address
-	l      %r6,.LsccbS0-.LbaseS6(%r13)	# get sccb address
-
-	# prepare sccb
-	mvc    0(.LinfosccbendS6-.LinfosccbS6,%r6),.LinfosccbS6-.LbaseS6(%r13)
-
-	la     %r7,.LreadinfoS6-.LbaseS6(%r13)
-.LretryS6:
-	l      %r2,0(%r7)			# get command word
-	ltr    %r2,%r2
-	jz     .LerrorS6
-
-	lr     %r3,%r6				# get sccb address
-	bras   %r14,_sclp_servc
-
-	ltr    %r2,%r2				# servc successful?
-	jnz    .LerrorS6
-
-	chi    %r3,0x10				# read info successful?
-	je     .LgotinfoS6
-
-	ahi    %r7,4				# next try
-	j      .LretryS6
-
-.LgotinfoS6:
-	lr     %r2,%r6
-	j      .LendS6
-
-.LerrorS6:
-	lhi    %r2,0				# failure
-
-.LendS6:
-	exit_linkage
-
-	br     %r14
-
-.LreadinfoS6:
-	.long  0x00120001
-	.long  0x00020001
-	.long  0
-.LinfosccbS6:
-	.word  0x1000
-	.byte  0
-	.byte  0,0
-	.byte  0
-	.word  0
-.LinfosccbendS6:
-
-	# Global constants
-.LsccbS0:
-	.long  SCCB_ADDR
-
-.endm # sclp_read_info
-
-.macro sclp_param
-
-#
-# Subroutine to read load parameter.
-#
-# Parameters:
-#   R2  = destination address for load parameter (8 bytes)
-#
-# Returns:
-#   R2  = 0 on success, 1 on failure
-#
-
-_sclp_param:
-	stm    %r6,%r15,24(%r15)                # save registers
-
-	basr   %r13,0                           # get base register
-.LbaseS7:
-	ahi    %r15,-96                         # create stack frame
-
-	lr     %r8,%r2                          # save dest address
-	bras   %r14,_sclp_read_info
-	chi    %r2,0
-	je     .LerrorS7
-
-	mvc    0(8,%r8),SCCB_PARAM(%r2)         # copy parameter to dest address
-	sr     %r2,%r2
-	j      .LendS7
-.LerrorS7:
-	lhi    %r2,1                            # failure
-.LendS7:
-	lm     %r6,%r15,120(%r15)               # restore registers
-
-	br     %r14
-
-.endm # sclp_param
-
-.macro entry_linkage
-
-#
-# sclp subroutines called by dump tools operating in 64-bit mode need
-# to set bits 0-31 of working registers to zero. Otherwise the sclp code,
-# which was originally designed to operate in 31-bit mode, might fail.
-# Depending on 31 or 64-bit mode this entry linkage
-# - saves the caller's registers r6-r15 with stm/stmg
-# - nulls the stack frame and loads working registers r6-r13 with 0
-
-#ifdef USE_64BIT_SCLP
-	stmg   %r6,%r15,48(%r15)                # save registers
-	ahi    %r15,-200                        # create stack frame
-	xc     0(200,%r15),0(%r15)              # init stack frame with 0
-	lmg    %r6,%r13,0(%r15)                 # zero work registers
-#else
-	stm    %r6,%r15,24(%r15)                # save registers
-	ahi    %r15,-96                         # create stack frame
-#endif
-
-.endm entry_linkage
-
-.macro exit_linkage
-
-#ifdef USE_64BIT_SCLP
-	lmg    %r6,%r15,248(%r15)               # restore registers
-#else
-	lm     %r6,%r15,120(%r15)               # restore registers
-#endif
-
-.endm exit_linkage
--- /dev/null
+++ b/zipl/boot/sclp.c
@@ -0,0 +1,361 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Functions for console input and output.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "error.h"
+#include "sclp.h"
+#include "s390.h"
+
+/* Perform service call. Return 0 on success, non-zero otherwise. */
+static int sclp_service_call(unsigned int command, void *sccb)
+{
+	int cc;
+
+	asm volatile(
+		"       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
+		"       ipm     %0\n"
+		"       srl     %0,28"
+		: "=&d" (cc)
+		: "d" (command), "a" (sccb)
+		: "cc", "memory");
+	if (cc == 3)
+		return 3;
+	if (cc == 2)
+		return 2;
+	return 0;
+}
+
+static inline int wait(void)
+{
+	do {
+		load_wait_psw(0x0102000180000000ULL, &S390_lowcore.external_new_psw);
+		if (S390_lowcore.ext_int_code == 0x1004)
+			return ETIMEOUT;
+	} while (S390_lowcore.ext_int_code != 0x2401);
+
+	return 0;
+}
+
+int sclp_wait_for_int(unsigned long long timeout)
+{
+	unsigned long old_ctl, ctl;
+	uint64_t time;
+	int rc;
+
+	if (timeout) {
+		timeout <<= 32;
+		time = get_tod_clock();
+		time += timeout;
+		set_clock_comparator(time);
+	}
+
+	/* get control register 0 */
+	__ctl_store(old_ctl, 0, 0);
+
+	ctl = old_ctl;
+	/* set new mask */
+	ctl |= CTL_SERVICE_SIGNAL;
+	if (timeout)
+		ctl |= CTL_CLOCK_COMPARATOR;
+	else
+		ctl &= ~CTL_CLOCK_COMPARATOR;
+	/* write control register 0 */
+	__ctl_load(ctl, 0, 0);
+
+	rc = wait();
+
+	/* restore old control register 0 */
+	__ctl_load(old_ctl, 0, 0);
+
+	return rc;
+}
+
+int start_sclp(unsigned int cmd, void *sccb)
+{
+	int rc;
+
+	while (1) {
+		rc = sclp_service_call(cmd, sccb);
+		if (rc == 3)
+			return 1;
+
+		if (rc == 2)
+			sclp_wait_for_int(0);
+		else
+			break;
+	}
+	sclp_wait_for_int(0);
+	return 0;
+}
+
+static int mask_is_set(sccb_mask_t mask_to_set, sccb_mask_t mask_set)
+{
+	return (mask_to_set & mask_set) == mask_to_set;
+}
+
+int sclp_setup(int initialise)
+{
+	struct init_sccb *sccb;
+	unsigned int cmd;
+	int rc;
+
+	sccb = (void *)get_zeroed_page();
+	sccb->header.length = sizeof(struct init_sccb);
+	sccb->mask_length = 4;
+
+	switch (initialise) {
+	case SCLP_INIT:
+		sccb->receive_mask = 0x80000000;
+		sccb->send_mask = 0x40000000;
+		break;
+	case SCLP_DISABLE:
+		sccb->receive_mask = 0x0;
+		sccb->send_mask = 0x0;
+		break;
+	case SCLP_HSA_INIT:
+		sccb->receive_mask = 0x0;
+		sccb->send_mask = 0x40000010;
+		break;
+	case SCLP_HSA_INIT_ASYNC:
+		sccb->receive_mask = 0x00000010;
+		sccb->send_mask = 0x40000010;
+		break;
+	}
+
+	cmd = SCLP_CMD_WRITE_MASK;
+	rc = start_sclp(cmd, sccb);
+	if (rc || sccb->header.response_code != 0x20) {
+		rc = 1;
+		goto out_free_page;
+	}
+
+	if (!mask_is_set(sccb->send_mask, sccb->sclp_send_mask) ||
+	    !mask_is_set(sccb->receive_mask, sccb->sclp_receive_mask)) {
+		rc = 1;
+		goto out_free_page;
+	}
+	rc = 0;
+out_free_page:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+int sclp_print(char *buffer)
+{
+	struct write_sccb *sccb;
+	struct mto *mto;
+	char *data;
+	unsigned int cmd;
+	int rc, i = 0;
+
+	sccb = (void *)get_zeroed_page();
+	mto = (void *)((char *)sccb) + sizeof(struct write_sccb);
+	data = (char *)mto + sizeof(struct mto);
+	sccb->header.length = sizeof(struct write_sccb);
+	sccb->msg_buf.header.length =  sizeof(struct msg_buf);
+	sccb->msg_buf.header.type = 0x02;
+	sccb->msg_buf.mdb.header.length = sizeof(struct mdb);
+	sccb->msg_buf.mdb.header.type = 1;
+	sccb->msg_buf.mdb.header.tag = EBC_MDB;
+	sccb->msg_buf.mdb.header.revision_code = 1;
+	sccb->msg_buf.mdb.go.length = sizeof(struct go);
+	sccb->msg_buf.mdb.go.type = 1;
+
+	while (buffer[i] != 0) {
+		memset(mto, 0, sizeof(struct mto));
+		mto->length = sizeof(struct mto);
+		mto->type = 4;
+		mto->line_type_flags = 0x1000;
+
+		/*
+		 * while not end of string and not end of line
+		 * copy characterwise
+		 */
+		while (buffer[i] != 0 && buffer[i] != 0x15) {
+			*data = buffer[i];
+			mto->length++;
+			data++;
+			i++;
+		}
+
+		/* update lengths */
+		sccb->msg_buf.mdb.header.length += mto->length;
+		sccb->msg_buf.header.length +=  mto->length;
+		sccb->header.length +=  mto->length;
+
+		/* if another line is remaining build a new mto */
+		if (buffer[i] != 0) {
+			mto = (struct mto *)data;
+			data = (char *)mto + sizeof(struct mto);
+			i++;
+		}
+	}
+
+	/* SCLP command for write data */
+	cmd = SCLP_CMD_WRITE_DATA;
+	rc = start_sclp(cmd, sccb);
+	if (rc || sccb->header.response_code != 0x20) {
+		rc = 1;
+		goto out_free_page;
+	}
+	rc = 0;
+out_free_page:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+int sclp_read_info(struct read_info_sccb *sccb)
+{
+	unsigned int cmd;
+	int rc;
+
+	sccb->header.length = sizeof(struct read_info_sccb);
+	cmd = SCLP_CMD_READ_INFO;
+
+	rc = start_sclp(cmd, sccb);
+
+	if (rc)
+		return 1;
+
+	if (sccb->header.response_code != 0x10) {
+		cmd = SCLP_CMD_READ_INFO2;
+		rc = start_sclp(cmd, sccb);
+	}
+
+	if (rc || sccb->header.response_code != 0x10)
+		return 2;
+
+	return 0;
+}
+
+int sclp_param(char *loadparm)
+{
+	struct read_info_sccb *sccb;
+	int rc;
+
+	sccb = (void *)get_zeroed_page();
+	rc = sclp_read_info(sccb);
+
+	if (rc == 0)
+		memcpy(loadparm, sccb->loadparm, 8);
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+static struct gds_vector *sclp_find_gds_vector(void *start, void *end, uint16_t id)
+{
+	struct gds_vector *v;
+
+	for (v = start; (void *)v < end; v = (void *)v + v->length)
+		if (v->gds_id == id)
+			return v;
+	return NULL;
+}
+
+static struct gds_subvector *sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
+{
+	void *end;
+
+	end = (void *)sv + sv->length;
+	for (sv = sv + 1; (void *)sv < end; sv = (void *)sv + sv->length)
+		if (sv->key == 0x30)
+			return sv;
+
+	return NULL;
+}
+
+static struct gds_subvector *sclp_eval_textcmd(struct gds_vector *v)
+{
+	struct gds_subvector *sv;
+	void *end;
+
+	end = (void *)v + v->length;
+	for (sv = (struct gds_subvector *)(v + 1); (void *)sv < end;
+	     sv = (void *)sv + sv->length)
+		if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
+			return sclp_eval_selfdeftextmsg(sv);
+
+	return NULL;
+}
+
+static struct gds_subvector *sclp_eval_cpmsu(struct gds_vector *v)
+{
+	void *end;
+
+	end = (void *)v + v->length;
+	for (v = v + 1; (void *)v < end; v = (void *)v + v->length)
+		if (v->gds_id == GDS_ID_TEXTCMD)
+			return sclp_eval_textcmd(v);
+
+	return NULL;
+}
+
+static struct gds_subvector *sclp_eval_mdsmu(struct gds_vector *v)
+{
+	v = sclp_find_gds_vector(v + 1, (void *)v + v->length, GDS_ID_CPMSU);
+	if (v)
+		return sclp_eval_cpmsu(v);
+
+	return NULL;
+}
+
+int sclp_read(unsigned long timeout, void *target, int *count)
+{
+	struct read_sccb *sccb;
+	struct evbuf_header *evbuf;
+	struct gds_subvector *sv;
+	struct gds_vector *v;
+	unsigned int cmd;
+	int rc;
+
+	sccb = (void *)get_zeroed_page();
+	evbuf = (struct evbuf_header *)sccb->data;
+retry:
+	memset(sccb, 0, sizeof(struct read_sccb));
+	sccb->header.length = 0x1000;
+
+	cmd = SCLP_CMD_READ_DATA;
+	rc = start_sclp(cmd, sccb);
+	if (rc) {
+		rc = 1;
+		goto out_free_page;
+	}
+
+	if (sccb->header.response_code == 0x20) {
+		v = sclp_find_gds_vector((void *)evbuf + sizeof(*evbuf),
+					 (void *)evbuf + evbuf->length,
+					 GDS_ID_MDSMU);
+		if (!v) {
+			rc = -EIO;
+			goto out_free_page;
+		}
+		sv = sclp_eval_mdsmu(v);
+		if (!sv) {
+			rc = -EIO;
+			goto out_free_page;
+		}
+		*count = sv->length - (sizeof(*sv));
+		memcpy(target, sv + 1, *count);
+		rc = 0;
+		goto out_free_page;
+	}
+
+	if (sccb->header.response_code == 0x60f0) {
+		rc = sclp_wait_for_int(timeout);
+		if (rc) {
+			rc = 2;
+			goto out_free_page;
+		}
+		goto retry;
+	} else {
+		rc = 1;
+	}
+out_free_page:
+	free_page((unsigned long) sccb);
+	return rc;
+}
--- /dev/null
+++ b/zipl/boot/sclp.h
@@ -0,0 +1,156 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Functions for console input and output.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#ifndef SCLP_H
+#define SCLP_H
+
+#include "libc.h"
+#include "s390.h"
+
+/* vector keys and ids */
+#define GDS_ID_MDSMU		0x1310
+#define GDS_ID_CPMSU		0x1212
+#define GDS_ID_TEXTCMD		0x1320
+#define GDS_KEY_SELFDEFTEXTMSG	0x31
+#define EBC_MDB                 0xd4c4c240
+
+#define SCLP_CMD_WRITE_MASK     0x00780005
+#define SCLP_CMD_WRITE_DATA     0x00760005
+#define SCLP_CMD_READ_INFO      0x00120001
+#define SCLP_CMD_READ_INFO2     0x00020001
+#define SCLP_CMD_READ_DATA      0x00770005
+
+#define PSW_EXT_MASK            0x00080000ULL
+#define PSW_EXT_ADDR            0x80000000ULL
+#define PSW_WAIT_MASK           0x010a0000ULL
+#define PSW_WAIT_ADDR           0x00000000ULL
+
+#define CTL_SERVICE_SIGNAL      0x0200
+#define CTL_CLOCK_COMPARATOR    0x0800
+
+#define SCLP_INIT               0x0
+#define SCLP_DISABLE            0x1
+#define SCLP_HSA_INIT           0x2
+#define SCLP_HSA_INIT_ASYNC     0x3
+
+typedef uint32_t sccb_mask_t;
+
+struct gds_vector {
+	uint16_t     length;
+	uint16_t     gds_id;
+} __packed;
+
+struct gds_subvector {
+	uint8_t      length;
+	uint8_t      key;
+} __packed;
+
+struct sccb_header {
+	uint16_t     length;
+	uint8_t      function_code;
+	uint8_t      control_mask[3];
+	uint16_t     response_code;
+} __packed;
+
+struct evbuf_header {
+	uint16_t     length;
+	uint8_t      type;
+	uint8_t      flags;
+	uint16_t     _reserved;
+} __packed;
+
+struct mto {
+	uint16_t length;
+	uint16_t type;
+	uint16_t line_type_flags;
+	uint8_t  alarm_control;
+	uint8_t  _reserved[3];
+} __packed;
+
+struct go {
+	uint16_t length;
+	uint16_t type;
+	uint32_t domid;
+	uint8_t  hhmmss_time[8];
+	uint8_t  th_time[3];
+	uint8_t  reserved_0;
+	uint8_t  dddyyyy_date[7];
+	uint8_t  _reserved_1;
+	uint16_t general_msg_flags;
+	uint8_t  _reserved_2[10];
+	uint8_t  originating_system_name[8];
+	uint8_t  job_guest_name[8];
+} __packed;
+
+struct mdb_header {
+	uint16_t length;
+	uint16_t type;
+	uint32_t tag;
+	uint32_t revision_code;
+} __packed;
+
+struct mdb {
+	struct mdb_header header;
+	struct go go;
+} __packed;
+
+struct msg_buf {
+	struct evbuf_header header;
+	struct mdb mdb;
+} __packed;
+
+struct write_sccb {
+	struct sccb_header header;
+	struct msg_buf msg_buf;
+} __packed;
+
+
+struct init_sccb {
+	struct sccb_header header;
+	uint16_t _reserved;
+	uint16_t mask_length;
+	sccb_mask_t receive_mask;
+	sccb_mask_t send_mask;
+	sccb_mask_t sclp_send_mask;
+	sccb_mask_t sclp_receive_mask;
+} __packed;
+
+struct read_info_sccb {
+	struct  sccb_header header;
+	uint16_t     rnmax;
+	uint8_t      rnsize;
+	uint8_t      _reserved0[24-11];
+	uint8_t      loadparm[8];
+	uint8_t      _reserved1[48-32];
+	uint64_t     facilities;
+	uint8_t      _reserved2[84-56];
+	uint8_t      fac84;
+	uint8_t      fac85;
+	uint8_t      _reserved3[91-86];
+	uint8_t      flags;
+	uint8_t      _reserved4[100-92];
+	uint32_t     rnsize2;
+	uint64_t     rnmax2;
+	uint8_t      _reserved5[4096-112];
+} __packed __aligned(PAGE_SIZE);
+
+struct read_sccb {
+	struct  sccb_header header;
+	uint8_t      data[4096-8];
+} __packed __aligned(PAGE_SIZE);
+
+int start_sclp(unsigned int, void *);
+int sclp_setup(int);
+int sclp_print(char *);
+int sclp_param(char *);
+int sclp_read(unsigned long, void *, int *);
+int sclp_read_info(struct read_info_sccb *sccb);
+int sclp_wait_for_int(unsigned long long);
+
+#endif /* SCLP_H */
--- /dev/null
+++ b/zipl/boot/sclp_stage3.c
@@ -0,0 +1,163 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Functions for console input and output.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "sclp.h"
+#include "sclp_stage3.h"
+
+#define EQ_STORE_DATA	0x0
+#define EQ_SIZE		0x1
+#define DI_FCP_DUMP	0x0
+#define EVTYP_SDIAS	0x1c
+
+/* Global flag for synchrous(1) or asynchronus(0) hsa copy */
+static int hsa_sync_mode = 1;
+
+static int sclp_hsa_copy_wait(struct read_sccb *sccb)
+{
+	unsigned int cmd;
+	int rc;
+
+	memset(sccb, 0, sizeof(struct read_sccb));
+	sccb->header.length = 0x1000;
+
+	cmd = SCLP_CMD_READ_DATA;
+	rc = start_sclp(cmd, sccb);
+
+	if (rc)
+		return rc;
+
+	if (sccb->header.response_code != 0x20)
+		return 1;
+
+	return 0;
+}
+
+static int __sclp_hsa_copy(struct sdias_sccb *sccb, void *dest_addr,
+			   unsigned long first_block, unsigned long nr_blocks)
+{
+	unsigned int cmd;
+	int rc;
+
+	sccb->header.length = sizeof(*sccb);
+
+	sccb->evbuf.header.length = sizeof(sccb->evbuf);
+	sccb->evbuf.header.type = EVTYP_SDIAS;
+	sccb->evbuf.event_qual = EQ_STORE_DATA;
+	sccb->evbuf.event_id = 0x4712;
+	sccb->evbuf.asa_size = 1;
+	sccb->evbuf.asa = (unsigned long) dest_addr;
+	sccb->evbuf.fbn = first_block;
+	sccb->evbuf.blk_cnt = nr_blocks;
+	sccb->evbuf.dbs = 1;
+
+	cmd = SCLP_CMD_WRITE_DATA;
+	rc = start_sclp(cmd, sccb);
+	if (rc)
+		return 1;
+
+	if (sccb->header.response_code != 0x20)
+		return 1;
+
+	if (!hsa_sync_mode) {
+		if (!(S390_lowcore.ext_params & 0x3)) {
+			sclp_wait_for_int(0);
+			if (!(S390_lowcore.ext_params & 0x3))
+				return 1;
+		}
+		if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
+			return 1;
+	}
+	/* Check for expected event status */
+	if ((sccb->evbuf.event_status != SDIAS_EVSTATE_PART_STORED) &&
+	    (sccb->evbuf.event_status != SDIAS_EVSTATE_ALL_STORED))
+		return 1;
+
+	return 0;
+}
+
+int sclp_hsa_copy(void *dest_addr, unsigned long first_block,
+		  unsigned long nr_blocks)
+{
+	struct sdias_sccb *sccb;
+	int rc;
+
+	sccb = (void *)get_zeroed_page();
+	rc = __sclp_hsa_copy(sccb, dest_addr, first_block, nr_blocks);
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+int sclp_hsa_get_size(unsigned long *hsa_size)
+{
+	struct sdias_sccb *sccb;
+	unsigned int cmd;
+	int rc = -EIO;
+
+	sccb = (void *)get_zeroed_page();
+	sccb->header.length = sizeof(*sccb);
+
+	sccb->header.length = sizeof(*sccb);
+	sccb->evbuf.header.length = sizeof(struct sdias_evbuf);
+	sccb->evbuf.header.type = EVTYP_SDIAS;
+	sccb->evbuf.event_qual = EQ_SIZE;
+	sccb->evbuf.data_id = DI_FCP_DUMP;
+	sccb->evbuf.event_id = 4712;
+	sccb->evbuf.dbs = 1;
+
+	cmd = SCLP_CMD_WRITE_DATA;
+	if (start_sclp(cmd, sccb))
+		goto out;
+	if (sccb->header.response_code != 0x20)
+		goto out;
+
+	if (!hsa_sync_mode) {
+		if (!(S390_lowcore.ext_params & 0x3)) {
+			sclp_wait_for_int(0);
+			if (!(S390_lowcore.ext_params & 0x3))
+				goto out;
+		}
+		if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
+			goto out;
+	}
+	if (sccb->evbuf.blk_cnt) {
+		*hsa_size = (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
+		rc = 0;
+	}
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+void sclp_hsa_copy_init(void *dest_addr)
+{
+	struct sdias_sccb *sccb;
+
+	sclp_setup(SCLP_HSA_INIT);
+	sccb = (void *)get_zeroed_page();
+	__sclp_hsa_copy(sccb, dest_addr, 2, 1);
+	/* Check buffer that was filled by sclp_hsa_copy */
+	if (sccb->evbuf.event_status != 0) {
+		/* Use synchonous mode */
+		hsa_sync_mode = 1;
+		free_page((unsigned long) sccb);
+		return;
+	}
+
+	/* Use async mode */
+	hsa_sync_mode = 0;
+	free_page((unsigned long) sccb);
+	sclp_setup(SCLP_DISABLE);
+	sclp_setup(SCLP_HSA_INIT_ASYNC);
+}
+
+void sclp_hsa_copy_exit(void)
+{
+	sclp_setup(SCLP_DISABLE);
+	diag308(DIAG308_REL_HSA, NULL);
+}
--- /dev/null
+++ b/zipl/boot/sclp_stage3.h
@@ -0,0 +1,52 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Functions for console input and output.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#ifndef SCLP_STAGE3_H
+#define SCLP_STAGE3_H
+
+#include "sclp.h"
+
+#define SDIAS_EVSTATE_ALL_STORED  0x00
+#define SDIAS_EVSTATE_PART_STORED 0x10
+
+#define SDIAS_EVSTATE_ALL_STORED  0x00
+#define SDIAS_EVSTATE_PART_STORED 0x10
+
+struct sdias_evbuf {
+	struct  evbuf_header header;
+	uint8_t      event_qual;
+	uint8_t      data_id;
+	uint64_t     reserved2;
+	uint32_t     event_id;
+	uint16_t     reserved3;
+	uint8_t      asa_size;
+	uint8_t      event_status;
+	uint32_t     reserved4;
+	uint32_t     blk_cnt;
+	uint64_t     asa;
+	uint32_t     reserved5;
+	uint32_t     fbn;
+	uint32_t     reserved6;
+	uint32_t     lbn;
+	uint16_t     reserved7;
+	uint16_t     dbs;
+} __packed;
+
+struct sdias_sccb {
+	struct sccb_header  header;
+	struct sdias_evbuf  evbuf;
+} __packed;
+
+
+int sclp_hsa_copy(void *, unsigned long, unsigned long);
+int sclp_hsa_get_size(unsigned long *hsa_size);
+void sclp_hsa_copy_init(void *);
+void sclp_hsa_copy_exit();
+
+#endif /* SCLP_H */
--- /dev/null
+++ b/zipl/boot/stage2.c
@@ -0,0 +1,137 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Main program for stage2 bootloader.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "stage2.h"
+#include "error.h"
+#include "libc.h"
+#include "s390.h"
+#include "menu.h"
+
+static int is_null_descriptor(disk_blockptr_t *address)
+{
+	unsigned long long *value = (unsigned long long *)address;
+
+	return *value == 0;
+}
+
+static void *load_blocklist(struct component_entry *descriptor_address,
+			    struct subchannel_id subchannel_id, void *load_address)
+{
+	disk_blockptr_t *indirect_blocks, *indirect_blockspace,
+		*start_addr;
+	unsigned long length;
+	long long nr_descr;
+
+	/* start address to load first indirect blocks */
+	start_addr = (disk_blockptr_t *)&descriptor_address->data;
+	/* get a free page to store indirect blocks in */
+	indirect_blockspace = (void *)get_zeroed_page();
+
+	do {
+		length = extract_length(start_addr);
+		/* calculate number of descriptors to be processed and base 0 */
+		nr_descr = length/DESCR_PER_BLOCK - 1;
+		indirect_blocks = indirect_blockspace;
+		/* load indirect blocks */
+		load_direct(start_addr, subchannel_id, indirect_blocks);
+
+		/* process indirect blocks */
+		while (nr_descr > 0) {
+			if (is_null_descriptor(indirect_blocks))
+				goto out_free_page;
+
+			/* for special zero block simply clear mem */
+			if (!is_zero_block(indirect_blocks)) {
+				length = extract_length(indirect_blocks);
+				memset(load_address, 0, length);
+				load_address += length;
+			} else
+				load_address = load_direct(indirect_blocks,
+							   subchannel_id,
+							   load_address);
+
+			indirect_blocks++;
+			nr_descr--;
+		}
+		/* update pointer for next round */
+		start_addr = indirect_blocks;
+	/* as long as another indirect block needs to be loaded */
+	} while (!is_null_descriptor(indirect_blocks));
+
+out_free_page:
+	free_page((unsigned long)indirect_blockspace);
+	return load_address;
+}
+
+
+static void execute(uint64_t psw)
+{
+	asm volatile(
+		"      lpsw    %[psw]\n"
+		: : [psw] "Q" (psw) : "cc"
+		);
+}
+
+void start(void)
+{
+	struct stage2_descr stage2_descr;
+	struct subchannel_id subchannel_id;
+	void *load_address;
+	struct component_entry *entry;
+	disk_blockptr_t *blockptr;
+	void *load_page;
+	int config_nr;
+
+	subchannel_id = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
+	stage2_descr = *(struct stage2_descr*)STAGE2_DESC;
+
+	/* print menu and get configuration number */
+	config_nr = menu();
+	kdump_stage2(config_nr);
+
+	io_irq_enable();
+	set_device(subchannel_id, ENABLED);
+
+	load_page = (void *)get_zeroed_page();
+	load_address = (disk_blockptr_t *) load_page;
+
+	/* load blockpointer list to load address */
+	load_direct((disk_blockptr_t *)&stage2_descr, subchannel_id,
+		    load_address);
+
+	blockptr = (disk_blockptr_t *)(load_address +
+					     sizeof(disk_blockptr_t));
+
+	load_direct(&blockptr[config_nr], subchannel_id, load_address);
+
+	/* skip header */
+	entry = (struct component_entry *)
+		(load_address + sizeof(struct component_header));
+
+	while (entry->type == COMPONENT_LOAD) {
+		load_address = (void *)(unsigned long)
+			entry->address.load_address[1];
+		load_blocklist(entry, subchannel_id, load_address);
+		entry++;
+	}
+	if (entry->type != COMPONENT_EXECUTE)
+		panic(EWRONGTYPE, "");
+
+	free_page((unsigned long)load_page);
+	io_irq_disable();
+	set_device(subchannel_id, DISABLED);
+
+	execute(entry->address.load_psw);
+}
+
+void panic_notify(unsigned long UNUSED(reason))
+{
+}
+
+uint64_t stage2_head __attribute__((section(".stage2.head")));
--- /dev/null
+++ b/zipl/boot/stage2.h
@@ -0,0 +1,76 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Main program for stage2 bootloader.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "error.h"
+#include "libc.h"
+#include "cio.h"
+#include "s390.h"
+
+#define DESCR_PER_BLOCK         16
+
+/* ADRESS */
+#define STAGE2_DESC 0x78
+
+/* Layout of ECKD disk block pointer */
+struct eckd_blockptr {
+	uint16_t cyl;
+	uint16_t head;
+	uint8_t sec;
+	uint16_t size;
+	uint8_t blockct;
+	uint8_t reserved[8];
+} __packed;
+
+struct linear_blockptr {
+	uint64_t blockno;
+	uint16_t size;
+	uint16_t blockct;
+	uint8_t reserved[4];
+} __packed;
+
+typedef union {
+	struct eckd_blockptr eckd;
+	struct linear_blockptr linear;
+} disk_blockptr_t;
+
+struct component_header {
+	uint8_t magic[4];
+	uint8_t type;
+	uint8_t reserved[27];
+} __packed;
+
+struct component_entry {
+	uint8_t data[23];
+	uint8_t type;
+	union {
+		uint32_t load_address[2];
+		uint64_t load_psw;
+	} address;
+} __packed;
+
+typedef enum {
+	COMPONENT_EXECUTE = 0x01,
+	COMPONENT_LOAD = 0x02
+} component_type;
+
+struct stage2_descr {
+	uint8_t reserved[16];
+} __packed __aligned(8);
+
+void *load_direct(disk_blockptr_t *, struct subchannel_id , void *);
+int extract_length(void *);
+int is_zero_block(void *);
+void kdump_stage2(unsigned long);
+
+
+#endif /* COMMON_H */
+
--- /dev/null
+++ b/zipl/boot/stage2.lds
@@ -0,0 +1,61 @@
+/*
+ * Memory layout for stage 2
+ * =========================
+ *
+ * General memory layout
+ * ---------------------
+ *
+ * 0x0000-0x1fff	Lowcore
+ * 0x2000-0x4fff	Sections (load): head, text, data, rodata, rodata.str
+ * 0x5000-0x51ff	eckd2dump_mv parameter block (426 bytes)
+ * 0x5200-0x5fff	Sections: bss
+ * 0x6000-0x9fff	Memory allocation (heap)
+ * 0xa000-0xdfff        Memory to load stage3 to
+ * 0xe000-0xffff	Stack
+ *
+ * Special memory locations
+ * ------------------------
+ *
+ * 0x78			Stage 2 description parameters
+ * 0x2018		Stage 2 entry point
+ * 0x3ff7		eckd2dump_mv force parameter
+ * 0x3ff8		Max mem dump parameter
+ * 0x5000-0x51ff	eckd2dump_mv parameter block (426 bytes)
+ */
+
+SECTIONS
+{
+  . = 0x78;
+  __stage2_desc = .;
+
+  . = 0x2000;
+  .stage2.head : { *(.stage2.head) }
+  . = 0x2018;
+  .text.start : { *(.text.start) }
+  .text : { *(.text) }
+  __ex_table_start = .;
+  .ex_table : { *(.ex_table) }
+  __ex_table_stop = .;
+  .rodata : {*(.rodata) }
+  .data : { *(.data) }
+  __stage2_params = .;
+
+  . = 0x4ff0;
+  .stage2dump.tail : { *(.stage2dump.tail) }
+  . = 0x5000;
+  .eckd2dump_mv.tail : { *(.eckd2dump_mv.tail) }
+
+  . = 0x5200;
+  __bss_start = .;
+  .bss : { *(.bss) }
+  __bss_stop = .;
+
+  . = 0x6000;
+  __heap_start = .;
+  . = 0xa000;
+  __heap_stop = .;
+
+  . = 0xf000;
+  .eh_frame : { *(.eh_frame) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+}
--- /dev/null
+++ b/zipl/boot/stage2dump.c
@@ -0,0 +1,300 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common functions for stand-alone dump tools
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include <stdarg.h>
+#include "stage2dump.h"
+#include "error.h"
+#include "sclp.h"
+
+#define CPU_ADDRESS_MAX	1000
+
+/*
+ * Static globals
+ */
+static unsigned long progress_next_addr;
+static unsigned long progress_inc = 0x20000000; /* Issue message each 512M */
+
+/*
+ * IPL info in lowcore
+ */
+struct ipib_info {
+	unsigned long	ipib;
+	uint32_t	ipib_csum;
+};
+
+/*
+ * Tail parameters
+ */
+struct stage2dump_parm_tail parm_tail
+	__attribute__ ((section(".stage2dump.tail"))) = {
+	.mem_upper_limit = 0xffffffffffffffffULL,
+};
+
+/*
+ * Globals
+ */
+struct df_s390_hdr *dump_hdr;
+
+/*
+ * Init dumper: Allocate standard pages, set timers
+ */
+static void init_early(void)
+{
+	/* Allocate dump header */
+	dump_hdr = (void *) get_zeroed_page();
+
+	/* Set clock comparator and CPU timer to future */
+	set_clock_comparator(0xffffffffffffffffULL);
+	set_cpu_timer(0x7fffffffffffffffULL);
+}
+
+/*
+
+ * Init dump progress messages to sclp console
+ *
+ * 8 messages if the memory is 4G or less, otherwise one message for each
+ * 512M chunk of dumped memory
+ */
+static void progress_init(void)
+{
+	if (dump_hdr->mem_size <= (4 * 1024 * 1024 * 1024ULL))
+		progress_inc = dump_hdr->mem_size >> 3;
+	progress_next_addr = progress_inc;
+}
+
+/*
+ * Print progress message
+ */
+void progress_print(unsigned long addr)
+{
+	if (addr < progress_next_addr && addr != dump_hdr->mem_size)
+		return;
+	printf("%08lu / %08lu MB", addr >> 20, dump_hdr->mem_size >> 20);
+	progress_next_addr += progress_inc;
+}
+
+/*
+ * Create IDA list starting at "addr" with "len" bytes
+ */
+void create_ida_list(unsigned long *list, int len, unsigned long addr,
+		     unsigned long zero_page)
+{
+	unsigned long ida_addr;
+
+	while (len > 0) {
+		if (zero_page)
+			ida_addr = page_is_valid(addr) ? addr : zero_page;
+		else
+			ida_addr = addr;
+		*list = ida_addr;
+		list++;
+		addr += PAGE_SIZE;
+		len -= PAGE_SIZE;
+	}
+}
+
+/*
+ * Initialize s390 dump header
+ */
+static void df_s390_dump_init(void)
+{
+	struct df_s390_hdr *dh = dump_hdr;
+
+	dh->magic = DF_S390_MAGIC;
+	dh->hdr_size = DF_S390_HDR_SIZE;
+	dh->page_size = PAGE_SIZE;
+	dh->dump_level = 4;
+	dh->version = 5;
+	dh->mem_start = 0;
+	dh->arch = DF_S390_ARCH_64;
+	dh->build_arch = DF_S390_ARCH_64;
+	get_cpu_id((struct cpuid *) &dh->cpu_id);
+	dh->tod = get_tod_clock();
+	dh->volnr = 0;
+}
+
+/*
+ * Initialize page with end marker
+ */
+void df_s390_em_page_init(unsigned long addr)
+{
+	struct df_s390_em *em = (void *) addr;
+
+	em->magic = DF_S390_EM_MAGIC;
+	em->tod = get_tod_clock();
+}
+
+/*
+ * Find out memory size
+ */
+static void count_mem(void)
+{
+	unsigned long mem_size_max, mem_size, addr, rnmax, rzm;
+	struct read_info_sccb *sccb;
+
+	sccb = (void *) get_zeroed_page();
+	/* Get memory max */
+	if (sclp_read_info(sccb))
+		panic(EMEMCOUNT, "Could not evaluate memory layout");
+	rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
+	rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
+	rzm <<= 20;
+	mem_size_max = rnmax * rzm;
+	mem_size = 0;
+	/* Find out real memory end without standby memory */
+	for (addr = 0; addr < mem_size_max; addr += rzm) {
+		if (!page_is_valid(addr))
+			continue;
+		mem_size = addr + rzm;
+	}
+	free_page((unsigned long) sccb);
+
+	dump_hdr->mem_size_real = mem_size;
+	/* Check if we have an upper limit */
+	if (mem_size > parm_tail.mem_upper_limit) {
+		printf("Using memory limit");
+		mem_size = parm_tail.mem_upper_limit;
+	}
+	dump_hdr->mem_size = dump_hdr->mem_end = mem_size;
+	dump_hdr->num_pages = dump_hdr->mem_size >> 12;
+}
+
+/*
+ * Copy 64 bit lowcore after store status
+ */
+static void copy_lowcore_64(void)
+{
+	char *real_cpu_cnt_ptr = ((char *) &dump_hdr->mem_size_real) + 11;
+	char *cpu_cnt_ptr = ((char *) &dump_hdr->mem_size_real) + 9;
+	unsigned long prefix;
+	uint16_t cpu_cnt = 0;
+
+	prefix = S390_lowcore.prefixreg_save_area;
+
+	/* Need memcpy because of aligment problem of members */
+	memcpy(&cpu_cnt, real_cpu_cnt_ptr, sizeof(cpu_cnt));
+	cpu_cnt++;
+	memcpy(real_cpu_cnt_ptr, &cpu_cnt, sizeof(cpu_cnt));
+
+	if (prefix < 0x10000) /* if < linux-start addr */
+		return;
+	if (prefix % 0x1000) /* check page alignment */
+		return;
+
+	/* Save lowcore pointer (32 bit) in dump header */
+	memcpy(&cpu_cnt, cpu_cnt_ptr, sizeof(cpu_cnt));
+	dump_hdr->lc_vec[cpu_cnt] = prefix;
+	cpu_cnt++;
+	memcpy(cpu_cnt_ptr, &cpu_cnt, sizeof(cpu_cnt));
+	/*
+	 *  |-----------------------------------------------------------|
+	 *  | Decimal |  Length   | Data                                |
+	 *  | Address |  in Bytes |                                     |
+	 *  |_________|___________|_____________________________________|
+	 *  | 163     | 1         | Architectural Mode ID               |
+	 *  | 4608    | 128       | Fl-pt registers 0-15                |
+	 *  | 4736    | 128       | General registers 0-15              |
+	 *  | 4864    | 16        | Current PSW                         |
+	 *  | 4888    | 4         | Prefix register                     |
+	 *  | 4892    | 4         | Fl-pt control register              |
+	 *  | 4900    | 4         | TOD programmable register           |
+	 *  | 4904    | 8         | CPU timer                           |
+	 *  | 4912    | 1         | Zeros                               |
+	 *  | 4913    | 7         | Bits 0-55 of clock comparator       |
+	 *  | 4928    | 64        | Access registers 0-15               |
+	 *  | 4992    | 128       | Control registers 0-15              |
+	 *  |_________|___________|_____________________________________|
+	 */
+	memcpy((void *) prefix + 4608, (void *) 4608, 272);
+	memcpy((void *) prefix + 4888, (void *) 4888, 8);
+	memcpy((void *) prefix + 4900, (void *) 4900, 20);
+	memcpy((void *) prefix + 4928, (void *) 4928, 192);
+}
+
+/*
+ * Do store status
+ */
+static void store_status(void)
+{
+	unsigned short current_cpu;
+	unsigned long page;
+	int addr, cc;
+
+	/* Save absolute zero lowcore */
+	page = get_zeroed_page();
+	memcpy((void *) page, (void *) 0x1000, PAGE_SIZE);
+
+	current_cpu = stap();
+
+	copy_lowcore_64();
+
+	for (addr = 0; addr < CPU_ADDRESS_MAX; addr++) {
+		if (addr == current_cpu)
+			continue;
+		do {
+			cc = sigp(addr, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
+		} while (cc == SIGP_CC_BUSY);
+
+		if (cc != SIGP_CC_ORDER_CODE_ACCEPTED)
+			continue;
+		copy_lowcore_64();
+	}
+	/* Restore absolute zero lowcore */
+	memcpy((void *) 0x1000, (void *) page, PAGE_SIZE);
+	free_page(page);
+}
+
+/*
+ * Perform reipl: check lowcore for the address of an IPL Information
+ * Block followed by a valid checksum (as defined in lowcore.h and set
+ * by ipl.c). In case of match use diag308 to IPL.
+ */
+static void dump_exit(unsigned long code)
+{
+	struct ipib_info *ipib_info = (struct ipib_info *)&S390_lowcore.ipib;
+	uint32_t ipib_len, csum;
+
+	if (!ipib_info->ipib)
+		libc_stop(code);
+	ipib_len = *((uint32_t *) ipib_info->ipib);
+	csum = csum_partial((void *) ipib_info->ipib, ipib_len, 0);
+	if (ipib_info->ipib_csum != csum)
+		libc_stop(code);
+	diag308(DIAG308_SET, (void *) ipib_info->ipib);
+	diag308(DIAG308_IPL, NULL);
+}
+
+/*
+ * Print message and exit dumper
+ */
+void panic_notify(unsigned long code)
+{
+	printf("Dump failed");
+	dump_exit(code);
+}
+
+/*
+ * Create stand-alone dump
+ */
+void start(void)
+{
+	init_early();
+	store_status();
+	dt_device_parm_setup();
+	sclp_setup(SCLP_INIT);
+	dt_device_enable();
+	df_s390_dump_init();
+	printf("zIPL v%s dump tool (64 bit)", RELEASE_STRING);
+	printf("Dumping 64 bit OS");
+	count_mem();
+	progress_init();
+	dt_dump_mem();
+	printf("Dump successful");
+	dump_exit(0);
+}
--- /dev/null
+++ b/zipl/boot/stage2dump.h
@@ -0,0 +1,127 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Common dump functions
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#ifndef STAGE2DUMP_H
+#define STAGE2DUMP_H
+
+#include "libc.h"
+#include "s390.h"
+
+#define IPL_SC	*((struct subchannel_id *) &S390_lowcore.subchannel_id)
+
+/*
+ * zipl parameters passed at tail of dump tools
+ */
+struct stage2dump_parm_tail {
+	char		reserved[6];
+	uint16_t	mvdump_force;
+	uint64_t	mem_upper_limit;
+} __packed;
+
+extern struct stage2dump_parm_tail parm_tail
+	__attribute__ ((section(".stage2dump.tail")));
+
+/*
+ * Load 4 bytes from addr
+ */
+static inline unsigned int load(unsigned long addr)
+{
+	unsigned int val;
+
+	asm volatile(
+		"	l	%0,0(%1)\n"
+		: "=d" (val) : "d" (addr) : "cc");
+	return val;
+}
+
+/*
+ * S390 dump format defines
+ */
+#define DF_S390_MAGIC		0xa8190173618f23fdULL
+#define DF_S390_HDR_SIZE	0x1000
+#define DF_S390_EM_SIZE		16
+#define DF_S390_EM_MAGIC	0x44554d505f454e44ULL
+#define DF_S390_CPU_MAX		512
+#define DF_S390_MAGIC_BLK_ECKD	3
+
+/*
+ * Architecture of dumped system
+ */
+enum df_s390_arch {
+	DF_S390_ARCH_32	= 1,
+	DF_S390_ARCH_64	= 2,
+};
+
+/*
+ * s390 dump header format
+ */
+struct df_s390_hdr {
+	uint64_t	magic;				/* 0x000 */
+	uint32_t	version;			/* 0x008 */
+	uint32_t	hdr_size;			/* 0x00c */
+	uint32_t	dump_level;			/* 0x010 */
+	uint32_t	page_size;			/* 0x014 */
+	uint64_t	mem_size;			/* 0x018 */
+	uint64_t	mem_start;			/* 0x020 */
+	uint64_t	mem_end;			/* 0x028 */
+	uint32_t	num_pages;			/* 0x030 */
+	uint32_t	pad;				/* 0x034 */
+	uint64_t	tod;				/* 0x038 */
+	uint64_t	cpu_id;				/* 0x040 */
+	uint32_t	arch;				/* 0x048 */
+	uint32_t	volnr;				/* 0x04c */
+	uint32_t	build_arch;			/* 0x050 */
+	uint64_t	mem_size_real;			/* 0x054 */
+	uint8_t		mvdump;				/* 0x05c */
+	uint16_t	cpu_cnt;			/* 0x05d */
+	uint16_t	real_cpu_cnt;			/* 0x05f */
+	uint8_t		end_pad1[0x200-0x061];		/* 0x061 */
+	uint64_t	mvdump_sign;			/* 0x200 */
+	uint64_t	mvdump_zipl_time;		/* 0x208 */
+	uint8_t		end_pad2[0x800-0x210];		/* 0x210 */
+	uint32_t	lc_vec[DF_S390_CPU_MAX];	/* 0x800 */
+} __packed __aligned(16);
+
+/*
+ *  End marker: Should be at the end of every valid s390 crash dump
+ */
+struct df_s390_em {
+	uint64_t	magic;
+	uint64_t	tod;
+} __packed __aligned(16);
+
+/*
+ * Linker script defined symbols
+ */
+extern char __eckd2mvdump_parm_start[];
+extern char __stage2_desc[];
+
+/*
+ * Dump common globals
+ */
+extern struct df_s390_hdr *dump_hdr;
+
+/*
+ * Common functions
+ */
+void create_ida_list(unsigned long *list, int len, unsigned long addr,
+		     unsigned long zero_page);
+void init_progress_print(void);
+void progress_print(unsigned long addr);
+void df_s390_em_page_init(unsigned long page);
+void pgm_check_handler(void);
+
+/*
+ * Dump tool backend functions
+ */
+void dt_device_parm_setup(void);
+void dt_device_enable(void);
+void dt_dump_mem(void);
+
+#endif /* STAGE2DUMP_H */
--- a/zipl/boot/stage3.S
+++ /dev/null
@@ -1,198 +0,0 @@
-#
-#  Third stage boot loader
-#    Copyright IBM Corp. 2003, 2006.
-#    Author(s):	Heiko Carstens (heiko.carstens@de.ibm.com)
-#              	Peter Oberparleiter (peter.oberparleiter@de.ibm.com)
-#
-
-# some definitions from kernel land
-__LC_CPUID		= 0xC60
-__LC_IPLDEV		= 0xC6C
-IPL_DEVICE		= 0x10404
-INITRD_START		= 0x10408
-INITRD_SIZE		= 0x10410
-COMMAND_LINE		= 0x10480
-COMMAND_LINE_SIZE	= 896		# max command line length
-COMMAND_LINE_EXTRA	= 0xA000-0x400	# address of extra command line
-
-_parm_addr:				#
-	.quad  0			# address of parmline
-_initrd_addr:				#
-	.quad  0			# address of initrd
-_initrd_len:				#
-	.quad  0			# length of initrd
-_load_psw:				#
-	.quad  0			# load psw of kernel
-_extra_parm:				#
-	.quad  0			# use extra parm line mechanism?
-
-#
-# Program execution of the third stage boot loader starts at 0xA028
-#
-        .globl _start
-_start: basr   %r13,0                   # base register
-0:	l      %r2,0xb8			# subchannel id of ipl device
-	st     %r2,__LC_IPLDEV          # old ipl device storage location
-	l      %r3,1f-0b(%r13)          # load address of IPL_DEVICE
-	st     %r2,0(%r3)               # new ipl device storage location
-
-	l      %r1,2f-0b(%r13)		# load address of parmfile parameter
-	l      %r1,4(%r1)		# load address of parmfile
-	l      %r2,3f-0b(%r13)          # load address of kernel command line
-	mvc    0x0(256,%r2),0(%r1)      # move command line to 0x10480
-	mvc    0x100(256,%r2),0x100(%r1)
-	mvc    0x200(256,%r2),0x200(%r1)
-	mvc    0x300(127,%r2),0x300(%r1)
-	xc     0x37f(1,%r2),0x37f(%r2)
-
-	l      %r1,11f-0b(%r13)		# check for extra parm flag
-	l      %r1,4(%r1)
-	ltr    %r1,%r1
-	jz     .Lnoextra		# skip if zero
-
-	l      %r1,9f-0b(%r13)		# check for extra command line
-	sr     %r0,%r0
-	ic     %r0,0(%r1)
-	ltr    %r0,%r0
-	jz     .Lnoextra		# skip if no extra command line present
-
-	la     %r3,10f-0b(%r13)		# convert to ascii
-	stidp  __LC_CPUID		# use different code page on LPAR
-	tm     __LC_CPUID,0xff
-	jo     .Lnolpar
-	la     %r3,12f-0b(%r13)
-.Lnolpar:
-	tr     0x0(256,%r1),0(%r3)
-	tr     0x100(256,%r1),0(%r3)
-	tr     0x200(256,%r1),0(%r3)
-	tr     0x300(127,%r1),0(%r3)
-
-	sr     %r4,%r4			# leading '=' will replace string
-.Lfindequal:
-	ic     %r0,0(%r4,%r1)
-	ahi    %r4,1
-	ltr    %r0,%r0
-	jz     .Lnoextra
-	chi    %r0,' '			# skip leading whitespace
-	je     .Lfindequal
-	chi    %r0,'='
-	jne    .Ldoappend
-	ar     %r1,%r4			# start copy after '='
-	lnr    %r4,%r4
-	ahi    %r4,COMMAND_LINE_SIZE
-	j      .Lappend
-
-.Ldoappend:
-	lhi    %r4,COMMAND_LINE_SIZE
-.Lfindend:
-	ic     %r0,0(%r2)		# find end of current parameter string
-	ltr    %r0,%r0
-	jz     .Lappend			# got it
-	ahi    %r2,1
-	brct   %r4,.Lfindend
-	j      .Lnoextra		# none found
-
-.Lappend:
-	ic     %r0,0(%r1)		# append extra parameters
-	stc    %r0,0(%r2)
-	ahi    %r1,1
-	ahi    %r2,1
-	ltr    %r0,%r0			# at end of string?
-	jz     .Lnoextra		# yes, continue with ipl
-	brct   %r4,.Lappend		# no, loop
-
-	xc     0x37f(1,%r2),0x37f(%r2)	# nil-terminate string
-
-.Lnoextra:
-	l      %r1,4f-0b(%r13)		# load address of initrd parameter
-	l      %r2,5f-0b(%r13)		# load address of INITRD_START
-	mvc    0(8,%r2),0(%r1)		# copy INITRD_START address
-
-	l      %r1,6f-0b(%r13)		# load address of initrd length parmeter
-	l      %r2,7f-0b(%r13)		# load address of INITRD_SIZE
-	mvc    0(8,%r2),0(%r1)		# copy INITRD_SIZE length
-
-	l      %r1,8f-0b(%r13)
-	mvc    0(8,%r0),0(%r1)		# copy load psw to 0
-
-	lm     %r0,%r15,0x180		# load saved registers
-	lpsw   0			# start kernel
-	
-1:	.long  IPL_DEVICE
-2:	.long  _parm_addr
-3:	.long  COMMAND_LINE
-4:	.long  _initrd_addr
-5:	.long  INITRD_START
-6:	.long  _initrd_len
-7:	.long  INITRD_SIZE
-8:	.long  _load_psw
-9:	.long  COMMAND_LINE_EXTRA
-11:	.long  _extra_parm
-
-# EBCDIC 037 to ASCII (z/VM default)
-10:	.byte 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F
-	.byte 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-	.byte 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07
-	.byte 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
-	.byte 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B
-	.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07
-	.byte 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04
-	.byte 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A
-	.byte 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86
-	.byte 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C
-	.byte 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07
-	.byte 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA
-	.byte 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F
-	.byte 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F
-	.byte 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
-	.byte 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22
-	.byte 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
-	.byte 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1
-	.byte 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70
-	.byte 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07
-	.byte 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78
-	.byte 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07
-	.byte 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC
-	.byte 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07
-	.byte 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
-	.byte 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07
-	.byte 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50
-	.byte 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98
-	.byte 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58
-	.byte 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07
-	.byte 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
-	.byte 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
-
-# EBCDIC 500 to ASCII (LPAR default)
-12:	.byte 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F
-	.byte 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-	.byte 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07
-	.byte 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
-	.byte 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B
-	.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07
-	.byte 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04
-	.byte 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A
-	.byte 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86
-	.byte 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21
-	.byte 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07
-	.byte 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E
-	.byte 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F
-	.byte 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F
-	.byte 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
-	.byte 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22
-	.byte 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67
-	.byte 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1
-	.byte 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70
-	.byte 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07
-	.byte 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78
-	.byte 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07
-	.byte 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC
-	.byte 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07
-	.byte 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
-	.byte 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07
-	.byte 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50
-	.byte 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98
-	.byte 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58
-	.byte 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07
-	.byte 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
-	.byte 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
--- /dev/null
+++ b/zipl/boot/stage3.c
@@ -0,0 +1,298 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Main program for stage3 bootloader.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#include "stage3.h"
+#include "libc.h"
+#include "s390.h"
+
+/*
+ * 48 Byte dummy space for external symbols
+ * _parm_addr;    address of parmline
+ * _initrd_addr;  address of initrd
+ * _initrd_len;   length of initrd
+ * _load_psw;     load psw of kernel
+ * _extra_parm;   use extra parm line mechanism?
+ * stage3_flags;  flags (e.g. STAGE3_FLAG_KDUMP)
+ *
+ * needed to blow up the binary and leave room
+ */
+__attribute__ ((section(".text.dummy"))) void _dummy(void)
+{
+		asm volatile(
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		".long 0x00000000\n"
+		);
+}
+
+static unsigned char ebc_037[256] = {
+/* 0x00  NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+	0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08  -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+	0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10  DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                -ENP  ->LF             */
+	0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18  CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                  -IUS */
+	0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20  -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                -INP                   */
+	0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28  -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                     -SW                               */
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+	0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+	0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40   SP   RSP           ä              ----       */
+	0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48                      .     <     (     +     | */
+	0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50    &                                      ---- */
+	0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58          ß     !     $     *     )     ;       */
+	0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60    -     /  ----     Ä  ----  ----  ----       */
+	0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68             ----     ,     %     _     >     ? */
+	0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70  ---        ----  ----  ----  ----  ----  ---- */
+	0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78    *     `     :     #     @     '     =     " */
+	0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80    *     a     b     c     d     e     f     g */
+	0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88    h     i              ----  ----  ----       */
+	0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90    °     j     k     l     m     n     o     p */
+	0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98    q     r                    ----        ---- */
+	0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0          ~     s     t     u     v     w     x */
+	0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8    y     z              ----  ----  ----  ---- */
+	0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0    ^                    ----     §  ----       */
+	0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8       ----     [     ]  ----  ----  ----  ---- */
+	0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0    {     A     B     C     D     E     F     G */
+	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8    H     I  ----           ö              ---- */
+	0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0    }     J     K     L     M     N     O     P */
+	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8    Q     R  ----           ü                   */
+	0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0    \           S     T     U     V     W     X */
+	0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8    Y     Z        ----     Ö  ----  ----  ---- */
+	0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0    0     1     2     3     4     5     6     7 */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8    8     9  ----  ----     Ü  ----  ----  ---- */
+	0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+static unsigned char ebc_500[256] = {
+/* 0x00  NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+	0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08  -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+	0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10  DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                -ENP  ->LF             */
+	0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18  CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                  -IUS */
+	0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20  -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                -INP                   */
+	0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28  -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                     -SW                               */
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+	0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+	0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40   SP   RSP           ä              ----       */
+	0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48                      .     <     (     +     | */
+	0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50    &                                      ---- */
+	0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58          ß     !     $     *     )     ;       */
+	0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60    -     /  ----     Ä  ----  ----  ----       */
+	0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68             ----     ,     %     _     >     ? */
+	0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70  ---        ----  ----  ----  ----  ----  ---- */
+	0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78    *     `     :     #     @     '     =     " */
+	0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80    *     a     b     c     d     e     f     g */
+	0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88    h     i              ----  ----  ----       */
+	0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90    °     j     k     l     m     n     o     p */
+	0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98    q     r                    ----        ---- */
+	0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0          ~     s     t     u     v     w     x */
+	0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8    y     z              ----  ----  ----  ---- */
+	0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0    ^                    ----     §  ----       */
+	0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8       ----     [     ]  ----  ----  ----  ---- */
+	0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0    {     A     B     C     D     E     F     G */
+	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8    H     I  ----           ö              ---- */
+	0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0    }     J     K     L     M     N     O     P */
+	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8    Q     R  ----           ü                   */
+	0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0    \           S     T     U     V     W     X */
+	0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8    Y     Z        ----     Ö  ----  ----  ---- */
+	0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0    0     1     2     3     4     5     6     7 */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8    8     9  ----  ----     Ü  ----  ----  ---- */
+	0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+static void ebcdic_to_ascii(unsigned char *target, unsigned char *source,
+		     unsigned int l)
+{
+	unsigned char *ebc;
+	unsigned int i;
+
+	ebc = is_zvm() ? ebc_037 : ebc_500;
+	for (i = 0; i < l; i++)
+			target[i] = ebc[source[i]];
+}
+
+static void
+start_kernel(void)
+{
+	struct psw_t *psw = &S390_lowcore.program_new_psw;
+	unsigned long addr, code;
+
+	/* Setup program check handler */
+	psw->mask = 0x000000180000000ULL;
+	code = 1;
+
+	asm volatile(
+		/* Setup program check handler */
+		"       larl    %[addr],.no_diag308\n"
+		"       stg     %[addr],8(%[psw])\n"
+		"       diag    %[code],%[code],0x308\n"
+		".no_diag308:\n"
+		"       sam31\n"
+		"       sr      %r1,%r1\n"
+		"       sr      %r2,%r2\n"
+		"       sigp    %r1,%r2,0x12\n"
+		"       lpsw    0\n"
+		: [addr] "=&d" (addr),
+		  [code] "+&d" (code)
+		: [psw] "a" (psw) );
+}
+
+void start(void)
+{
+	unsigned int subchannel_id;
+	unsigned char *cextra = (unsigned char *)COMMAND_LINE_EXTRA;
+	unsigned char *command_line =  (unsigned char *)COMMAND_LINE;
+	unsigned int begin = 0, end = 0, length = 0;
+
+	/* store subchannel ID into low core and into new kernel space */
+	subchannel_id = S390_lowcore.subchannel_id;
+	*(unsigned int *)__LC_IPLDEV = subchannel_id;
+	*(unsigned int *)IPL_DEVICE = subchannel_id;
+
+	/* if valid command line is given, copy it into new kernel space */
+	if (_parm_addr != UNSPECIFIED_ADDRESS) {
+		memcpy((void *)COMMAND_LINE,
+		       (void *)(unsigned long *)_parm_addr, COMMAND_LINE_SIZE);
+		/* terminate \0 */
+		*(char *)(COMMAND_LINE + COMMAND_LINE_SIZE - 1) = 0;
+	}
+
+	/* convert extra parameter to ascii */
+	if (!_extra_parm || !*cextra)
+		goto noextra;
+
+	/* Handle extra kernel parameters specified in DASD boot menu. */
+	ebcdic_to_ascii(cextra, cextra, COMMAND_LINE_SIZE);
+
+	/* remove leading whitespace */
+	while (begin <= COMMAND_LINE_SIZE && cextra[begin] == 0x20)
+		begin++;
+
+	/* determine length of extra parameter */
+	while (length <= COMMAND_LINE_SIZE && cextra[length] != 0)
+		length++;
+
+	/* find end of original parm line */
+	while (command_line[end] != 0 && command_line[end] != 0)
+		end++;
+
+	/*
+	 * if extra parm string starts with '=' replace original string,
+	 * else append
+	 */
+	if (cextra[begin] == 0x3d) {
+		memcpy((void *)COMMAND_LINE, (void *)(cextra + begin),
+		       length);
+	} else {
+		/* check if length is within max value */
+		length = (end + 1 + length <= COMMAND_LINE_SIZE) ? length :
+			(COMMAND_LINE_SIZE - end - 1);
+		/* add blank */
+		command_line[end] = 0x20;
+		end++;
+		/* append string */
+		memcpy((void *)(command_line + end),
+		       (void *)(cextra + begin), length);
+		/* terminate 0 */
+		command_line[end + length] = 0;
+	}
+
+noextra:
+	/* copy initrd start address and size intop new kernle space */
+	*(unsigned long long *)INITRD_START = _initrd_addr;
+	*(unsigned long long *)INITRD_SIZE = _initrd_len;
+
+	/* store address of new kernel to 0 to be able to start it */
+	*(unsigned long long *)0 = _load_psw;
+
+	kdump_stage3();
+
+	/* start new kernel */
+	start_kernel();
+}
+
+void panic_notify(unsigned long UNUSED(rc))
+{
+}
--- /dev/null
+++ b/zipl/boot/stage3.h
@@ -0,0 +1,38 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Main program for stage3 bootloader.
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Stefan Haberland <stefan.haberland@de.ibm.com>
+ */
+
+#ifndef STAGE3_H
+#define STAGE3_H
+
+#include "libc.h"
+#include "s390.h"
+
+#define IPL_DEVICE		 0x10404
+#define INITRD_START		 0x10408
+#define INITRD_SIZE		 0x10410
+#define OLDMEM_BASE		 0x10418
+#define OLDMEM_SIZE		 0x10420
+#define COMMAND_LINE		 0x10480
+#define COMMAND_LINE_SIZE	 896
+#define COMMAND_LINE_EXTRA	 (0xA000-0x400)
+
+#define STAGE3_FLAG_SCSI	 0x0001000000000000ULL
+#define STAGE3_FLAG_KDUMP	 0x0002000000000000ULL
+
+#define UNSPECIFIED_ADDRESS		-1ULL
+
+extern unsigned long long _parm_addr;   /* address of parmline */
+extern unsigned long long _initrd_addr; /* address of initrd */
+extern unsigned long long _initrd_len;  /* length of initrd */
+extern unsigned long long _load_psw;    /*  load psw of kernel */
+extern unsigned long long _extra_parm;  /* use extra parm line mechanism? */
+extern unsigned long long stage3_flags; /*  flags (e.g. STAGE3_FLAG_KDUMP) */
+extern void kdump_stage3();
+
+#endif /* STAGE3_H */
--- /dev/null
+++ b/zipl/boot/stage3.lds
@@ -0,0 +1,45 @@
+/*
+ * Memory layout for stage 3
+ */
+
+SECTIONS
+{
+  . = 0x0;
+
+  . = 0x7000;
+  __heap_start = .;
+  . = 0xa000;
+  __heap_stop = .;
+
+  . = 0xa000;
+  _parm_addr = .;
+  . = 0xa008;
+  _initrd_addr = .;
+  . = 0xa010;
+  _initrd_len = .;
+  . = 0xa018;
+  _load_psw = .;
+  . = 0xa020;
+  _extra_parm = .;
+  . = 0xa028;
+  stage3_flags =.;
+
+  . = 0xa000;
+  .text.dummy : { *(.text.dummy) }
+
+  . = 0xa050;
+  .text.start : { *(.text.start) }
+  .text : { *(.text) }
+  __ex_table_start = .;
+  .ex_table : { *(.ex_table) }
+  __ex_table_stop = .;
+  .eh_frame : { *(.eh_frame) }
+
+  . = 0xc000;
+  __bss_start = .;
+  .bss : { *(.bss) }
+  __bss_stop = .;
+  .rodata : {*(.rodata) }
+  .data : { *(.data) }
+
+}
--- a/zipl/boot/tape0.S
+++ b/zipl/boot/tape0.S
@@ -11,6 +11,8 @@ IPL_OFF			= 0x4000		# temporary kernel l
 COMMAND_LINE_SIZE	= 896			# max command line length
 KERNEL_OFF		= 0x10000		# kernel start code offset
 						# relative to image start
+__LC_IO_NEW_PSW         = 0x1f0			# IO New PSW addr
+
 
 # Parameter address offsets
 
@@ -50,12 +52,11 @@ _start:
 	.long 0x000a0000,0x00000060		# svc new psw
 	.long 0x000a0000,0x00000068		# program check new psw
 	.long 0x000a0000,0x00000070		# machine check new psw
-	.long 0x00080000,0x80000000+.Lioint	# io new psw
 
 
 # IPL parameter area
 
-	.org 0x100
+	.org 0x200
 _parm_addr:
 	.quad PARMFILE_ADDR			# parmfile load address
 _initrd_addr:
@@ -178,6 +179,23 @@ _load_psw:
 
 iplstart:
 	stm   %r0,%r15,.Lvmparamtemp		# store vm params for later use
+	basr    %r13,0
+0:
+	la      %r7,2                           #/* First try code 2: */
+	la      %r6,0                           #/* 64 bit psws are restored */
+	sigp    %r7,%r6,0x12                    #/* Switch to 64 bit */
+	bc      8,.Lswitched_64-0b(%r13)        #/* Accepted ? */
+	la      %r7,1                           #/* Failed - try code 1 */
+	sigp    %r7,%r6,0x12                    #/* Switch to 64 bit */
+.Lswitched_64:
+	sam64                                   #/* Switch to 64 bit addr mode */
+	basr    %r13,0
+1:
+	mvc    __LC_IO_NEW_PSW(16),4f-1b(%r13)    # set i/o new ps
+	b      .Lafterpsw
+4:
+	.long  0x00000001,0x80000000,0x00000000,0x00000000+.Lioint    # io new psw
+.Lafterpsw:
 	l     %r1,0xb8			 	# load rest of loader/TM
 	la    %r2,IPL_BS
 	bas   %r14,.Lloader
--- /dev/null
+++ b/zipl/boot/tape2dump.c
@@ -0,0 +1,214 @@
+/*
+ * zipl - zSeries Initial Program Loader tool
+ *
+ * Dump tool for channel-attached tape devices
+ *
+ * Copyright IBM Corp. 2013
+ * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include "stage2dump.h"
+#include "libc.h"
+#include "cio.h"
+#include "error.h"
+
+#define BLK_SIZE	0x8000 /* We write 32 KB at a time */
+#define ETAPE_WRITE	0x0003 /* Error code for failed write */
+
+#define WRITE_CMD	0x01	/* Write block */
+#define SENSE_OVERRUN	0x04	/* Sense */
+#define WRITETAPEMARK	0x1f	/* Write Tape Mark */
+#define READ_DEV_CHAR	0x64	/* Read device characteristics */
+#define LOAD_DISPLAY	0x9f	/* Load tape display */
+#define MODE_SET_DB	0xdb	/* Mode set */
+
+/*
+ * Tape head code (PSW and two CCWs to load dump tool)
+ */
+struct tape_head {
+	uint64_t	psw;
+	uint64_t	ccw1;
+	uint64_t	ccw2;
+} __packed;
+
+struct tape_head tape_head __attribute__((section(".stage2.head"))) = {
+	.psw	= 0x0008000080002018ULL, /* Start code at 0x2018 */
+	.ccw1	= 0x0700000060000001ULL, /* Rewind ccw */
+	.ccw2	= 0x0200200020003000ULL, /* CCW to load dump tool to 0x2000 */
+};
+
+/*
+ * ORB, CCW, and CCW data
+ */
+static struct orb orb = {
+	.fmt	= 1,		/* Use format 1 CCWs */
+	.c64	= 1,		/* Use IDAs */
+	.lpm	= 0xff,		/* Logical path mask */
+};
+static char ccw_data[64] __aligned(8);
+static uint32_t mode_set_byte = 0x08000000;
+static struct irb irb;
+
+/*
+ * CCW program for writes
+ */
+static struct {
+	struct ccw1	compress;
+	struct ccw1	write;
+	unsigned long	ida_list[BLK_SIZE / PAGE_SIZE];
+} ccw_program __aligned(8);
+
+/*
+ * Get device characteristics (nothing to do for tape)
+ */
+void dt_device_parm_setup(void)
+{
+}
+
+/*
+ * Enable tape device
+ */
+void dt_device_enable(void)
+{
+	io_irq_enable();
+	set_device(IPL_SC, ENABLED);
+}
+
+/*
+ * Initialize CCW
+ */
+static void ccw_init(struct ccw1 *ccw, uint8_t code, uint8_t flags,
+		     uint16_t count, void *cda)
+{
+	ccw->cmd_code = code;
+	ccw->flags = flags;
+	ccw->count = count;
+	ccw->cda = __pa32(cda);
+}
+
+/*
+ * Execute CCW
+ */
+static void start_ccw(uint8_t code, uint8_t flags, uint16_t count, void *cda)
+{
+	static struct ccw1 ccw;
+
+	ccw_init(&ccw, code, flags, count, cda);
+	orb.cpa = __pa32(&ccw);
+	start_io(IPL_SC, &irb, &orb);
+}
+
+/*
+ * Read tape device characteristics to find out if IDRC compression can be used
+ */
+static void setup_idrc_compression(void)
+{
+	uint16_t type;
+
+	start_ccw(READ_DEV_CHAR, 0x0, 0x40, ccw_data);
+
+	memcpy(&type, &ccw_data[3], sizeof(type));
+	switch (type) {
+	case 0x3490:
+	case 0x3590: // XXX 3592
+		ccw_init(&ccw_program.compress, MODE_SET_DB, CCW_FLAG_CC, 0x1,
+			 &mode_set_byte);
+		orb.cpa = __pa32(&ccw_program.compress);
+		break;
+	default:
+	case 0x3480:
+		orb.cpa = __pa32(&ccw_program.write);
+		break;
+	}
+}
+
+/*
+ * Print message on tape display
+ */
+static void ccw_load_display(const char *msg)
+{
+	char _msg[24] = {0x20};
+
+	strcpy(&_msg[1], msg);
+	start_ccw(LOAD_DISPLAY, CCW_FLAG_SLI, 0x11, (void *) _msg);
+}
+
+/*
+ * Write sense data to buffer
+ */
+static void sense(void *sense_data)
+{
+	start_ccw(SENSE_OVERRUN, CCW_FLAG_SLI, 0x20, sense_data);
+}
+
+/*
+ * Write tape mark at current tape position
+ */
+static void ccw_write_tapemark(void)
+{
+	start_ccw(WRITETAPEMARK, CCW_FLAG_SLI, 0x1, NULL);
+}
+
+/*
+ * Write buffer at current tape position
+ */
+static void ccw_write_block(unsigned long addr, unsigned long size,
+			    unsigned long zero_page)
+{
+	struct scsw *scsw = (struct scsw *) &irb;
+	unsigned long code;
+
+	create_ida_list(ccw_program.ida_list, size, addr, zero_page);
+	ccw_init(&ccw_program.write, WRITE_CMD, CCW_FLAG_SLI | CCW_FLAG_IDA,
+		 size, ccw_program.ida_list);
+	orb.cpa = __pa32(&ccw_program.write);
+	start_io(IPL_SC, &irb, &orb);
+
+	if (scsw->dstat & 0xd2) {
+		/* Something went wrong */
+		sense(ccw_data);
+		code = ccw_data[3]; /* ERA */
+		code = ETAPE_WRITE | (code << 24);
+		panic(code, "I/O Error: RC=%08x", code);
+	}
+	if (scsw->dstat & 0x01) /* Unit exception, end of tape */
+		panic(EMEM, "Device too small");
+}
+
+/*
+ * Every 16 MB we update the tape display
+ */
+static void progress_print_disp(unsigned long addr)
+{
+	char msg[24];
+
+	if (addr % (1024 * 1024 * 16) != 0)
+		return;
+	sprintf(msg, "%08u", addr >> 20);
+	ccw_load_display(msg);
+}
+
+/*
+ * Dump all memory to tape
+ */
+void dt_dump_mem(void)
+{
+	unsigned long addr, page;
+
+	page = get_zeroed_page();
+	setup_idrc_compression();
+	ccw_write_tapemark();
+
+	ccw_write_block((unsigned long) dump_hdr, DF_S390_HDR_SIZE, 0);
+	for (addr = 0; addr < dump_hdr->mem_size; addr += BLK_SIZE) {
+		ccw_write_block(addr, BLK_SIZE, page);
+		progress_print(addr);
+		progress_print_disp(addr);
+	}
+	progress_print(addr);
+	df_s390_em_page_init(page);
+	ccw_write_block(page, sizeof(struct df_s390_em), 0);
+	free_page(page);
+	ccw_write_tapemark();
+	ccw_load_display("DUMP*END");
+}
--- a/zipl/boot/tapedump.S
+++ /dev/null
@@ -1,875 +0,0 @@
-/*
- *  Dump boot loader for 3480/3490 tape devices
- *    Copyright IBM Corp. 1999, 2006.
- *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
- *               Martin Schwidefsky (schwidefsky@de.ibm.com)
- *
- * Uses extern functions:
- *  - _panik
- *  - _enable_device
- *  - _take_dump
- *  - _ssch
- *  - _wait4de
- *
- * Functions:
- *  - _dump_mem
- */
-
-#include "dumpcommon.S"
-#if defined(__s390x__)
-#define USE_64BIT_SCLP
-#endif
-#include "sclp.S"
-
-#define IPL_BS           0x2000
-#define BLOCK_SIZE       0x8000 /* 32 KB */
-#define DUMP_TOOL_START  0x2000 /* tool is loaded to this address in order */
-                                /* not to overwrite page 0 */
-/* Tape display messages */
-
-#ifdef LOWER_CASE 
-#define DISP_DUMP_END   0x2084a494,0x975c8595,0x84000000 /* dump*end */
-#else
-#define DISP_DUMP_END   0x20c4e4d4,0xd75cc5d5,0xc4000000 /* DUMP*END */
-#endif
-
-#define DISP_COUNT_SHIFT 24 /* all 16 MB display is changed */
-
-/* Error codes */
-
-#define ETAPE_REWUNL_1  0x00000001
-#define ETAPE_REWUNL_2  0x00000002
-#define ETAPE_WRITE     0x0003
-
-/* Tape types */
-
-#define TAPE_UNKNOWN 1
-#define TAPE_3590    2
-#define TAPE_3480    3 
-#define TAPE_3490    4
-
-################################################################################
-# The first 24 bytes are loaded by ipl to addresses 0-23. (a PSW and two CCWs)
-################################################################################
-
-        # psw  
-        .long  0x00080000,0x80000000+_start
-        # rewind ccw
-        .long  0x07000000,0x60000001
-        # ccw to load dump utility to 0x2000
-        .long  0x02000000+DUMP_TOOL_START ,0x20000000+IPL_BS
-
-
-#if defined(__s390x__)
-
-/******************************** 64 BIT **************************************/ 
-
-.globl _start
-_start: 
-        basr  %r13,0
-.Linit_base:
-        xc    .Ldh_arch-.Linit_base(4,%r13),.Ldh_arch-.Linit_base(%r13)
-        l     %r15,1f-.Linit_base(%r13)       # load end of stack address
-        tm    __LC_ARCH_MODE_ID(%r0),0x01     # check arch mode
-        bnz   .Larch_64-.Linit_base(%r13)
-
-        /* 32 bit store status */
-
-        larl  %r14,.Lstore_status_32
-        basr  %r14,%r14
-	mvi   .Ldh_arch+3-.Linit_base(%r13),ARCH_S390_ID
-.Larch_64:
-        la    %r7,2                             # first try code 2:
-        la    %r6,0                             # 64 bit psws are restored
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-        bc    8,.Lswitched_64-.Linit_base(%r13) # order accepted ?
-        la    %r7,1                             # code 2 failed - try code 1
-        sigp  %r7,%r6,0x12                      # switch to 64 bit
-.Lswitched_64:
-        sam64                                   # switch to 64 bit addr mode
-        basr   %r13,0
-0:      llgf   %r15,1f-0b(%r13)                 # load end of stack address
-
-        llgf   %r10,.Ldh_arch-0b(%r13)
-        cghi   %r10,ARCH_S390_ID
-        be     .Larch_32-0b(%r13)
-
-        /* 64 bit store status */
-
-        larl   %r14,_store_status_64
-        basr   %r14,%r14
-        lghi   %r10,ARCH_S390X_ID
-        st     %r10,.Ldh_arch-0b(%r13)
-.Larch_32:
-        llgf   %r2,IPL_SC                     # load ipl device subchannel id
-        larl   %r14,_enable_device_64
-        basr   %r14,%r14
-        bas    %r14,_get_device_characteristics_64-0b(%r13)
-        larl   %r14,_take_dump_64
-        basr   %r14,%r14
-1:      .long  0x10000-128                    # end of stack
-
-################################################################################
-# Dump memory
-#  - no parameters
-################################################################################
-
-_dump_mem_64:
-        stmg   %r6,%r15,48(%r15)
-        basr   %r13,0                         # base register
-0:      aghi   %r15,-200                      # create stack frame
-
-#
-# first write a tape mark
-#
-        bas   %r14,_tapemark_64-0b(%r13)
-
-# init progress bar
-
-        bras %r14,_init_print_progress_64
-
-#
-# write header
-#
-        lghi  %r2,HEADER_PAGE_START
-        lghi  %r3,HEADER_SIZE                 # size of header
-        lgr   %r4,%r3                         # blocksize 
-        bas   %r14,_writer_64-0b(%r13)
-        
-#
-# write real storage to tape
-#       
-        lg    %r10,.Ldh_mem_size-0b(%r13)     # length
-        lgr   %r12,%r10                       # save mem size
-        lghi  %r11,0                          # start
-
-        lgr   %r2,%r11                        # start
-        lgr   %r3,%r10                        # length
-        llgf  %r4,.Lblock_size-0b(%r13)       # blocksize
-        bas   %r14,_writer_64-0b(%r13)        # write page
-
-        clgr  %r2,%r12
-        bhe   1f-0b(%r13)
-
-        # Cartridge full
-
-        la    %r2,EMEM
-        larl  %r14,_panik_64
-        basr  %r14,%r14
-
-1:      # All memory written
-
-#
-# write end marker
-#
-        stck  .Ld_end_time-0b(%r13)           # store end time
-        lghi  %r2, TMP_PAGE_START
-        mvc   0(256,%r2),.Ld_endmarker-0b(%r13) # move to 4k boundary
-        lghi  %r3,END_MARKER_SIZE             # size of end marker
-        lghi  %r4,END_MARKER_SIZE             # blocksize
-        bas   %r14,_writer_64-0b(%r13)
-#
-# write another tape mark
-#
-        bas   %r14,_tapemark_64-0b(%r13)
-
-        la    %r2,.Lend_text-0b(%r13)
-        bas   %r14,_load_display_64-0b(%r13)
-
-        lmg   %r6,%r15,248(%r15)
-        br    %r14                            # return to caller
-.Lblock_size:
-        .long BLOCK_SIZE
-.Lend_text:
-        .long DISP_DUMP_END
-
-################################################################################
-# subroutine for writing to tape
-# Parameters:   
-#  -r2: start address
-#  -r3: length
-#  -r4: blocksize
-################################################################################
-
-_writer_64:        
-        stmg  %r6,%r15,48(%r15)
-        basr  %r13,0                           # base register
-0:      aghi  %r15,-200                        # create stack frame
-
-        lgr    %r10,%r2                        # save start address
-        lgr    %r11,%r3                        # save length
-        agr    %r11,%r2                        # end address
-        lgr    %r12,%r4                        # save blocksize
-        lgr    %r8,%r2                         # mb counter = start
-
-	# setup idrc
-
-        la    %r7,.Lccwwrite-0b(%r13)
-        st    %r7,8+.Lorbwrite-0b(%r13)
-        lh    %r7,.Luse_idrc-0b(%r13)
-        chi   %r7,1
-        bne   .Lnocomp-0b(%r13)
-        la    %r7,.Lccwwrite_compressed-0b(%r13)
-        st    %r7,8+.Lorbwrite-0b(%r13)
-
-	# setup idas 
-
-.Lnocomp:
-
-        la    %r9,.Ltmp_data-0b(%r13)
-        st    %r9,.Lccwwrite+4-0b(%r13)        # initialize CCW data addresses
-        sth   %r12,.Lccwwrite+2-0b(%r13)       # setup blocksize
-.Lldlp:
-        lgr   %r2,%r10                         # start address
-        lgr   %r3,%r12                         # size = blocksize
-        la    %r4,.Ltmp_data-0b(%r13)
-        bas   %r14,_create_ida_list_64-0b(%r13)
-
-        llgf  %r2,IPL_SC                       # subchannel id
-        la    %r3,.Lorbwrite-0b(%r13)          # address of orb
-        la    %r4,.Lirb-0b(%r13)               # address of irb
-        lghi  %r5,10                           # 10 retries
-        bas   %r14,_ssch_64-0b(%r13)           # write chunk of PAGE_SIZE bytes
-
-
-        la    %r4,.Lirb-0b(%r13)
-        tm    8(%r4),0xd2                      # something went wrong ?
-        bz    .check_ue-0b(%r13)
-
-        /* fatal write error */
-
-        llgf  %r2,IPL_SC
-        la    %r3,.Lorbsense-0b(%r13)
-        la    %r4,.Lirb-0b(%r13)
-        lghi  %r5,1
-        bas   %r14,_ssch_64-0b(%r13)
-
-        /* build error code: first byte ERA, last byte our error code */
-
-        llgc  %r2,.Ltmp_data+3-0b(%r13)      # get ERA
-        sll   %r2,24                           # move it to first byte
-        ahi   %r2,ETAPE_WRITE
-
-        llgf  %r14,.Lpanik_64-0b(%r13)
-        basr  %r14,%r14
-
-.check_ue:
-
-        tm    8(%r4),0x1                       # unit exception ?
-        bz    1f-0b(%r13)
-
-        # unit exception: We reached End of Tape
-
-        la    %r2,0(%r12,%r10)                 # r2 contains next write addr
-        b     3f-0b(%r13)                      # return
-
-1:
-        # write was ok:
-
-        cgr   %r10,%r8
-        bl    2f-0b(%r13)
-
-
-        srlg  %r2,%r10,20                      # change display
-        la    %r3,.Ldump_text+1-0b(%r13)
-        bas   %r14,_hex_to_ebcdic_64-0b(%r13)
-        la    %r2,.Ldump_text-0b(%r13)
-        bas   %r14,_load_display_64-0b(%r13)
-
-        lghi  %r2,1
-        sll   %r2,DISP_COUNT_SHIFT
-        agr   %r8,%r2                          # update mb counter (+16MB)
-2:
-        agr   %r10,%r12                        # add block size
-
-        lgr   %r2,%r10                         # print progress to console
-        bras  %r14,_print_progress_64
-
-        clgr  %r10,%r11                        # enough ?
-        bl    .Lldlp-0b(%r13)
-
-        lgr   %r2,%r10                         # return value
-3:
-        lmg   %r6,%r15,248(%r15)
-        br    %r14                             
-
-        .align 8
-.Lorbwrite:
-        .long  0x00000000,0x0082ff00,.Lccwwrite
-        .align 8
-.Lorbsense:
-        .long  0x00000000,0x0080ff00,.Lccwsense
-        .align 8
-.Lccwwrite_compressed: /* note that 3480 does not support IDRC */
-	.long  0xdb400001,.Lmodsetbyte
-.Lccwwrite:
-        .long  0x01240000,0x00000000
-.Ldump_text:
-        .long  0x20000000,0x00000000,0x00000000
-.Lmodsetbyte:
-	.long  0x08000000
-	.align 8
-.Lccwsense:
-        .long  0x04200020,.Ltmp_data
-################################################################################
-#  Translate binary hex to decimal ebcdic
-#   -r2: value (bin)
-#   -r3: outbuffer (ebcdic - decimal)
-################################################################################
-
-_hex_to_ebcdic_64:
-        stmg  %r6,%r15,48(%r15)
-        basr  %r13,0                           # base register
-0:      aghi  %r15,-200                        # create stack frame
-        cvd   %r2,.Lout_packed-0b(%r13)        # convert to packed decimal
-        unpk  0(8,%r3),.Lout_packed+4-0b(4,%r13)
-        oi    7(%r3),0xf0                      # remove signed flag
-        lmg   %r6,%r15,248(%r15)
-        br    %r14
-.Lout_packed:
-        .long 0x0,0x0
-
-################################################################################
-# subroutine for reading the device characteristics
-################################################################################
-
-_get_device_characteristics_64:
-        stmg   %r6,%r15,48(%r15)
-        basr   %r13,0                   # base register
-0:      aghi   %r15,-200                # create stack frame
-        llgf   %r2,IPL_SC
-        la     %r3,.Lorb_read_cc-0b(%r13)
-        la     %r4,.Lirb-0b(%r13)
-        lghi   %r5,2
-        bas    %r14,_ssch_64-0b(%r13)   # start I/O: Read device characteristic
-
-        # find out device type
-
-        lhi     %r6,TAPE_3480
-	lhi     %r7,0                   # idrc off
-        clc     .Ltmp_data+3-0b(2,%r13),.L3480-0b(%r13)
-        be      1f-0b(%r13)
-
-        lhi     %r6,TAPE_3490
-	lhi     %r7,1                   # idrc on
-        clc     .Ltmp_data+3-0b(2,%r13),.L3490-0b(%r13)
-        be      1f-0b(%r13) 
-
-        lhi     %r6,TAPE_3590
-	lhi     %r7,1                   # idrc on
-        clc     .Ltmp_data+3-0b(2,%r13),.L3590-0b(%r13)
-        be      1f-0b(%r13)
-
-	lhi     %r6,TAPE_UNKNOWN
-	lhi     %r7,0                   # idrc off
-1:
-	sth     %r6,.Ltape_type-0b(%r13)
-	sth     %r7,.Luse_idrc-0b(%r13)
-	lmg	%r6,%r15,248(%r15)
-        br	%r14
-
-.align 8
-.Lorb_read_cc:
-        .long  0x00000000,0x0080ff00,.Lrdcccw
-        .align 8
-.Lrdcccw:
-        .long 0x64000040,0x00000000+.Ltmp_data    # read device characteristics
-.L3590:
-        .word   0x3590
-.L3480:
-        .word   0x3480
-.L3490:
-        .word   0x3490
-
-################################################################################
-# subroutine for writing to tape display
-#  -r2: start address of text
-################################################################################
-
-_load_display_64:
-        stmg    %r6,%r15,48(%r15)
-        basr    %r13,0                        # base register
-0:      aghi    %r15,-200                     # create stack frame
-        st    %r2,.Lccwload_disp+4-0b(%r13)   # store text field
-        l     %r2,IPL_SC                      # subchannel id
-        la    %r3,.Lorbload_disp-0b(%r13)     # address of orb
-        la    %r4,.Lirb-0b(%r13)              # address of irb
-        lghi  %r5,1                           # no retry
-        bas   %r14,_ssch_64-0b(%r13)          # load the display
-        lmg   %r6,%r15,248(%r15)
-        br    %r14
-.align 8
-.Lorbload_disp:
-        .long  0x00000000,0x0080ff00,.Lccwload_disp
-        .align 8
-.Lccwload_disp:
-        .long  0x9f200011,0x00000000
-
-
-################################################################################
-# write tapemark
-#  - no parameters
-################################################################################
-
-_tapemark_64:
-        stmg  %r6,%r15,48(%r15)
-        basr  %r13,0                           # base register
-0:      aghi  %r15,-200                        # create stack frame
-
-        llgf  %r2,IPL_SC                       # subchannel id
-        la    %r3,.Lorbmark-0b(%r13)           # r12 = address of orb
-        la    %r4,.Lirb-0b(%r13)               # r5 = address of irb
-        la    %r5,10                           # retries
-        bas   %r14,_ssch_64-0b(%r13)           # write a tape mark
-
-        lmg   %r6,%r15,248(%r15)
-        br    %r14                             # return to caller
-        .align 8
-.Lorbmark:
-        .long  0x00000000,0x0080ff00,.Lccwmark
-        .align 8
-.Lccwmark:
-        .long  0x1f200001,0x00000000
-
-################################################################################
-# expand Macros
-################################################################################
-
-	hex_to_ebcdic
-	print_progress_64
-        dump_common_store_status_32
-        dump_common_fn_64
-        dump_io_subroutines_64
-	dump_idal_64
-        dump_header
-	dump_messages
-	sclp_base
-	sclp_print
-	sclp_read_info
-	tmp_data
-
-# extern functions
- 
-.Lpanik_64:
-        .long      _panik_64
-.Lenable_device_64:
-        .long      _enable_device_64
-.Ltake_dump_64:
-        .long      _take_dump_64
-.Lstore_status_32:
-        .long      _store_status_32
-.Lstore_status_64:
-        .long      _store_status_64
-
-#else /* __s390x__ */
- 
-
-
-/******************************** 32 BIT **************************************/
-
-
-.globl _start
-_start: basr   %r13,0
-0:      l      %r15,1f-0b(%r13)               # load end of stack address
-
-	tm    __LC_ARCH_MODE_ID,0x01          # check arch mode
-	bz   .Larch_31-0b(%r13)
-	la    %r10,ARCH_S390X_ID
-	st    %r10,.Ldh_arch-0b(%r13)
-
-.Larch_31:
-        l      %r11,IPL_SC                    # load ipl device subchannel id
-        lr     %r2,%r11
-        l      %r14,.Lenable_device_32-0b(%r13)
-        basr   %r14,%r14
-	bas    %r14,_get_device_characteristics_32-0b(%r13)
-        l      %r14,.Ltake_dump_32-0b(%r13)
-        basr   %r14,%r14
-1:      .long  0x10000-96                     # end of stack
-
-################################################################################
-# Dump memory
-################################################################################
-
-_dump_mem_32:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                         # base register
-0:      ahi    %r15,-96                       # create stack frame
-
-#
-# first write a tape mark
-#
-        bas   %r14,_tapemark_32-0b(%r13)
-
-# init progress bar
-
-        bras %r14,_init_print_progress_32
-
-#
-# write header
-#
-        lhi   %r2,HEADER_PAGE_START
-        mvc   0(256,%r2),.Ldh_dumpheader-0b(%r13) # move to 4k boundary
-        lhi   %r3,HEADER_SIZE                 # size of header
-        lr    %r4,%r3                         # blocksize 
-        bas   %r14,_writer_32-0b(%r13)
-        
-#
-# write real storage to tape
-#       
-        l     %r10,.Ldh_mem_size+4-0b(%r13)   # length
-        lr    %r12,%r10                       # save mem size
-        la    %r11,0                          # start
-
-        lr    %r2,%r11                        # start
-        lr    %r3,%r10                        # length
-        l     %r4,.Lblock_size-0b(%r13)       # blocksize
-        bas   %r14,_writer_32-0b(%r13)        # write page
-
-        clr   %r2,%r12
-        bhe   1f-0b(%r13)
-
-        # Cartridge full
-
-        la    %r2,EMEM
-        larl  %r14,_panik_32
-        basr  %r14,%r14
-
-1:      # All memory written
-#
-# write end marker
-#
-        stck  .Ld_end_time-0b(%r13)           # store end time
-        lhi   %r2, TMP_PAGE_START
-        mvc   0(256,%r2),.Ld_endmarker-0b(%r13) # move to 4k boundary
-        la    %r3,END_MARKER_SIZE             # size of end marker
-        la    %r4,END_MARKER_SIZE             # blocksize
-        bas   %r14,_writer_32-0b(%r13)
-#
-# write another tape mark
-#
-        bas   %r14,_tapemark_32-0b(%r13)
-
-        la    %r2,.Lend_text-0b(%r13)
-        bas   %r14,_load_display_32-0b(%r13)
-
-        lm    %r6,%r15,120(%r15)
-        br    %r14                            # return to caller
-.Lblock_size:       
-        .long BLOCK_SIZE
-.Lend_text:
-        .long DISP_DUMP_END
-
-################################################################################# _init_tape
-################################################################################
-
-_init_tape_32:
-        stm   %r6,%r15,24(%r15)
-        basr  %r13,0                           # base register
-0:      ahi   %r15,-96                         # create stack frame
-
-        l     %r2,IPL_SC                       # subchannel id
-        la    %r3,.Lorbmode_set-0b(%r13)
-        la    %r4,.Lirb-0b(%r13)
-        la    %r5,2
-        bas    %r14,_ssch_32-0b(%r13)
-        lm    %r6,%r15,120(%r15)
-        br    %r14                             # return to caller
-.align 8
-.Lorbmode_set:
-        .long  0x00000000,0x0080ff00,.Lccwmode_set
-        .align 8
-.Lccwmode_set:
-        .long  0xdb200001,.Lmode_set
-.Lmode_set:
-        .long  0x00000000 /* buffered mode + IDRC */
-
-################################################################################
-# subroutine for writing to tape
-# Parameters:   
-#  -r2: start address
-#  -r3: length
-#  -r4: blocksize
-#
-# Returns:
-#  -r2: up to this address we have written the memory
-################################################################################
-
-_writer_32:        
-        stm   %r6,%r15,24(%r15)
-        basr  %r13,0                           # base register
-0:      ahi   %r15,-96                         # create stack frame
-
-        lr    %r10,%r2                         # save start address
-        lr    %r11,%r3                         # save length
-        ar    %r11,%r2                         # end address
-        lr    %r12,%r4                         # save blocksize 
-        lr    %r8,%r2                          # mb counter = start
-
-	# setup idrc
-
-	la    %r7,.Lccwwrite-0b(%r13)
-	st    %r7,8+.Lorbwrite-0b(%r13)
-	lh    %r7,.Luse_idrc-0b(%r13)
-	chi   %r7,1
-	bne   .Lnocomp-0b(%r13)
-	la    %r7,.Lccwwrite_compressed-0b(%r13)
-        st    %r7,8+.Lorbwrite-0b(%r13)
-
-.Lnocomp:
-
-        la    %r9,.Ltmp_data-0b(%r13)
-        st    %r9,.Lccwwrite+4-0b(%r13)        # initialize CCW data addresses
-        sth   %r12,.Lccwwrite+2-0b(%r13)       # setup blocksize
-.Lldlp:
-
-        lr    %r2,%r10                         # start address
-	lr    %r3,%r12                         # size = blocksize
-	la    %r4,.Ltmp_data-0b(%r13)
-        bas   %r14,_create_ida_list_32-0b(%r13)
-
-        l     %r2,IPL_SC                       # subchannel id
-        la    %r3,.Lorbwrite-0b(%r13)          # address of orb
-        la    %r4,.Lirb-0b(%r13)               # address of irb
-        la    %r5,10                           # 10 retries
-        bas   %r14,_ssch_32-0b(%r13)           # write chunk of PAGE_SIZE bytes
-
-
-        la    %r4,.Lirb-0b(%r13)
-        tm    8(%r4),0xd2                      # something went wrong ?
-        bz    .check_ue-0b(%r13)
-
-        /* fatal write error */
-
-        l     %r2,IPL_SC
-        la    %r3,.Lorbsense-0b(%r13)
-        la    %r4,.Lirb-0b(%r13)
-        la    %r5,1
-        bas   %r14,_ssch_32-0b(%r13)
-
-        /* build error code: first byte ERA, last byte our error code */ 
-
-        la    %r2,0 
-        ic    %r2,.Ltmp_data+3-0b(%r13)      # get ERA
-        sll   %r2,24                           # move it to first byte 
-        ahi   %r2,ETAPE_WRITE
- 
-        l     %r14,.Lpanik_32-0b(%r13)
-        basr  %r14,%r14
-
-.check_ue:
-
-        tm    8(%r4),0x1                       # unit exception ?
-        bz    1f-0b(%r13)
-
-        # unit exception: We reached End of Tape
-
-        lr    %r2,%r10                         # r2 contains
-        ar    %r2,%r12                         # next write addr 
-        b     3f-0b(%r13)                      # return
-
-
-1:       
-        # write was ok:
-
-        clr   %r10,%r8                         # one mb written ?
-        bl    2f-0b(%r13)
-
-         
-        srl   %r2,20                           # change display
-        la    %r3,.Ldump_text+1-0b(%r13) 
-        bas   %r14,_hex_to_ebcdic_32-0b(%r13)
-        la    %r2,.Ldump_text-0b(%r13)
-        bas   %r14,_load_display_32-0b(%r13)
-
-        la    %r2,1
-        sll   %r2,DISP_COUNT_SHIFT
-        ar    %r8,%r2                          # update mb counter (+16 MB)
-
-2:
-        ar    %r10,%r12                        # add block size
-
-        lr    %r2,%r10                         # print progress to console
-        bras  %r14,_print_progress_32
-
-        clr   %r10,%r11                        # enough ?
-        bl    .Lldlp-0b(%r13)
-        lr    %r2,%r10                         # return value
-3:
-        lm    %r6,%r15,120(%r15)
-        br    %r14                             
-        .align 8
-.Lorbwrite:
-        .long  0x00000000,0x0080ff00,.Lccwwrite
-        .align 8
-.Lorbsense:
-        .long  0x00000000,0x0080ff00,.Lccwsense
-        .align 8
-.Lccwwrite_compressed: /* note that 3480 does not support IDRC */ 
-        .long  0xdb400001,.Lmodsetbyte
-.Lccwwrite:
-        .long  0x01240000,0x00000000
-.Ldump_text:
-        .long  0x20000000,0x00000000,0x00000000
-.Lmodsetbyte:
-        .long  0x08000000
-.Lccwsense:
-        .long  0x04200020,.Ltmp_data
-
-################################################################################
-#  Translate binary hex to decimal ebcdic
-#   -r2: value (bin)
-#   -r3: outbuffer (ebcdic - decimal)
-################################################################################ 
-
-_hex_to_ebcdic_32:
-        stm  %r6,%r15,24(%r15)
-        basr  %r13,0                           # base register
-0:      ahi   %r15,-96                         # create stack frame
-        cvd   %r2,.Lout_packed-0b(%r13)        # convert to packed decimal
-        unpk  0(8,%r3),.Lout_packed+4-0b(4,%r13) 
-        oi    7(%r3),0xf0                      # remove signed flag
-        lm    %r6,%r15,120(%r15)
-        br    %r14
-.Lout_packed:
-        .long 0x0,0x0
-
-################################################################################# subroutine for reading the device characteristics
-################################################################################ 
-_get_device_characteristics_32:
-	stm    %r6,%r15,24(%r15)
-        basr   %r13,0                   # base register
-0:      ahi    %r15,-96                 # create stack frame
-        l      %r2,IPL_SC
-        la     %r3,.Lorb_read_cc-0b(%r13)
-        la     %r4,.Lirb-0b(%r13)
-        la     %r5,2
-        bas    %r14,_ssch_32-0b(%r13)   # start I/O: Read device characteristic
- 
-        # find out device type
-
-	la      %r6,TAPE_3480
-        la      %r7,0                   # idrc off
-        clc     .Ltmp_data+3-0b(2,%r13),.L3480-0b(%r13)
-        be      1f-0b(%r13) 
-
-	la      %r6,TAPE_3490
-        la      %r7,1                   # idrc on
-        clc     .Ltmp_data+3-0b(2,%r13),.L3490-0b(%r13)
-        be      1f-0b(%r13)
-
-        la      %r6,TAPE_3590
-	la      %r7,1                   # idrc on
-        clc     .Ltmp_data+3-0b(2,%r13),.L3590-0b(%r13)
-        be      1f-0b(%r13)
- 
-        la      %r6,TAPE_UNKNOWN
-	la      %r7,0                   # idrc off
-1:
-        sth     %r6,.Ltape_type-0b(%r13)
-	sth     %r7,.Luse_idrc-0b(%r13)
-	lm      %r6,%r15,120(%r15)
-        br      %r14
- 
-.align 8
-.Lorb_read_cc:
-        .long  0x00000000,0x0080ff00,.Lrdcccw
-        .align 8
-.Lrdcccw:
-        .long 0x64000040,0x00000000+.Ltmp_data    # read device characteristics
-.L3590:
-        .word   0x3590
-.L3480:
-        .word   0x3480
-.L3490:
-        .word   0x3490
-
-################################################################################
-# subroutine for writing to tape display
-#  -r2: start address of text
-################################################################################
-
-_load_display_32:
-        stm    %r6,%r15,24(%r15)
-        basr   %r13,0                         # base register
-0:      ahi    %r15,-96                       # create stack frame
-        st    %r2,.Lccwload_disp+4-0b(%r13)   # store text field
-        l     %r2,IPL_SC                      # subchannel id
-        la    %r3,.Lorbload_disp-0b(%r13)     # address of orb
-        la    %r4,.Lirb-0b(%r13)              # address of irb
-        la    %r5,1                           # no retry
-        bas   %r14,_ssch_32-0b(%r13)          # load the display
- 
-        lm    %r6,%r15,120(%r15)
-        br    %r14
-.align 8
-.Lorbload_disp:
-        .long  0x00000000,0x0080ff00,.Lccwload_disp
-        .align 8
-.Lccwload_disp:
-        .long  0x9f200011,0x00000000
-
-################################################################################
-# write tapemark
-#  - no parameters
-################################################################################
-
-_tapemark_32:
-        stm   %r6,%r15,24(%r15)
-        basr  %r13,0                           # base register
-0:      ahi   %r15,-96                         # create stack frame
-
-        l     %r2,IPL_SC                       # subchannel id
-        la    %r3,.Lorbmark-0b(%r13)           # r3 = address of orb
-        la    %r4,.Lirb-0b(%r13)               # r4 = address of irb
-        la    %r5,10                           # retries
-        bas   %r14,_ssch_32-0b(%r13)           # write a tape mark
-
-        lm    %r6,%r15,120(%r15)
-        br    %r14                             # return to caller
-        .align 8
-.Lorbmark:
-        .long  0x00000000,0x0080ff00,.Lccwmark
-        .align 8
-.Lccwmark:
-        .long  0x1f200001,0x00000000
-
-################################################################################
-# expand Macros
-################################################################################
-
-	hex_to_ebcdic
-	print_progress_32
-	dump_common_fn_32
- 	dump_io_subroutines_32
-	dump_idal_32
-	dump_messages
-	dump_header
-	sclp_base
-	sclp_print
-	sclp_read_info
-	tmp_data
-
-# extern functions
- 
-.Lpanik_32:
-        .long      _panik_32
-.Lenable_device_32:
-        .long      _enable_device_32
-.Ltake_dump_32:
-        .long      _take_dump_32
-     
-#endif /* __s390x__ */
-
-################################################################################
-# DATA
-################################################################################
-
-.Ltape_type: .word 0 /* 3480/90 3590 etc. */
-.Luse_idrc:  .word 1 /* 1 -> use idrc compression */
-                     /* 0 -> do not use idrc (e.g. for 3480 not allowed) */
-
-.Lirb:  .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-.org IPL_BS-8
-.Lmem_upper_limit:
-        .long 0xffffffff,0xffffffff              # can be used for memsize=xxx
--- a/zipl/include/boot.h
+++ b/zipl/include/boot.h
@@ -18,12 +18,139 @@
 #include "disk.h"
 #include "job.h"
 
+#define STAGE2_BLK_CNT_MAX	24 /* Stage 1b can load up to 24 blocks */
+#define STAGE1B_BLK_CNT_MAX	2  /* Stage 1 can load up to 2 blocks */
+
+/* Boot info */
+
+#define BOOT_INFO_VERSION		1
+#define BOOT_INFO_MAGIC			"zIPL"
+
+#define BOOT_INFO_DEV_TYPE_ECKD		0x00
+#define BOOT_INFO_DEV_TYPE_FBA		0x01
+#define BOOT_INFO_DEV_TYPE_SCSI         0x02
+
+#define BOOT_INFO_BP_TYPE_IPL		0x00
+#define BOOT_INFO_BP_TYPE_DUMP		0x01
+
+#ifdef __s390x__
+#define BOOT_INFO_FLAGS_ARCH		0x01
+#else
+#define BOOT_INFO_FLAGS_ARCH		0x00
+#endif
+
+/* SCSI dump super block */
+
+struct scsi_dump_sb {
+	uint64_t        magic;
+	uint64_t        version;
+	uint64_t        part_start;
+	uint64_t        part_size;
+	uint64_t        dump_offset;
+	uint64_t        dump_size;
+	uint64_t        csum_offset;
+	uint64_t        csum_size;
+	uint64_t        csum;
+} __attribute((packed));
+
+#define SCSI_DUMP_SB_MAGIC	0x5a46435044554d50ULL; /* ZFCPDUMP */
+/* To avoid a csum entry of 0 a seed is used */
+#define SCSI_DUMP_SB_SEED	0x12345678
+#define SCSI_DUMP_SB_CSUM_SIZE  4096
+
+/* SCSI dump parameter */
+
+struct scsi_dump_param {
+	uint64_t block;
+	uint64_t reserved;
+} __attribute((packed));
+/* ECKD dump parameter */
+
+struct eckd_dump_param {
+	uint32_t	start_blk;
+	uint32_t	end_blk;
+	uint16_t	blocksize;
+	uint8_t		num_heads;
+	uint8_t		bpt;
+	char		reserved[4];
+} __attribute((packed, may_alias));
+
+/* FBA dump parameter */
+
+struct fba_dump_param {
+	uint64_t	start_blk;
+	uint64_t	blockct;
+} __attribute((packed));
+
+struct boot_info_bp_dump {
+	union {
+		struct eckd_dump_param eckd;
+		struct fba_dump_param fba;
+		struct scsi_dump_param scsi;
+	} param;
+	uint8_t		unused[16];
+} __attribute__ ((packed));
+
+/*
+ * Layout of block pointer for linear devices
+ * e.g. SCSI
+ */
+/* Layout of SCSI disk block pointer */
+struct linear_blockptr {
+	uint64_t blockno;
+	uint16_t size;
+	uint16_t blockct;
+	uint8_t reserved[4];
+} __attribute((packed));
+
+/*
+ * Layout of block pointer for cylinder/head/sector devices
+ * e.g. SCSI or FBA
+ */
+/* Layout of ECKD disk block pointer */
+struct eckd_blockptr {
+	uint16_t cyl;
+	uint16_t head;
+	uint8_t sec;
+	uint16_t size;
+	uint8_t blockct;
+	uint8_t reserved[8];
+} __attribute((packed));
+
+struct boot_info_bp_ipl {
+	union {
+		struct eckd_blockptr eckd;
+		struct linear_blockptr lin;
+	} bm_ptr;
+	uint8_t		unused[16];
+} __attribute__ ((packed));
+
+struct boot_info {
+	char		magic[4];
+	uint8_t		version;
+	uint8_t		bp_type;
+	uint8_t		dev_type;
+	uint8_t		flags;
+	union {
+		struct boot_info_bp_dump dump;
+		struct boot_info_bp_ipl ipl;
+	} bp;
+} __attribute__ ((packed));
+
+struct boot_ccw0 {
+	uint8_t cmd;
+	uint8_t address_hi;
+	uint16_t address_lo;
+	uint8_t flags;
+	uint8_t pad;
+	uint16_t count;
+} __attribute__ ((packed));
 
 /* Boot data structures for FBA disks */
 
 struct boot_fba_locread {
-	uint64_t locate;
-	uint64_t read;
+	struct boot_ccw0 locate;
+	struct boot_ccw0 read;
 } __attribute__ ((packed));
 
 struct boot_fba_locdata {
@@ -34,27 +161,24 @@ struct boot_fba_locdata {
 } __attribute__ ((packed));
 
 struct boot_fba_stage0 {
-	uint64_t PSW;
-	uint64_t READ;
-	uint64_t TIC;
-	uint64_t param1;
-	uint64_t param2;
-	struct boot_fba_locread locread[16];
-	struct boot_fba_locdata locdata[16];
+	uint64_t psw;
+	uint64_t read_ipl;
+	uint64_t tic1;
+	struct boot_fba_locread locread[2];
+	uint64_t tic1b;
+	struct boot_fba_locdata locdata[2];
+	uint64_t reserved[4];
+	struct boot_info boot_info;
 } __attribute__ ((packed));
 
+struct boot_fba_stage1b {
+	struct boot_fba_locread locread[STAGE2_BLK_CNT_MAX];
+	struct boot_fba_locdata locdata[STAGE2_BLK_CNT_MAX];
+	uint8_t unused[448];
+} __attribute__ ((packed));
 
 /* Boot data structures for ECKD disks */
 
-struct boot_eckd_ccw0 {
-	uint8_t cmd;
-	uint8_t address_hi;
-	uint16_t address_lo;
-	uint8_t flags;
-	uint8_t pad;
-	uint16_t count;
-} __attribute__ ((packed));
-
 struct boot_eckd_ccw1 {
 	uint8_t cmd;
 	uint8_t flags;
@@ -63,10 +187,10 @@ struct boot_eckd_ccw1 {
 } __attribute__ ((packed));
 
 struct boot_eckd_ssrt {
-	struct boot_eckd_ccw0 seek;
-	struct boot_eckd_ccw0 search;
-	struct boot_eckd_ccw0 tic;
-	struct boot_eckd_ccw0 read;
+	struct boot_ccw0 seek;
+	struct boot_ccw0 search;
+	struct boot_ccw0 tic;
+	struct boot_ccw0 read;
 } __attribute__ ((packed));
 
 struct boot_eckd_seekarg {
@@ -77,29 +201,30 @@ struct boot_eckd_seekarg {
 	uint8_t pad2;
 } __attribute__ ((packed));
 
-struct boot_eckd_stage0 {
+struct boot_eckd_cdl_stage0 {
 	uint64_t psw;
-	struct boot_eckd_ccw0 read;
-	struct boot_eckd_ccw0 tic;
+	struct boot_ccw0 read;
+	struct boot_ccw0 tic;
 } __attribute__ ((packed));
 
-struct boot_eckd_classic_stage1 {
-	uint64_t param1;
-	uint64_t param2;
-	struct boot_eckd_ssrt ssrt[8];
-	struct boot_eckd_seekarg seek[8];
-} __attribute__ ((packed));
-
-struct boot_eckd_compatible_stage1 {
-	uint64_t param1;
-	uint64_t param2;
-	struct boot_eckd_ccw0 seek;
-	struct boot_eckd_ccw0 search;
-	struct boot_eckd_ccw0 tic;
-	struct boot_eckd_ccw0 read[12];
-	struct boot_eckd_seekarg seekarg;
+struct boot_eckd_ldl_stage0 {
+	uint64_t psw;
+	struct boot_ccw0 read_r0;
+	struct boot_ccw0 read_r1;
 } __attribute__ ((packed));
 
+struct boot_eckd_stage1 {
+	struct boot_eckd_ssrt ssrt[2];
+	struct boot_ccw0 tic1b;
+	struct boot_eckd_seekarg seek[2];
+	struct boot_info boot_info;
+} __attribute__ ((packed));
+
+struct boot_eckd_stage1b {
+	struct boot_eckd_ssrt ssrt[STAGE2_BLK_CNT_MAX];
+	struct boot_eckd_seekarg seek[STAGE2_BLK_CNT_MAX];
+	uint8_t unused[64];
+} __attribute__ ((packed));
 
 /* Stage 2 boot menu parameter structure */
 
@@ -110,7 +235,8 @@ struct boot_stage2_params {
 	uint16_t timeout;
 	uint16_t banner;
 	uint16_t config[BOOT_MENU_ENTRIES + 1];
-};
+	uint64_t config_kdump;
+} __attribute__ ((packed));
 
 
 /* Stage 3 bootloader parameter structure */
@@ -121,12 +247,15 @@ struct boot_stage3_params {
 	uint64_t initrd_len;
 	uint64_t load_psw;
 	uint64_t extra_parm;
-};
+	uint16_t flags;
+} __attribute__ ((packed));
 
+#define STAGE3_FLAG_SCSI		0x0001
+#define STAGE3_FLAG_KDUMP		0x0002
 
 /* Tape IPL bootloader parameter structure */
 
-#define BOOT_TAPE_IPL_PARAMS_OFFSET	0x100
+#define BOOT_TAPE_IPL_PARAMS_OFFSET	0x200
 
 struct boot_tape_ipl_params {
 	uint64_t parm_addr;
@@ -141,7 +270,7 @@ struct mvdump_param {
 	uint32_t	start_blk;
 	uint32_t	end_blk;
 	uint8_t		blocksize;
-	uint8_t		end_sec;
+	uint8_t		bpt;
 	uint8_t		num_heads;
 } __attribute__ ((packed));
 
@@ -153,36 +282,38 @@ struct mvdump_parm_table {
 		(MAX_DUMP_VOLUMES * sizeof(struct mvdump_param))];
 } __attribute__ ((packed));
 
+void boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type,
+			void *param);
+void boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
+		       disk_blockptr_t *bm_ptr, struct disk_info *info);
 
 int boot_check_data(void);
 int boot_init_fba_stage0(struct boot_fba_stage0* stage0,
 			 disk_blockptr_t* stage2_list,
 			 blocknum_t stage2_count);
 int boot_get_fba_stage2(void** data, size_t* size, struct job_data* job);
-void boot_init_eckd_classic_stage0(struct boot_eckd_stage0* stage0);
-int boot_init_eckd_classic_stage1(struct boot_eckd_classic_stage1* stage1,
-				  disk_blockptr_t* stage2_list,
-				  blocknum_t stage2_count);
-void boot_init_eckd_compatible_stage0(struct boot_eckd_stage0* stage0);
-int boot_init_eckd_compatible_stage1(
-			struct boot_eckd_compatible_stage1* stage1,
-			struct disk_info* info);
+void boot_init_eckd_ldl_stage0(struct boot_eckd_ldl_stage0 *stage0);
+void boot_init_eckd_cdl_stage0(struct boot_eckd_cdl_stage0 *stage0);
+int boot_init_eckd_stage1(struct boot_eckd_stage1 *stage1,
+			  disk_blockptr_t *stage1b_list,
+			  blocknum_t stage1b_count);
+int boot_init_eckd_stage1b(struct boot_eckd_stage1b *stage1b,
+			   disk_blockptr_t *stage2_list,
+			   blocknum_t stage2_count);
+int boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b,
+			  disk_blockptr_t *stage2_list,
+			  blocknum_t stage2_count);
 int boot_get_eckd_stage2(void** data, size_t* size, struct job_data* job);
+size_t get_stage3_size();
 int boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
 		    address_t initrd_addr, size_t initrd_len,
-		    address_t image_addr, int extra_parm);
+		    address_t image_addr, int extra_parm, uint16_t flags);
 int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
 		      address_t initrd_addr, address_t image_addr);
 int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);
 int boot_get_eckd_dump_stage2(void** data, size_t* size, uint64_t mem);
 int boot_get_eckd_mvdump_stage2(void** data, size_t* size, uint64_t mem,
 				uint8_t force, struct mvdump_parm_table);
-int boot_init_eckd_classic_dump_stage1(struct boot_eckd_classic_stage1* stage1,
-				       struct disk_info* info);
-int boot_init_eckd_compatible_dump_stage1(
-				struct boot_eckd_compatible_stage1* stage1,
-				struct disk_info* info,
-				int mvdump_switch);
 int boot_get_fba_dump_stage2(void** data, size_t* size, uint64_t mem);
 
 #endif /* BOOT_H */
--- a/zipl/include/bootmap.h
+++ b/zipl/include/bootmap.h
@@ -18,6 +18,7 @@
 
 
 int bootmap_create(struct job_data* job, disk_blockptr_t* program_table,
+		   disk_blockptr_t *scsi_dump_sb_blockptr,
 		   disk_blockptr_t** stage2_list, blocknum_t* stage2_count,
 		   char** device, struct disk_info** new_info);
 void bootmap_store_blockptr(void* buffer, disk_blockptr_t* ptr,
--- a/zipl/include/disk.h
+++ b/zipl/include/disk.h
@@ -47,8 +47,8 @@ typedef enum {
 	disk_type_scsi,
 	disk_type_fba,
 	disk_type_diag,
-	disk_type_eckd_classic,
-	disk_type_eckd_compatible
+	disk_type_eckd_ldl,
+	disk_type_eckd_cdl,
 } disk_type_t;
 
 /* from linux/hdregs.h */
@@ -93,6 +93,8 @@ struct job_target_data;
 
 int disk_get_info(const char* device, struct job_target_data* target,
 		  struct disk_info** info);
+int disk_is_tape(const char* device);
+int disk_is_scsi(const char* device, struct job_target_data* target);
 int disk_get_info_from_file(const char* filename,
 			    struct job_target_data* target,
 			    struct disk_info** info);
@@ -106,8 +108,8 @@ void disk_blockptr_from_blocknum(disk_bl
 				 struct disk_info* info);
 int disk_write_block_aligned(int fd, const void* data, size_t bytecount,
 	  		     disk_blockptr_t* block, struct disk_info* info);
-blocknum_t disk_write_block_buffer(int fd, const void* buffer,
-				   size_t bytecount,
+blocknum_t disk_write_block_buffer(int fd, int fd_is_basedisk,
+				   const void* buffer, size_t bytecount,
 				   disk_blockptr_t** blocklist,
 				   struct disk_info* info);
 void disk_print_devt(dev_t d);
@@ -119,5 +121,6 @@ blocknum_t disk_get_blocklist_from_file(
 					disk_blockptr_t** blocklist,
 					struct disk_info* pinfo);
 int disk_check_subchannel_set(int devno, dev_t device, char* dev_name);
+void disk_print_geo(struct disk_info *data);
 
 #endif /* not DISK_H */
--- a/zipl/include/install.h
+++ b/zipl/include/install.h
@@ -18,6 +18,7 @@
 
 
 int install_bootloader(const char* device, disk_blockptr_t* program_table,
+		       disk_blockptr_t* scsi_dump_sb_blockptr,
 		       disk_blockptr_t* stage2_data, blocknum_t stage2_count,
 		       struct disk_info* info, struct job_data* job);
 int install_tapeloader(const char* device, const char* image,
@@ -29,4 +30,13 @@ int install_dump(const char* device, str
 int install_mvdump(char* const device[], struct job_target_data* target,
 		   int device_count, uint64_t mem, uint8_t force);
 
+int install_fba_stage1b(int fd, disk_blockptr_t **stage1b_list,
+			blocknum_t *stage1b_count, disk_blockptr_t *stage2_list,
+			blocknum_t stage2_count, struct disk_info *info);
+int install_eckd_stage1b(int fd, disk_blockptr_t **stage1b_list,
+			 blocknum_t *stage1b_count,
+			 disk_blockptr_t *stage2_list,
+			 blocknum_t stage2_count, struct disk_info *info);
+int rewind_tape(int fd);
+
 #endif /* INSTALL_H */
--- a/zipl/include/job.h
+++ b/zipl/include/job.h
@@ -22,10 +22,9 @@ enum job_id {
 	job_ipl = 3,
 	job_segment = 4,
 	job_dump_partition = 5,
-	job_dump_fs = 6,
-	job_menu = 7,
-	job_ipl_tape = 8,
-	job_mvdump = 9,
+	job_menu = 6,
+	job_ipl_tape = 7,
+	job_mvdump = 8,
 };
 
 struct job_target_data {
@@ -46,6 +45,7 @@ struct job_ipl_data {
 	address_t image_addr;
 	address_t parm_addr;
 	address_t ramdisk_addr;
+	int is_kdump;
 };
 
 struct job_segment_data {
@@ -55,6 +55,12 @@ struct job_segment_data {
 
 struct job_dump_data {
 	char* device;
+	char* image;
+	char* parmline;
+	char* ramdisk;
+	address_t image_addr;
+	address_t parm_addr;
+	address_t ramdisk_addr;
 	uint64_t mem;
 };
 
@@ -66,17 +72,6 @@ struct job_mvdump_data {
 	uint8_t force;
 };
 
-struct job_dump_fs_data {
-	char* partition;
-	char* image;
-	char* parmline;
-	char* ramdisk;
-	address_t image_addr;
-	address_t parm_addr;
-	address_t ramdisk_addr;
-	uint64_t mem;
-};
-
 struct job_ipl_tape_data {
 	char* device;
 	char* image;
@@ -90,7 +85,7 @@ struct job_ipl_tape_data {
 
 union job_menu_entry_data {
 	struct job_ipl_data ipl;
-	struct job_dump_fs_data dump_fs;
+	struct job_dump_data dump;
 };
 
 struct job_menu_entry {
@@ -117,7 +112,6 @@ struct job_data {
 		struct job_menu_data menu;
 		struct job_segment_data segment;
 		struct job_dump_data dump;
-		struct job_dump_fs_data dump_fs;
 		struct job_ipl_tape_data ipl_tape;
 		struct job_mvdump_data mvdump;
 	} data;
@@ -132,5 +126,6 @@ struct job_data {
 int job_get(int argc, char* argv[], struct job_data** data);
 void job_free(struct job_data* job);
 int type_from_target(char *target, disk_type_t *type);
+int check_job_dump_images(struct job_dump_data* dump, char* name);
 
 #endif /* not JOB_H */
--- a/zipl/include/misc.h
+++ b/zipl/include/misc.h
@@ -25,14 +25,18 @@ struct misc_file_buffer {
 
 
 void* misc_malloc(size_t size);
+int misc_asprintf(char **out, const char *fmt, ...);
 void* misc_calloc(size_t n, size_t size);
 char* misc_strdup(const char* s);
+int misc_open_exclusive(const char* filename);
 int misc_read(int fd, void* buffer, size_t count);
 int misc_read_file(const char* filename, char** buffer, size_t* size,
 		   int nil_terminate);
 int misc_read_special_file(const char* filename, char** buffer, size_t* size,
 			   int nil_terminate);
 int misc_write(int fd, const void* data, size_t count);
+int misc_pwrite(int fd, void *buf, size_t size, off_t off);
+int misc_seek(int fd, off_t off);
 int misc_get_file_buffer(const char* filename,
 			 struct misc_file_buffer* buffer);
 void misc_free_file_buffer(struct misc_file_buffer* file);
@@ -44,5 +48,10 @@ void misc_free_temp_dev(char* device);
 int misc_check_writable_directory(const char* directory);
 int misc_check_readable_file(const char* filename);
 int misc_check_writable_device(const char* devno, int blockdev, int chardev);
+void misc_ebcdic_to_ascii(unsigned char *from, unsigned char *to);
+void misc_ascii_to_ebcdic(unsigned char *from, unsigned char *to);
 
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
 #endif /* not MISC_H */
--- a/zipl/include/proc.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * s390-tools/zipl/include/proc.h
- *   Scanner for the /proc files
- *
- * Copyright IBM Corp. 2001, 2007.
- *
- * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
- */
-
-#ifndef PROC_H
-#define PROC_H
-
-#include "zipl.h"
-
-#include <ctype.h>
-#include <sys/types.h>
-
-
-struct proc_part_entry {
-	dev_t device;
-	size_t blockcount;
-	char* name;
-};
-
-struct proc_dev_entry {
-	int blockdev;
-	dev_t device;
-	char *name;
-};
-
-
-int proc_part_get_entry(dev_t device, struct proc_part_entry* entry);
-void proc_part_free_entry(struct proc_part_entry* entry);
-int proc_dev_get_entry(dev_t dev, int blockdev, struct proc_dev_entry* entry);
-void proc_dev_free_entry(struct proc_dev_entry* entry);
-
-#endif /* not PROC_H */
--- a/zipl/include/scan.h
+++ b/zipl/include/scan.h
@@ -15,7 +15,7 @@
 
 
 #define SCAN_SECTION_NUM		9
-#define SCAN_KEYWORD_NUM		20
+#define SCAN_KEYWORD_NUM		21
 #define SCAN_KEYWORD_ONLY_NUM		1
 #define SCAN_AUTOMENU_NAME		"zipl-automatic-menu"
 
@@ -49,6 +49,7 @@ enum scan_keyword_id {
 	scan_keyword_targetblocksize = 17,
 	scan_keyword_targetoffset = 18,
 	scan_keyword_defaultauto = 19,
+	scan_keyword_kdump = 20,
 };
 
 enum scan_section_type {
--- a/zipl/include/zipl.h
+++ b/zipl/include/zipl.h
@@ -19,18 +19,20 @@
 #define DISK_LAYOUT_ID			0x00000001
 
 #define ZIPL_STAGE2_LOAD_ADDRESS        0x2000
-#define ZIPL_STAGE3_ENTRY_ADDRESS	0xa028LL
+#define ZIPL_STAGE3_ENTRY_ADDRESS	0xa050LL
 #define DEFAULT_IMAGE_ADDRESS		0x10000LL
+#define KDUMP_IMAGE_ADDRESS		0x10010LL
 #define DEFAULT_STAGE3_ADDRESS          0xa000LL
 #define MINIMUM_ADDRESS 		0x10000LL
 #define ADDRESS_LIMIT 			0x80000000LL
+#define ADDRESS_LIMIT_KDUMP		0x2000000UL /* HSA size: 32 MiB */
 #define UNSPECIFIED_ADDRESS		-1ULL
 #define MAXIMUM_PARMLINE_SIZE 		0x380
 #define MAXIMUM_PHYSICAL_BLOCKSIZE 	0x1000
 
 #define PSW_ADDRESS_MASK		0x000000007fffffffLL
-#define PSW_LOAD			0x0008000080000000LL
-#define PSW_DISABLED_WAIT		0x000a000000000000LL
+#define PSW_LOAD                        0x0008000080000000LL
+#define PSW_DISABLED_WAIT               0x000a000000000000LL
 
 #define KERNEL_HEADER_SIZE		65536
 #define BOOTMAP_FILENAME		"bootmap"
@@ -44,8 +46,12 @@
 #define MENU_DEFAULT_PROMPT		0
 #define MENU_DEFAULT_TIMEOUT		0
 
-#define FSDUMP_IMAGE	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_IMAGE)
-#define FSDUMP_RAMDISK	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_RD)
+#define FSDUMP_IMAGE	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_FS_IMAGE)
+#define FSDUMP_RAMDISK	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_FS_RD)
+#define FSDUMP_PART_IMAGE	STRINGIFY(ZFCPDUMP_DIR) "/" \
+					STRINGIFY(ZFCPDUMP_PART_IMAGE)
+#define FSDUMP_PART_RAMDISK	STRINGIFY(ZFCPDUMP_DIR) "/" \
+					STRINGIFY(ZFCPDUMP_PART_RD)
 
 #define MAX_DUMP_VOLUMES		32
 
--- a/zipl/man/zipl.8
+++ b/zipl/man/zipl.8
@@ -1,4 +1,4 @@
-.TH ZIPL 8 "Nov 2009" "s390-tools"
+.TH ZIPL 8 "Feb 2012" "s390-tools"
 .SH NAME
 zipl \- boot loader for IBM S/390 and zSeries architectures
 
@@ -137,7 +137,7 @@ Assume that the physical device is of th
 .IP "         -" 12
 CDL: DASD disk with ECKD/compatible disk layout
 .IP "         -" 12
-LDL: DASD disk with ECDK/linux disk layout
+LDL: DASD disk with ECKD/linux disk layout
 .IP "         -" 12
 FBA: FBA disk DASD
 .IP "         -" 12
@@ -216,6 +216,14 @@ It is not possible to specify both this
 section on the command line at the same time.
 
 .TP
+.BR "\-k auto" " or " "\-\-kdump=auto"
+Install a kdump kernel that can be used as a stand-alone dump tool. You
+can IPL this kernel in an LPAR or guest virtual machine to create a dump of
+a previously running operating system instance that has been configured
+with a reserved memory area for kdump. For Linux, the memory is reserved
+with the "crashkernel" kernel parameter.
+
+.TP
 .BR "\-s <SEGMENT,ADDRESS>" " or " "\-\-segment=<SEGMENT,ADDRESS>"
 Use the segment image <SEGMENT>. The mandatory hexadecimal ADDRESS specifies
 the load address for the segment file.
@@ -226,16 +234,16 @@ or configuration section on the command
 .TP
 .BR "\-d <DEVNODE[,SIZE]>" " or " "--dumpto=<DEVNODE[,SIZE]>"
 Install a system dump record on the device identified by DEVNODE.
-Supported devices are DASD ECKD or FBA disk partitions 
+Supported devices are SCSI disk partitions, DASD ECKD or FBA disk partitions,
 and IBM 3480/3490/3590/3592 tape devices.
 
-An optional decimal SIZE parameter may be specified to determine the
-maximum dump size in bytes. SIZE can be suffixed by either of the letters
-K, M or G to signify that the decimal number be interpreted as kilobytes,
-megabytes or gigabytes respectively. SIZE will be rounded up to the next
-megabyte boundary. Note that when you specify a SIZE lower than the actual
-memory size used by linux (see kernel parameter mem=), the resulting dump
-will be incomplete.
+With the exception of SCSI, an optional decimal SIZE parameter may be
+specified to determine the maximum dump size in bytes. SIZE can be suffixed
+by either of the letters K, M or G to signify that the decimal number be
+interpreted as kilobytes, megabytes or gigabytes respectively. SIZE will be
+rounded up to the next megabyte boundary. Note that when you specify a SIZE
+lower than the actual memory size used by linux (see kernel parameter mem=),
+the resulting dump will be incomplete.
 
 Note that on partitions formatted with the ECKD/linux disk layout, the dump
 record will be overwritten by system dump data so that it can be used for
@@ -247,29 +255,23 @@ It is not possible to specify both this
 or configuration section on the command line at the same time.
 
 .TP
-.BR "\-D <DEVNODE[,SIZE]>" " or " "--dumptofs=<DEVNODE[,SIZE]>"
-Install a dump record on the target device which writes system dumps to the
-file system on the disk partition identified by DEVNODE if supported by the
-hardware.
-
-An optional decimal SIZE parameter may be specified to determine the
-maximum dump size in bytes. SIZE can be suffixed by either of the letters
-K, M or G to signify that the decimal number be interpreted as kilobytes,
-megabytes or gigabytes respectively. SIZE will be rounded up to the next
-megabyte boundary. Note that when you specify a SIZE lower than the actual
-memory size used by linux (see kernel parameter mem=), the resulting dump
-will be incomplete.
-
-It is not possible to specify both this parameter and the name of a menu
-or configuration section on the command line at the same time.
+.BR "\-D" " or " "\-\-dumptofs"
+This option has been removed, use --dumpto instead.
 
 .TP
 .BR "\-M <DUMPLIST[,SIZE]>" " or " "--mvdump=<DUMPLIST[,SIZE]>"
 Install a multi-volume dump record on each device associated with one of the
 partitions listed in file DUMPLIST.
 Supported are DASD ECKD partitions formatted with the compatible
-disk layout. A dump signature is written to each partition contained in
-DUMPLIST.
+disk layout.
+
+A dump signature is written to each partition contained in
+DUMPLIST. This signature is checked by the dump tool, when the dump is
+written. If a dump partition does not have the signature, the dump tool
+will refuse to write the dump. With the
+.BR \-\-force
+option this mechanism can be disabled. E.g. this can be used
+for installing swap space on dump partitions.
 
 An optional decimal SIZE parameter may be specified to determine the
 maximum dump size in bytes. SIZE can be suffixed by either of the letters
@@ -297,8 +299,7 @@ This option cannot be used together with
 .BR \-\-parmfile ,
 .BR \-\-parameters ,
 .BR \-\-segment ,
-.BR \-\-dumpto ,
-.BR \-\-dumptofs " or"
+.BR \-\-dumpto " or"
 .BR \-\-mvdump .
 
 .TP
@@ -364,4 +365,5 @@ following parameters:
 .br
 
 .SH SEE ALSO
-.BR zipl.conf (5)
+.BR zipl.conf (5),
+.BR kexec (8)
--- a/zipl/man/zipl.conf.5
+++ b/zipl/man/zipl.conf.5
@@ -233,7 +233,7 @@ description above).
 Only disk IPL sections (see option
 .BR image ) 
 and file system dump sections (option
-.BR dumptofs )
+.BR dumpto )
 may be included in menus. 
 
 Note that position number 0 is reserved and will automatically be assigned to
@@ -348,29 +348,9 @@ will be incomplete.
 .PP
 
 .B dumptofs
-=
-.IR dump\-partition [, size ]
-(configuration only)
 .IP
-.B Configuration section:
 .br
-Specify a SCSI partition which should be used for system dump.
-Every time this configuration is booted, the current system status is written
-as a numbered file to the file system located on the dump partition. This
-option has to be specified together with the
-.B 'target'
-option. If necessary, the
-.BR 'parmfile' " or "
-.B 'parameters'
-option may be used to pass parameters to the system dump tool.
-
-An optional decimal SIZE parameter may be specified to determine the
-maximum dump size in bytes. SIZE can be suffixed by either of the letters
-K, M or G to signify that the decimal number be interpreted as kilobytes,
-megabytes or gigabytes respectively. SIZE will be rounded up to the next
-megabyte boundary. Note that when you specify a SIZE lower than the actual
-memory size used by linux (see kernel parameter mem=), the resulting dump
-will be incomplete.
+This option has been removed, use dumpto instead.
 .PP
 
 .B mvdump
@@ -422,8 +402,7 @@ To change the kernel parameters, use
 .BR 'parameters' .
 
 This option cannot be used together with either
-.BR 'dump' ,
-.BR 'dumptofs' " or"
+.BR 'dump' , " or"
 .BR 'segment' .
 .PP
 
@@ -452,6 +431,20 @@ An optional hexadecimal address may be p
 non-default memory location.
 .PP
 
+.B kdump
+=
+.IR auto
+(configuration only)
+.IP
+.B Configuration section:
+.br
+Specify this option to install a kdump kernel that can be used as a
+stand-alone dump tool. You can IPL this kernel in an LPAR or guest virtual
+machine to create a dump of a previously running operating system instance
+that has been configured with a reserved memory area for kdump. For
+Linux, the memory is reserved with the "crashkernel" kernel parameter.
+.PP
+
 .B prompt
 =
 .IR 0 / 1
@@ -520,8 +513,7 @@ Specify a IBM 3480/3490/3590 tape device
 
 This option cannot be used together with
 .BR 'target' ", "
-.BR 'dump' ", "
-.BR 'dumptofs' " or "
+.BR 'dump' ", " " or "
 .BR 'segment' .
 .PP
 
@@ -566,7 +558,7 @@ Specify the device type for the physical
 .IP "         - " 12
 CDL: DASD disk with ECKD/compatible disk layout
 .IP "         - " 12
-LDL: DASD disk with ECDK/linux disk layout
+LDL: DASD disk with ECKD/linux disk layout
 .IP "         - " 12
 FBA: FBA disk DASD
 .IP "         - " 12
--- a/zipl/src/Makefile
+++ b/zipl/src/Makefile
@@ -3,11 +3,17 @@ include ../../common.mak
 
 CPPFLAGS += -I../include -I../boot -I../../include \
 	    -DZFCPDUMP_DIR=$(ZFCPDUMP_DIR) \
-	    -DZFCPDUMP_IMAGE=$(ZFCPDUMP_IMAGE) -DZFCPDUMP_RD=$(ZFCPDUMP_RD) \
+	    -DZFCPDUMP_FS_IMAGE=$(ZFCPDUMP_FS_IMAGE) \
+	    -DZFCPDUMP_FS_RD=$(ZFCPDUMP_FS_RD) \
+	    -DZFCPDUMP_PART_IMAGE=$(ZFCPDUMP_PART_IMAGE) \
+	    -DZFCPDUMP_PART_RD=$(ZFCPDUMP_PART_RD) \
 	    -D_FILE_OFFSET_BITS=64
 LDFLAGS += -Wl,-z,noexecstack
-objects = misc.o proc.o error.o scan.o job.o boot.o bootmap.o disk.o \
-	  install.o zipl.o ../boot/data.o
+
+objects = misc.o error.o scan.o job.o boot.o bootmap.o disk.o \
+	  install.o zipl.o $(rootdir)/zipl/boot/data.o \
+	  $(rootdir)/libutil/util_part.o $(rootdir)/libutil/util_proc.o
+
 includes = $(wildcard ../include/*.h)
 zipl_helpers = $(wildcard zipl_helper.*)
 chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
@@ -33,5 +39,13 @@ clean:
 .PHONY: all install clean
 
 # Additional manual dependencies
+boot.o: ../boot/data.h
+
+../boot/data.h:
+	make -C ../boot data.h
+
+../boot/data.o:
+	make -C ../boot data.o
 
-boot.o: ../boot/data.o ../boot/data.h
+../../libutil/util_part.o:
+	make -C ../../libutil util_part.o
--- a/zipl/src/boot.c
+++ b/zipl/src/boot.c
@@ -18,6 +18,7 @@
 
 #include "error.h"
 #include "misc.h"
+#include "bootmap.h"
 
 /* Include declarations for boot_data symbols. */
 #include "../boot/data.h"
@@ -25,41 +26,56 @@
 #define DATA_SIZE(x)	((size_t) (&_binary_##x##_bin_size))
 #define DATA_ADDR(x)	(&_binary_##x##_bin_start)
 
-#define STAGE2_MAX_SIZE		4096
-
+#define STAGE2_MAX_SIZE		0x3000
+#define STAGE1B_LOAD_ADDR	0xe000
+#define CCW_FLAG_CC		0x40
+#define CCW_FLAG_SLI		0x20
+#define FBA_BLK_SIZE		512
+
+static struct boot_ccw0 tic_to_stage1b = {
+	.cmd = 0x08, /* tic */
+	.address_lo = STAGE1B_LOAD_ADDR,
+};
 
 /* Check sizes of internal objects. Return 0 if everything is correct,
  * non-zero otherwise. */
 int
 boot_check_data(void)
 {
-	if (DATA_SIZE(fba0) !=
-	    sizeof(struct boot_fba_stage0)) {
-		error_reason("Size mismatch of stage 0 loader for disks with "
-			     "FBA layout");
+	if (DATA_SIZE(fba0) != sizeof(struct boot_fba_stage0)) {
+		error_reason("Size mismatch of FBA stage 0 loader");
+		return -1;
+	}
+	if (DATA_SIZE(fba1b) != sizeof(struct boot_fba_stage1b)) {
+		error_reason("Size mismatch of FBA stage 1b loader");
 		return -1;
 	}
-	if (DATA_SIZE(eckd0) !=
-	    sizeof(struct boot_eckd_stage0)) {
-		error_reason("Size mismatch of stage 0 loader for disks with "
-			     "ECKD layout");
+	if (DATA_SIZE(eckd0_ldl) !=
+	    sizeof(struct boot_eckd_ldl_stage0)) {
+		error_reason("Size mismatch of ECKD LDL stage 0 loader");
 		return -1;
 	}
-	if (DATA_SIZE(eckd1a) !=
-	    sizeof(struct boot_eckd_classic_stage1)) {
-		error_reason("Size mismatch of stage 1 loader for disks with "
-			     "ECKD classic layout");
+	if (DATA_SIZE(eckd0_cdl) != sizeof(struct boot_eckd_cdl_stage0)) {
+		error_reason("Size mismatch of ECKD CDL stage 0 loader");
 		return -1;
 	}
-	if (DATA_SIZE(eckd1b) !=
-	    sizeof(struct boot_eckd_compatible_stage1)) {
-		error_reason("Size mismatch of stage 1 loader for disks with "
-			     "ECKD compatible layout");
+	if (DATA_SIZE(eckd1) != sizeof(struct boot_eckd_stage1)) {
+		error_reason("Size mismatch of ECKD stage 1 loader");
+		return -1;
+	}
+	if (DATA_SIZE(eckd1b) != sizeof(struct boot_eckd_stage1b)) {
+		error_reason("Size mismatch of ECKD stage 1b loader");
 		return -1;
 	}
 	return 0;
 }
 
+/* Export stage 3 size for partition dump with dump kernel */
+size_t
+get_stage3_size()
+{
+	return DATA_SIZE(stage3);
+}
 
 /* Create a stage 3 loader in memory.
  * Upon success, return 0 and set BUFFER to point to the data buffer and set
@@ -67,7 +83,7 @@ boot_check_data(void)
 int
 boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
 		address_t initrd_addr, size_t initrd_len, address_t image_addr,
-		int extra_parm)
+		int extra_parm, uint16_t flags)
 {
 	struct boot_stage3_params params;
 	void* data;
@@ -85,8 +101,9 @@ boot_get_stage3(void** buffer, size_t* b
 	params.parm_addr = (uint64_t) parm_addr;
 	params.initrd_addr = (uint64_t) initrd_addr;
 	params.initrd_len = (uint64_t) initrd_len;
-	params.load_psw = (uint64_t) (image_addr | PSW_LOAD);
+	params.load_psw = (uint64_t)(image_addr | PSW_LOAD);
 	params.extra_parm = (uint64_t) extra_parm;
+	params.flags = flags;
 	/* Initialize buffer */
 	memcpy(data, DATA_ADDR(stage3), DATA_SIZE(stage3));
 	memcpy(data, &params, sizeof(struct boot_stage3_params));
@@ -95,150 +112,124 @@ boot_get_stage3(void** buffer, size_t* b
 	return 0;
 }
 
-
-#define FBA_FLAG_CC 0x0000000040000000LL
-
 int
-boot_init_fba_stage0(struct boot_fba_stage0* stage0,
-		     disk_blockptr_t* stage2_list, blocknum_t stage2_count)
+boot_init_fba_stage0(struct boot_fba_stage0 *stage0,
+		     disk_blockptr_t *stage1b_list, blocknum_t stage1b_count)
 {
 	blocknum_t i;
 
 	/* Initialize stage 0 data */
-	memcpy(stage0, DATA_ADDR(fba0), sizeof(struct boot_fba_stage0));
+	memcpy(stage0, DATA_ADDR(fba0), sizeof(*stage0));
 	/* Fill in blocklist for stage 2 loader */
-	if (stage2_count > 16) {
-		error_reason("Not enough room for FBA stage 2 loader "
-			     "(try larger block size)");
+	if (stage1b_count > STAGE1B_BLK_CNT_MAX) {
+		error_reason("Not enough room for FBA stage 1b loader");
 		return -1;
 	}
-	for (i=0; i < stage2_count; i++) {
+	for (i = 0; i < stage1b_count; i++) {
 		stage0->locdata[i].blocknr =
-			(uint32_t) stage2_list[i].linear.block;
+			(uint32_t) stage1b_list[i].linear.block;
+		stage0->locread[i].read.address_lo =
+			STAGE1B_LOAD_ADDR + i * FBA_BLK_SIZE;
 	}
-	/* Terminate CCW chain */
-	stage0->locread[i - 1].read &= ~FBA_FLAG_CC;
+	/* Terminate CCW chain: Tic to stage 1b */
+	memcpy(&stage0->locread[i], &tic_to_stage1b, sizeof(tic_to_stage1b));
 	return 0;
 }
 
-
 void
-boot_init_eckd_classic_stage0(struct boot_eckd_stage0* stage0)
+boot_init_eckd_ldl_stage0(struct boot_eckd_ldl_stage0 *stage0)
 {
-	memcpy(stage0, DATA_ADDR(eckd0), sizeof(struct boot_eckd_stage0));
-	/* Fill in size of stage 1 loader */
-	stage0->read.count = sizeof(struct boot_eckd_classic_stage1);
+	memcpy(stage0, DATA_ADDR(eckd0_ldl), sizeof(*stage0));
+	/* Fill in size of stage 1 plus stage 0 loader */
+	stage0->read_r1.count = sizeof(struct boot_eckd_stage1) +
+		sizeof(struct boot_eckd_ldl_stage0);
 }
 
-
 void
-boot_init_eckd_compatible_stage0(struct boot_eckd_stage0* stage0)
+boot_init_eckd_cdl_stage0(struct boot_eckd_cdl_stage0 *stage0)
 {
-	memcpy(stage0, DATA_ADDR(eckd0), sizeof(struct boot_eckd_stage0));
+	memcpy(stage0, DATA_ADDR(eckd0_cdl), sizeof(*stage0));
 	/* Fill in size of stage 1 loader */
-	stage0->read.count = sizeof(struct boot_eckd_compatible_stage1);
+	stage0->read.count = sizeof(struct boot_eckd_stage1);
 }
 
-
-#define ECKD_CCW_FLAG_CC	0x40
-#define ECKD_CCW_FLAG_SLI	0x20
-
 int
-boot_init_eckd_classic_stage1(struct boot_eckd_classic_stage1* stage1,
-		     disk_blockptr_t* stage2_list, blocknum_t stage2_count)
+boot_init_eckd_stage1(struct boot_eckd_stage1 *stage1,
+		      disk_blockptr_t *stage1b_list, blocknum_t stage1b_count)
 {
 	blocknum_t i;
 
-	memcpy(stage1, DATA_ADDR(eckd1a),
-	       sizeof(struct boot_eckd_classic_stage1));
-	/* Fill in blocklist for stage 2 loader */
-	if (stage2_count > 8) {
-		error_reason("Not enough room for ECKD stage 2 loader "
+	memcpy(stage1, DATA_ADDR(eckd1), sizeof(*stage1));
+	/* Fill in blocklist for stage 1b  loader */
+	if (stage1b_count > STAGE1B_BLK_CNT_MAX) {
+		error_reason("Not enough room for ECKD stage 1b loader "
 			     "(try larger block size)");
 		return -1;
 	}
-	for (i=0; i < stage2_count; i++) {
-		stage1->ssrt[i].read.count 	= stage2_list[i].chs.size;
-		stage1->seek[i].cyl		= stage2_list[i].chs.cyl;
-		stage1->seek[i].head		= stage2_list[i].chs.head |
-			((stage2_list[i].chs.cyl >> 12) & 0xfff0);
-		stage1->seek[i].sec		= stage2_list[i].chs.sec;
-		stage1->ssrt[i].read.address_lo	= ZIPL_STAGE2_LOAD_ADDRESS +
-						  i * stage2_list[i].chs.size;
-		stage1->ssrt[i].read.flags	= ECKD_CCW_FLAG_CC |
-						  ECKD_CCW_FLAG_SLI;
+	for (i = 0; i < stage1b_count; i++) {
+		stage1->ssrt[i].read.count = stage1b_list[i].chs.size;
+		stage1->seek[i].cyl = stage1b_list[i].chs.cyl;
+		stage1->seek[i].head = stage1b_list[i].chs.head |
+			((stage1b_list[i].chs.cyl >> 12) & 0xfff0);
+		stage1->seek[i].sec = stage1b_list[i].chs.sec;
+		stage1->ssrt[i].read.address_lo =
+			STAGE1B_LOAD_ADDR + i * stage1b_list[i].chs.size;
+		stage1->ssrt[i].read.flags = CCW_FLAG_CC | CCW_FLAG_SLI;
 	}
-	/* Terminate CCW chain */
-	stage1->ssrt[i - 1].read.flags &= ~ECKD_CCW_FLAG_CC;
+	/* Terminate CCW chain: Tic to stage 1b */
+	memcpy(&stage1->ssrt[i], &tic_to_stage1b, sizeof(tic_to_stage1b));
 	return 0;
 }
 
-
 int
-boot_init_eckd_classic_dump_stage1(struct boot_eckd_classic_stage1* stage1,
-				   struct disk_info* info)
+boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b,
+		      disk_blockptr_t *stage2_list, blocknum_t stage2_count)
 {
-	blocknum_t blocks;
 	blocknum_t i;
 
-	memcpy(stage1, DATA_ADDR(eckd1a),
-	       sizeof(struct boot_eckd_classic_stage1));
-	blocks = (DATA_SIZE(eckd2dump) +
-			info->phy_block_size - 1) / info->phy_block_size;
-	if (blocks > 8) {
-		error_reason("Not enough room for ECKD stage 2 dump record "
-			     "(try larger block size)");
+	memcpy(stage1b, DATA_ADDR(fba1b), sizeof(*stage1b));
+	if (stage2_count > STAGE2_BLK_CNT_MAX) {
+		error_reason("Not enough room for FBA stage 2 loader");
 		return -1;
 	}
-	/* Fill in block list of stage 2 dump record */
-	for (i=0; i < blocks; i++) {
-		int cyl;
-
-		stage1->ssrt[i].read.count = info->phy_block_size;
-		stage1->ssrt[i].read.address_lo = ZIPL_STAGE2_LOAD_ADDRESS +
-						  i * info->phy_block_size;
-		cyl = disk_cyl_from_blocknum(i + info->geo.start, info);
-		stage1->seek[i].cyl = cyl;
-		stage1->seek[i].head =
-			disk_head_from_blocknum(i + info->geo.start, info) |
-			((cyl >> 12) & 0xfff0);
-		stage1->seek[i].sec =
-			disk_sec_from_blocknum(i + info->geo.start, info);
+	for (i = 0; i < stage2_count; i++) {
+		stage1b->locdata[i].blocknr =
+			(uint32_t) stage2_list[i].linear.block;
+		stage1b->locread[i].read.address_lo =
+			ZIPL_STAGE2_LOAD_ADDRESS + i * FBA_BLK_SIZE;
 	}
 	/* Terminate CCW chain */
-	stage1->ssrt[i - 1].read.flags &= ~ECKD_CCW_FLAG_CC;
+	stage1b->locread[i - 1].read.flags &= ~CCW_FLAG_CC;
 	return 0;
 }
 
-
 int
-boot_init_eckd_compatible_stage1(struct boot_eckd_compatible_stage1* stage1,
-				 struct disk_info* info)
+boot_init_eckd_stage1b(struct boot_eckd_stage1b *stage1b,
+		       disk_blockptr_t *stage2_list, blocknum_t stage2_count)
 {
-	blocknum_t blocks;
 	blocknum_t i;
 
-	memcpy(stage1, DATA_ADDR(eckd1b),
-	       sizeof(struct boot_eckd_compatible_stage1));
-	/* Fill in blocklist for stage 2 loader */
-	blocks = (STAGE2_MAX_SIZE + info->phy_block_size - 1) /
-		 info->phy_block_size;
-	if (blocks > 12) {
+	memcpy(stage1b, DATA_ADDR(eckd1b), sizeof(*stage1b));
+	if (stage2_count > STAGE2_BLK_CNT_MAX) {
 		error_reason("Not enough room for ECKD stage 2 loader "
 			     "(try larger block size)");
 		return -1;
 	}
-	for (i=0; i < blocks; i++) {
-		stage1->read[i].count		= info->phy_block_size;
-		stage1->read[i].address_lo	= ZIPL_STAGE2_LOAD_ADDRESS +
-						  i * info->phy_block_size;
+	for (i = 0; i < stage2_count; i++) {
+		stage1b->ssrt[i].read.count = stage2_list[i].chs.size;
+		stage1b->seek[i].cyl = stage2_list[i].chs.cyl;
+		stage1b->seek[i].head = stage2_list[i].chs.head |
+			((stage2_list[i].chs.cyl >> 12) & 0xfff0);
+		stage1b->seek[i].sec = stage2_list[i].chs.sec;
+		stage1b->ssrt[i].read.address_lo = ZIPL_STAGE2_LOAD_ADDRESS +
+			i * stage2_list[i].chs.size;
+		stage1b->ssrt[i].read.flags = CCW_FLAG_CC | CCW_FLAG_SLI;
 	}
 	/* Terminate CCW chain */
-	stage1->read[i - 1].flags &= ~ECKD_CCW_FLAG_CC;
+	stage1b->ssrt[i - 1].read.flags &= ~CCW_FLAG_CC;
 	return 0;
 }
 
-
 int
 boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
 		  address_t initrd_addr, address_t image_addr)
@@ -267,85 +258,6 @@ boot_get_tape_ipl(void** data, size_t* s
 	return 0;
 }
 
-
-int
-boot_init_eckd_compatible_dump_stage1(
-				struct boot_eckd_compatible_stage1* stage1,
-				struct disk_info* info,
-				int mvdump_switch)
-{
-	blocknum_t blocks;
-	blocknum_t i;
-
-	memcpy(stage1, DATA_ADDR(eckd1b),
-	       sizeof(struct boot_eckd_compatible_stage1));
-	if (mvdump_switch)
-		blocks = (DATA_SIZE(eckd2mvdump) +
-			  info->phy_block_size - 1) / info->phy_block_size;
-	else
-		blocks = (DATA_SIZE(eckd2dump) +
-			  info->phy_block_size - 1) / info->phy_block_size;
-	if (blocks > 12) {
-		error_reason("Not enough room for ECKD stage 2 dump record "
-			     "(try larger block size)");
-		return -1;
-	}
-	/* Fill in block list of stage 2 dump record */
-	for (i = 0; i < blocks; i++) {
-		stage1->read[i].count = info->phy_block_size;
-		stage1->read[i].address_lo = ZIPL_STAGE2_LOAD_ADDRESS +
-					     i * info->phy_block_size;
-	}
-	/* Terminate CCW chain */
-	stage1->read[i - 1].flags &= ~ECKD_CCW_FLAG_CC;
-	return 0;
-}
-
-
-/* ASCII to EBCDIC conversion table. */
-unsigned char ascebc[256] =
-{
-     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
-     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
-     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
-     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
-     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
-     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
-     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
-     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
-     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
-     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
-     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
-     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
-     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
-     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
-     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-static void ascii_to_ebcdic(unsigned char* from, unsigned char* to)
-{
-	for (;from != to; from++)
-		*from = ascebc[*from];
-}
-
-
 struct menu_buffer {
 	void *start;
 	size_t size;
@@ -391,7 +303,8 @@ mb_sprintf(struct menu_buffer *buffer, c
 	va_end(args);
 	if (len < 0 || len >= size)
 		return NULL;
-	ascii_to_ebcdic((unsigned char *) str, (unsigned char *) str + len);
+	misc_ascii_to_ebcdic((unsigned char *) str,
+			     (unsigned char *) str + len);
 	mb_alloc(buffer, len + 1);
 
 	return str;
@@ -408,14 +321,25 @@ store_stage2_menu(void* data, size_t siz
 	int i;
 	struct menu_buffer mb;
 	void *str;
+	uint64_t config_kdump = 0;
 
 	mb_init(&mb, data, size);
 	if (job->id == job_menu) {
 		name = "-";
-		for (i=0; i < job->data.menu.num; i++)
+		for (i = 0; i < job->data.menu.num; i++) {
+			if (job->data.menu.entry[i].id == job_ipl &&
+			    job->data.menu.entry[i].data.ipl.is_kdump)
+				/* we start with 2nd bit */
+				config_kdump |= (0x1 << (i + 1));
 			if (job->data.menu.entry[i].pos ==
-			    job->data.menu.default_pos)
+			    job->data.menu.default_pos) {
+				if (job->data.menu.entry[i].id == job_ipl &&
+				    job->data.menu.entry[i].data.ipl.is_kdump)
+					/* default entry is first bit */
+					config_kdump |= 0x1;
 				name = job->data.menu.entry[i].name;
+			}
+		}
 		flag = (job->data.menu.prompt != 0);
 		timeout = job->data.menu.timeout;
 		/* Be verbose */
@@ -432,6 +356,8 @@ store_stage2_menu(void* data, size_t siz
 			printf("  Default configuration...: '%s'\n", name);
 		}
 	} else {
+		if (job->id == job_ipl && job->data.ipl.is_kdump)
+			config_kdump |= 0x1;
 		name = job->name;
 		flag = 0;
 		timeout = 0;
@@ -441,6 +367,7 @@ store_stage2_menu(void* data, size_t siz
 	if (!params)
 		goto err_nospace;
 	params->flag = flag;
+	params->config_kdump = config_kdump;
 	params->timeout = timeout;
 	/* Banner text */
 	str = mb_sprintf(&mb, "zIPL v%s interactive boot menu\n ",
@@ -463,8 +390,13 @@ store_stage2_menu(void* data, size_t siz
 		return 0;
 	/* Config texts */
 	for (i = 0; i < job->data.menu.num; i++) {
-		str = mb_sprintf(&mb, "%2d. %s", job->data.menu.entry[i].pos,
-						 job->data.menu.entry[i].name);
+		const char *kdump_str = "";
+		if (job->data.menu.entry[i].data.ipl.is_kdump)
+			kdump_str = " (kdump)";
+		str = mb_sprintf(&mb, "%2d. %s%s",
+				 job->data.menu.entry[i].pos,
+				 job->data.menu.entry[i].name,
+				 kdump_str);
 		if (!str)
 			goto err_nospace_user;
 		params->config[job->data.menu.entry[i].pos] = (uint16_t)
@@ -534,15 +466,15 @@ boot_get_tape_dump(void** data, size_t*
 {
 	void* buffer;
 
-	buffer = misc_malloc(DATA_SIZE(tapedump));
+	buffer = misc_malloc(DATA_SIZE(tape2dump));
 	if (buffer == NULL)
 		return -1;
-	memcpy(buffer, DATA_ADDR(tapedump), DATA_SIZE(tapedump));
+	memcpy(buffer, DATA_ADDR(tape2dump), DATA_SIZE(tape2dump));
 	/* Write mem size to end of dump record */
-	memcpy(VOID_ADD(buffer, DATA_SIZE(tapedump) - sizeof(mem)), &mem,
+	memcpy(VOID_ADD(buffer, DATA_SIZE(tape2dump) - sizeof(mem)), &mem,
 	       sizeof(mem));
 	*data = buffer;
-	*size = DATA_SIZE(tapedump);
+	*size = DATA_SIZE(tape2dump);
 	return 0;
 }
 
@@ -552,15 +484,15 @@ boot_get_eckd_dump_stage2(void** data, s
 {
 	void* buffer;
 
-	buffer = misc_malloc(DATA_SIZE(eckd2dump));
+	buffer = misc_malloc(DATA_SIZE(eckd2dump_sv));
 	if (buffer == NULL)
 		return -1;
-	memcpy(buffer, DATA_ADDR(eckd2dump), DATA_SIZE(eckd2dump));
+	memcpy(buffer, DATA_ADDR(eckd2dump_sv), DATA_SIZE(eckd2dump_sv));
 	/* Write mem size to end of dump record */
-	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2dump) - sizeof(mem)),
+	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2dump_sv) - sizeof(mem)),
 	       &mem, sizeof(mem));
 	*data = buffer;
-	*size = DATA_SIZE(eckd2dump);
+	*size = DATA_SIZE(eckd2dump_sv);
 	return 0;
 }
 
@@ -570,22 +502,22 @@ boot_get_eckd_mvdump_stage2(void** data,
 {
 	void* buffer;
 
-	buffer = misc_malloc(DATA_SIZE(eckd2mvdump));
+	buffer = misc_malloc(DATA_SIZE(eckd2dump_mv));
 	if (buffer == NULL)
 		return -1;
-	memcpy(buffer, DATA_ADDR(eckd2mvdump), DATA_SIZE(eckd2mvdump));
+	memcpy(buffer, DATA_ADDR(eckd2dump_mv), DATA_SIZE(eckd2dump_mv));
 	/* Write mem size and force indicator (as specified by zipl -M)
 	 * to end of dump record, right before 512-byte parameter table */
-	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2mvdump) - sizeof(mem) -
+	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2dump_mv) - sizeof(mem) -
 			sizeof(struct mvdump_parm_table)), &mem, sizeof(mem));
-	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2mvdump) - sizeof(mem) -
+	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2dump_mv) - sizeof(mem) -
 			sizeof(force) - sizeof(struct mvdump_parm_table)),
 	       &force, sizeof(force));
-	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2mvdump) -
+	memcpy(VOID_ADD(buffer, DATA_SIZE(eckd2dump_mv) -
 			sizeof(struct mvdump_parm_table)), &parm,
 	       sizeof(struct mvdump_parm_table));
 	*data = buffer;
-	*size = DATA_SIZE(eckd2mvdump);
+	*size = DATA_SIZE(eckd2dump_mv);
 	return 0;
 }
 
@@ -606,3 +538,30 @@ boot_get_fba_dump_stage2(void** data, si
 	*size = DATA_SIZE(fba2dump);
 	return 0;
 }
+
+void
+boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type, void *param)
+{
+	memset(boot_info, 0, sizeof(*boot_info));
+	memcpy(&boot_info->magic, BOOT_INFO_MAGIC, sizeof(boot_info->magic));
+	boot_info->flags |= BOOT_INFO_FLAGS_ARCH;
+	boot_info->dev_type = dev_type;
+	boot_info->bp_type = BOOT_INFO_BP_TYPE_DUMP;
+	boot_info->version = BOOT_INFO_VERSION;
+	memcpy(&boot_info->bp.dump.param, param,
+	       sizeof(boot_info->bp.dump.param));
+}
+
+void
+boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
+		  disk_blockptr_t *bm_ptr, struct disk_info *info)
+{
+	memset(boot_info, 0, sizeof(*boot_info));
+	memcpy(&boot_info->magic, BOOT_INFO_MAGIC, sizeof(boot_info->magic));
+	boot_info->flags |= BOOT_INFO_FLAGS_ARCH;
+	boot_info->dev_type = dev_type;
+	boot_info->bp_type = BOOT_INFO_BP_TYPE_IPL;
+	boot_info->version = BOOT_INFO_VERSION;
+	bootmap_store_blockptr(&boot_info->bp, bm_ptr, info);
+}
+
--- a/zipl/src/bootmap.c
+++ b/zipl/src/bootmap.c
@@ -19,40 +19,17 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#include "util_part.h"
 #include "boot.h"
 #include "disk.h"
 #include "error.h"
 #include "misc.h"
-
+#include "install.h"
 
 /* Header text of the bootmap file */
 static const char header_text[] = "zSeries bootmap file\n"
 				  "created by zIPL\n";
 
-/* Layout of SCSI disk block pointer */
-struct scsi_blockptr {
-	uint64_t blockno;
-	uint16_t size;
-	uint16_t blockct;
-	uint8_t reserved[4];
-} __attribute((packed));
-
-/* Layout of FBA disk block pointer */
-struct fba_blockptr {
-	uint32_t blockno;
-	uint16_t size;
-	uint16_t blockct;
-} __attribute((packed));
-
-/* Layout of ECKD disk block pointer */
-struct eckd_blockptr {
-	uint16_t cyl;
-	uint16_t head;
-	uint8_t sec;
-	uint16_t size;
-	uint8_t blockct;
-} __attribute((packed));
-
 /* Pointer to dedicated empty block in bootmap. */
 disk_blockptr_t empty_block;
 
@@ -63,11 +40,10 @@ get_blockptr_size(struct disk_info* info
 {
 	switch (info->type) {
 	case disk_type_scsi:
-		return sizeof(struct scsi_blockptr);
 	case disk_type_fba:
-		return sizeof(struct fba_blockptr);
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+		return sizeof(struct linear_blockptr);
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		return sizeof(struct eckd_blockptr);
 	case disk_type_diag:
 		break;
@@ -80,27 +56,21 @@ void
 bootmap_store_blockptr(void* buffer, disk_blockptr_t* ptr,
 		       struct disk_info* info)
 {
-	struct scsi_blockptr* scsi;
-	struct eckd_blockptr* eckd;
-	struct fba_blockptr* fba;
+	struct linear_blockptr *lin;
+	struct eckd_blockptr *eckd;
 
 	memset(buffer, 0, get_blockptr_size(info));
 	if (ptr != NULL) {
 		switch (info->type) {
 		case disk_type_scsi:
-			scsi = (struct scsi_blockptr *) buffer;
-			scsi->blockno = ptr->linear.block;
-			scsi->size = ptr->linear.size;
-			scsi->blockct = ptr->linear.blockct;
-			break;
 		case disk_type_fba:
-			fba = (struct fba_blockptr *) buffer;
-			fba->blockno = ptr->linear.block;
-			fba->size = ptr->linear.size;
-			fba->blockct = ptr->linear.blockct;
+			lin = (struct linear_blockptr *) buffer;
+			lin->blockno = ptr->linear.block;
+			lin->size = ptr->linear.size;
+			lin->blockct = ptr->linear.blockct;
 			break;
-		case disk_type_eckd_classic:
-		case disk_type_eckd_compatible:
+		case disk_type_eckd_ldl:
+		case disk_type_eckd_cdl:
 			eckd = (struct eckd_blockptr *) buffer;
 			eckd->cyl = ptr->chs.cyl;
 			eckd->head = ptr->chs.head |
@@ -327,7 +297,7 @@ add_component_file(int fd, const char* f
 			return -1;
 		}
 		/* Write buffer */
-		count = disk_write_block_buffer(fd, buffer + offset,
+		count = disk_write_block_buffer(fd, 0, buffer + offset,
 					size - offset, &list, info);
 		free(buffer);
 		if (count == 0) {
@@ -396,7 +366,7 @@ add_component_buffer(int fd, void* buffe
 	int rc;
 
 	/* Write buffer */
-	count = disk_write_block_buffer(fd, buffer, size, &list, info);
+	count = disk_write_block_buffer(fd, 0, buffer, size, &list, info);
 	if (count == 0) {
 		error_text("Could not write to bootmap file");
 		return -1;
@@ -452,7 +422,7 @@ add_ipl_program(int fd, struct job_ipl_d
 				    "initial ramdisk", "internal loader"};
 	struct component_loc comp_loc[4];
 	int rc;
-	int offset;
+	int offset, flags = 0;
 
 	memset(comp_loc, 0, sizeof(comp_loc));
 	table = misc_malloc(info->phy_block_size);
@@ -485,11 +455,18 @@ add_ipl_program(int fd, struct job_ipl_d
 			return -1;
 		}
 	}
+	if (info->type == disk_type_scsi)
+		flags |= STAGE3_FLAG_SCSI;
+	if (ipl->is_kdump)
+		flags |= STAGE3_FLAG_KDUMP;
+
 	/* Add stage 3 loader to bootmap */
 	rc = boot_get_stage3(&stage3, &stage3_size, ipl->parm_addr,
 			     ipl->ramdisk_addr, (size_t) stats.st_size,
+			     ipl->is_kdump ? ipl->image_addr + 0x10 :
 			     ipl->image_addr,
-			     (info->type == disk_type_scsi) ? 0 : 1);
+			     (info->type == disk_type_scsi) ? 0 : 1,
+			     flags);
 	if (rc) {
 		free(table);
 		return rc;
@@ -594,7 +571,7 @@ add_segment_program(int fd, struct job_s
 	rc = add_component_file(fd, segment->segment, segment->segment_addr, 0,
 				VOID_ADD(table, offset), add_files, info,
 				target, &comp_loc[0]);
-	if (rc) {
+if (rc) {
 		error_text("Could not add segment file '%s'",
 			   segment->segment);
 		free(table);
@@ -618,29 +595,27 @@ add_segment_program(int fd, struct job_s
 #define DUMP_PARAM_MAX_LEN	896
 
 static char *
-create_dump_fs_parmline(const char* parmline, const char* root_dev,
-			int part_num, uint64_t mem, int max_cpus)
+create_dump_parmline(const char* parmline, const char* root_dev,
+		     uint64_t mem, int max_cpus)
 {
 	char* result;
 
 	result = misc_malloc(DUMP_PARAM_MAX_LEN);
 	if (!result)
 		return NULL;
-	snprintf(result, DUMP_PARAM_MAX_LEN, "%s%sroot=%s dump_part=%d "
-		 "dump_mem=%lld maxcpus=%d possible_cpus=%d "
-		 "cgroup_disable=memory",
-		 parmline ? parmline : "",
-		 parmline ? " " : "", root_dev, part_num,
-		 (unsigned long long) mem, max_cpus, max_cpus);
+	snprintf(result, DUMP_PARAM_MAX_LEN, "%s%sroot=%s dump_mem=%lld "
+		 "possible_cpus=%d cgroup_disable=memory ",
+		 parmline ? parmline : "", parmline ? " " : "", root_dev,
+		 (unsigned long long) mem, max_cpus);
 	result[DUMP_PARAM_MAX_LEN - 1] = 0;
 	return result;
 }
 
 
 static int
-get_dump_fs_parmline(char* partition, char* parameters, uint64_t mem,
-		     struct disk_info* target_info,
-		     struct job_target_data* target, char** result)
+get_dump_parmline(char *partition, char *parameters,
+		  struct disk_info *target_info,
+		  struct job_target_data *target, char **result)
 {
 	char* buffer;
 	struct disk_info* info;
@@ -665,8 +640,8 @@ get_dump_fs_parmline(char* partition, ch
 		disk_free_info(info);
 		return -1;
 	}
-	buffer = create_dump_fs_parmline(parameters, "/dev/ram0", info->partnum,
-					 mem, 1);
+	buffer = create_dump_parmline(parameters, "/dev/ram0",
+				      info->partnum, 1);
 	disk_free_info(info);
 	if (buffer == NULL)
 		return -1;
@@ -676,7 +651,7 @@ get_dump_fs_parmline(char* partition, ch
 
 
 static int
-add_dump_fs_program(int fd, struct job_dump_fs_data* dump_fs,
+add_dump_program(int fd, struct job_dump_data* dump,
 		    disk_blockptr_t* program, int verbose,
 		    component_header_type type,
 		    struct disk_info* info, struct job_target_data* target)
@@ -685,17 +660,18 @@ add_dump_fs_program(int fd, struct job_d
 	int rc;
 
 	/* Convert fs dump job to IPL job */
-	ipl.image = dump_fs->image;
-	ipl.image_addr = dump_fs->image_addr;
-	ipl.ramdisk = dump_fs->ramdisk;
-	ipl.ramdisk_addr = dump_fs->ramdisk_addr;
+	memset(&ipl, 0, sizeof(ipl));
+	ipl.image = dump->image;
+	ipl.image_addr = dump->image_addr;
+	ipl.ramdisk = dump->ramdisk;
+	ipl.ramdisk_addr = dump->ramdisk_addr;
 
 	/* Get file system dump parmline */
-	rc = get_dump_fs_parmline(dump_fs->partition, dump_fs->parmline,
-				  dump_fs->mem, info, target, &ipl.parmline);
+	rc = get_dump_parmline(dump->device, dump->parmline,
+			       info, target, &ipl.parmline);
 	if (rc)
 		return rc;
-	ipl.parm_addr = dump_fs->parm_addr;
+	ipl.parm_addr = dump->parm_addr;
 	return add_ipl_program(fd, &ipl, program, verbose, 1,
 			       type, info, target);
 }
@@ -708,7 +684,7 @@ build_program_table(int fd, struct job_d
 		    struct disk_info* info)
 {
 	disk_blockptr_t* table;
-	int entries;
+	int entries, component_header;
 	int i;
 	int rc;
 
@@ -727,9 +703,13 @@ build_program_table(int fd, struct job_d
 		else
 			printf("Adding IPL section '%s' (default)\n",
 			       job->name);
+		if (job->data.ipl.is_kdump)
+			component_header = component_header_dump;
+		else
+			component_header = component_header_ipl;
 		rc = add_ipl_program(fd, &job->data.ipl, &table[0],
 				     verbose || job->command_line,
-				     job->add_files, component_header_ipl,
+				     job->add_files, component_header,
 				     info, &job->target);
 		break;
 	case job_segment:
@@ -743,13 +723,14 @@ build_program_table(int fd, struct job_d
 					 job->add_files, component_header_ipl,
 					 info, &job->target);
 		break;
-	case job_dump_fs:
+	case job_dump_partition:
+		/* Only useful for a partition dump that uses a dump kernel*/
 		if (job->command_line)
 			printf("Adding fs-dump section\n");
 		else
 			printf("Adding fs-dump section '%s' (default)\n",
 			       job->name);
-		rc = add_dump_fs_program(fd, &job->data.dump_fs, &table[0],
+		rc = add_dump_program(fd, &job->data.dump, &table[0],
 					 verbose || job->command_line,
 					 component_header_dump,
 					 info, &job->target);
@@ -760,31 +741,26 @@ build_program_table(int fd, struct job_d
 		for (i=0; i < job->data.menu.num; i++) {
 			switch (job->data.menu.entry[i].id) {
 			case job_ipl:
-				printf("Adding #%d: IPL section '%s'%s\n",
+				printf("Adding #%d: IPL section '%s'%s",
 				       job->data.menu.entry[i].pos,
 				       job->data.menu.entry[i].name,
 				       (job->data.menu.entry[i].pos ==
 				        job->data.menu.default_pos) ?
 						" (default)": "");
+				if (job->data.menu.entry[i].data.ipl.is_kdump) {
+					component_header =
+						component_header_dump;
+					printf(" (kdump)\n");
+				} else {
+					component_header =
+						component_header_ipl;
+					printf("\n");
+				}
 				rc = add_ipl_program(fd,
 					&job->data.menu.entry[i].data.ipl,
 					&table[job->data.menu.entry[i].pos],
 					verbose || job->command_line,
-					job->add_files,	component_header_ipl,
-					info, &job->target);
-				break;
-			case job_dump_fs:
-				printf("Adding #%d: fs-dump section '%s'%s\n",
-				       job->data.menu.entry[i].pos,
-				       job->data.menu.entry[i].name,
-				       (job->data.menu.entry[i].pos ==
-				        job->data.menu.default_pos) ?
-						" (default)": "");
-				rc = add_dump_fs_program(fd,
-					&job->data.menu.entry[i].data.dump_fs,
-					&table[job->data.menu.entry[i].pos],
-					verbose || job->command_line,
-					component_header_dump,
+					job->add_files,	component_header,
 					info, &job->target);
 				break;
 			case job_print_usage:
@@ -808,7 +784,6 @@ build_program_table(int fd, struct job_d
 		break;
 	case job_print_usage:
 	case job_print_version:
-	case job_dump_partition:
 	default:
 		/* Should not happen */
 		rc = -1;
@@ -843,181 +818,228 @@ write_empty_block(int fd, disk_blockptr_
 
 
 int
-bootmap_create(struct job_data* job, disk_blockptr_t* program_table,
-	       disk_blockptr_t** stage2_list, blocknum_t* stage2_count,
-	       char** new_device, struct disk_info** new_info)
+bootmap_create(struct job_data *job, disk_blockptr_t *program_table,
+	       disk_blockptr_t *scsi_dump_sb_blockptr,
+	       disk_blockptr_t **stage1b_list, blocknum_t *stage1b_count,
+	       char **new_device, struct disk_info **new_info)
 {
-	struct disk_info* info;
-	char* device;
-	char* filename;
-	char *mapname;
-	void* stage2_data;
+	struct scsi_dump_sb scsi_sb;
+	char *device, *filename, *mapname;
+	disk_blockptr_t *stage2_list;
+	blocknum_t stage2_count;
+	struct disk_info *info;
 	size_t stage2_size;
-	int fd;
-	int rc;
+	void *stage2_data;
+	int fd, rc, part_ext;
 
 	/* Get full path of bootmap file */
-	filename = misc_make_path(job->target.bootmap_dir,
-			BOOTMAP_TEMPLATE_FILENAME);
-	if (filename == NULL)
-		return -1;
-	/* Create temporary bootmap file */
-	fd = mkstemp(filename);
-	if (fd == -1) {
-		error_reason(strerror(errno));
-		error_text("Could not create file '%s':", filename);
-		free(filename);
-		return -1;
+	if (job->id == job_dump_partition && !dry_run) {
+		filename = misc_strdup(job->data.dump.device);
+		if (filename == NULL)
+			return -1;
+		fd = misc_open_exclusive(filename);
+		if (fd == -1) {
+			error_text("Could not open file '%s'", filename);
+			goto out_free_filename;
+		}
+
+	} else {
+		filename = misc_make_path(job->target.bootmap_dir,
+					  BOOTMAP_TEMPLATE_FILENAME);
+		if (filename == NULL)
+			return -1;
+		/* Create temporary bootmap file */
+		fd = mkstemp(filename);
+		if (fd == -1) {
+			error_reason(strerror(errno));
+			error_text("Could not create file '%s':", filename);
+			goto out_free_filename;
+		}
 	}
 	/* Retrieve target device information. Note that we have to
 	 * call disk_get_info_from_file() to also get the file system
 	 * block size. */
-	rc = disk_get_info_from_file(filename, &job->target, &info);
-	if (rc) {
-		close(fd);
-		free(filename);
-		return -1;
+	if (job->id == job_dump_partition) {
+		if (disk_get_info(filename, &job->target, &info))
+			goto out_close_fd;
+	} else {
+		if (disk_get_info_from_file(filename, &job->target, &info))
+			goto out_close_fd;
 	}
 	/* Check for supported disk and driver types */
 	if ((info->source == source_auto) && (info->type == disk_type_diag)) {
 		error_reason("Unsupported disk type (%s)",
 			     disk_get_type_name(info->type));
-		disk_free_info(info);
-		close(fd);
-		free(filename);
-		return -1;
+		goto out_disk_free_info;
 	}
 	if (verbose) {
 		printf("Target device information\n");
 		disk_print_info(info);
 	}
-	rc = misc_temp_dev(info->device, 1, &device);
-	if (rc) {
-		disk_free_info(info);
-		close(fd);
-		free(filename);
-		return -1;
-	}
+	if (misc_temp_dev(info->device, 1, &device))
+		goto out_disk_free_info;
 	/* Check configuration number limits */
 	if (job->id == job_menu) {
-		rc = check_menu_positions(&job->data.menu, job->name, info);
-		if (rc) {
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			close(fd);
-			free(filename);
-			return rc;
-		}
+		if (check_menu_positions(&job->data.menu, job->name, info))
+			goto out_misc_free_temp_dev;
+	}
+	if (job->id == job_dump_partition) {
+		rc = util_part_search(device, info->geo.start, info->phy_blocks,
+				      info->phy_block_size, &part_ext);
+		if (rc <= 0 || part_ext) {
+			if (rc == 0)
+				error_reason("No partition");
+			else if (rc < 0)
+				error_reason("Could not read partition table");
+			else if (part_ext)
+				error_reason("Extended partitions not allowed");
+			error_text("Invalid dump device");
+			goto out_misc_free_temp_dev;
+		}
+		printf("Building bootmap directly on partition '%s'%s\n",
+		       filename,
+		       job->add_files ? " (files will be added to partition)"
+		       : "");
+	} else {
+		printf("Building bootmap in '%s'%s\n", job->target.bootmap_dir,
+		       job->add_files ? " (files will be added to bootmap file)"
+		       : "");
+	}
+	/* For partition dump set raw partition offset
+	   to expected size before end of disk */
+	if (job->id == job_dump_partition) {
+		struct stat st;
+		ulong size;
+		ulong unused_size;
+
+		size = DIV_ROUND_UP(get_stage3_size(), info->phy_block_size);
+		/* Ramdisk */
+		if (job->data.dump.ramdisk != NULL) {
+			if (stat(job->data.dump.ramdisk, &st))
+				goto out_misc_free_temp_dev;
+			size += DIV_ROUND_UP(st.st_size, info->phy_block_size);
+			size += 1; /* For ramdisk section entry */
+		}
+		/* Kernel */
+		if (stat(job->data.dump.image, &st))
+			goto out_misc_free_temp_dev;
+		size += DIV_ROUND_UP(st.st_size - 0x10000,
+				     info->phy_block_size);
+		/* Parmfile */
+		size += DIV_ROUND_UP(DUMP_PARAM_MAX_LEN, info->phy_block_size);
+		size += 8;  /* 1x table + 1x script + 3x section + 1x empty
+			       1x header + 1x scsi dump super block */
+		if (size > info->phy_blocks) {
+			error_text("Partition too small for dump tool");
+			goto out_misc_free_temp_dev;
+		}
+		unused_size = (info->phy_blocks - size) * info->phy_block_size;
+		if (lseek(fd, unused_size, SEEK_SET) < 0)
+			goto out_misc_free_temp_dev;
+		scsi_sb.dump_size = unused_size;
 	}
-	printf("Building bootmap in '%s'%s\n", job->target.bootmap_dir,
-	       job->add_files ? " (files will be added to bootmap file)" :
-	       "");
+
 	/* Write bootmap header */
-	rc = misc_write(fd, header_text, sizeof(header_text));
-	if (rc) {
+	if (misc_write(fd, header_text, sizeof(header_text))) {
 		error_text("Could not write to file '%s'", filename);
-		misc_free_temp_dev(device);
-		disk_free_info(info);
-		close(fd);
-		free(filename);
-		return rc;
+		goto out_misc_free_temp_dev;
 	}
 	/* Write empty block to be read in place of holes in files */
-	rc = write_empty_block(fd, &empty_block, info);
-	if (rc) {
+	if (write_empty_block(fd, &empty_block, info)) {
 		error_text("Could not write to file '%s'", filename);
-		misc_free_temp_dev(device);
-		disk_free_info(info);
-		close(fd);
-		free(filename);
-		return rc;
+		goto out_misc_free_temp_dev;
 	}
 	/* Build program table */
-	rc = build_program_table(fd, job, program_table, info);
-	if (rc)
-		return rc;
+	if (build_program_table(fd, job, program_table, info))
+		goto out_misc_free_temp_dev;
+	if (job->id == job_dump_partition) {
+		scsi_sb.magic = SCSI_DUMP_SB_MAGIC;
+		scsi_sb.version = 1;
+		scsi_sb.part_start = info->geo.start * info->phy_block_size;
+		scsi_sb.part_size = info->phy_blocks * info->phy_block_size;
+		scsi_sb.dump_offset = 0;
+		scsi_sb.csum_offset = 0;
+		scsi_sb.csum_size = SCSI_DUMP_SB_CSUM_SIZE;
+		/* Set seed because otherwise csum over zero block is 0 */
+		scsi_sb.csum = SCSI_DUMP_SB_SEED;
+		disk_write_block_aligned(fd, &scsi_sb,
+					 sizeof(scsi_sb),
+					 scsi_dump_sb_blockptr, info);
+	} else
+		scsi_dump_sb_blockptr->linear.block = 0;
+
 	/* Add stage 2 loader to bootmap if necessary */
 	switch (info->type) {
 	case disk_type_fba:
-		rc = boot_get_fba_stage2(&stage2_data, &stage2_size, job);
-		if (rc) {
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			close(fd);
-			free(filename);
-			return rc;
-		}
-		*stage2_count = disk_write_block_buffer(fd, stage2_data,
-						stage2_size, stage2_list,
+		if (boot_get_fba_stage2(&stage2_data, &stage2_size, job))
+			goto out_misc_free_temp_dev;
+		stage2_count = disk_write_block_buffer(fd, 0, stage2_data,
+						stage2_size, &stage2_list,
 						info);
 		free(stage2_data);
-		if (*stage2_count == 0) {
+		if (stage2_count == 0) {
 			error_text("Could not write to file '%s'", filename);
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			close(fd);
-			free(filename);
-			return -1;
+			goto out_misc_free_temp_dev;
 		}
+		if (install_fba_stage1b(fd, stage1b_list, stage1b_count,
+					stage2_list, stage2_count, info))
+			goto out_misc_free_temp_dev;
+		free(stage2_list);
 		break;
-	case disk_type_eckd_classic:
-		rc = boot_get_eckd_stage2(&stage2_data, &stage2_size, job);
-		if (rc) {
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			close(fd);
-			free(filename);
-			return rc;
-		}
-		*stage2_count = disk_write_block_buffer(fd, stage2_data,
-						stage2_size, stage2_list,
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
+		if (boot_get_eckd_stage2(&stage2_data, &stage2_size, job))
+			goto out_misc_free_temp_dev;
+		stage2_count = disk_write_block_buffer(fd, 0, stage2_data,
+						stage2_size, &stage2_list,
 						info);
 		free(stage2_data);
-		if (*stage2_count == 0) {
+		if (stage2_count == 0) {
 			error_text("Could not write to file '%s'", filename);
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			close(fd);
-			free(filename);
-			return -1;
+			goto out_misc_free_temp_dev;
 		}
+		if (install_eckd_stage1b(fd, stage1b_list, stage1b_count,
+					 stage2_list, stage2_count, info))
+			goto out_misc_free_temp_dev;
+		free(stage2_list);
 		break;
 	case disk_type_scsi:
-	case disk_type_eckd_compatible:
 	case disk_type_diag:
-		*stage2_list = NULL;
-		*stage2_count = 0;
+		*stage1b_list = NULL;
+		*stage1b_count = 0;
 		break;
 	}
-	close(fd);
 	if (dry_run) {
 		if (remove(filename) == -1)
 			fprintf(stderr, "Warning: could not remove temporary "
 				"file %s!\n", filename);
-	} else {
+	} else if (job->id != job_dump_partition) {
 		/* Rename to final bootmap name */
 		mapname = misc_make_path(job->target.bootmap_dir,
 				BOOTMAP_FILENAME);
-		if (mapname == NULL) {
-			misc_free_temp_dev(device);
-			disk_free_info(info);
-			free(filename);
-			return -1;
-		}
-		rc = rename(filename, mapname);
-		if (rc) {
+		if (mapname == NULL)
+			goto out_misc_free_temp_dev;
+		if (rename(filename, mapname)) {
 			error_reason(strerror(errno));
 			error_text("Could not overwrite file '%s':", mapname);
-			misc_free_temp_dev(device);
-			disk_free_info(info);
 			free(mapname);
-			free(filename);
-			return rc;
+			goto out_misc_free_temp_dev;
 		}
 		free(mapname);
 	}
 	*new_device = device;
 	*new_info = info;
+	close(fd);
 	free(filename);
-	return rc;
+	return 0;
+
+out_misc_free_temp_dev:
+	misc_free_temp_dev(device);
+out_disk_free_info:
+	disk_free_info(info);
+out_close_fd:
+	close(fd);
+out_free_filename:
+	free(filename);
+	return -1;
 }
--- a/zipl/src/disk.c
+++ b/zipl/src/disk.c
@@ -26,7 +26,8 @@
 
 #include "error.h"
 #include "misc.h"
-#include "proc.h"
+#include "util_proc.h"
+#include "install.h"
 
 /* from linux/fs.h */
 #define FIBMAP			_IO(0x00,1)
@@ -75,9 +76,9 @@ disk_determine_dasd_type(struct disk_inf
 		data->type = disk_type_diag;
 	else if (strncmp(dasd_info.type, "ECKD",4) == 0) {
 		if (dasd_info.FBA_layout)
-			data->type = disk_type_eckd_classic;
+			data->type = disk_type_eckd_ldl;
 		else
-			data->type = disk_type_eckd_compatible;
+			data->type = disk_type_eckd_cdl;
 	} else {
 		error_reason("Unknown DASD type");
 		return -1;
@@ -89,8 +90,95 @@ disk_determine_dasd_type(struct disk_inf
 int
 disk_is_eckd(disk_type_t type)
 {
-	return (type == disk_type_eckd_classic ||
-		type == disk_type_eckd_compatible);
+	return (type == disk_type_eckd_ldl ||
+		type == disk_type_eckd_cdl);
+}
+
+static int
+read_block_by_offset(int fd, int blksize, uint64_t offset, char *buffer)
+{
+
+	if (lseek(fd, offset, SEEK_SET) == -1) {
+		/* Seek error. */
+		error_text("Error: Could not seek to %llu: %s!\n",
+			   (unsigned long long) offset);
+		return -1;
+	}
+
+	misc_read(fd, buffer, blksize);
+
+	return 0;
+}
+
+int
+determine_virtblk_type(struct disk_info *data, struct stat *stats)
+{
+	char *device;
+	char *buffer;
+	int fd, rc, shift, sb;
+
+	rc = 0;
+	buffer = (char *) malloc(data->phy_block_size);
+	if (!buffer)
+		return -1;
+
+	/*
+	 * The geo.start value reported for virtblk devices is based on a
+	 * 512 byte blocksize.
+	 * For DASD devices it is based on the real (most likely 4k) blocksize
+	 * and the DASD device driver reports a shifted value.
+	 * For virtblk devices we need to shift the value manually according to
+	 * the physical blocksize of the device.
+	 */
+	shift = 0;
+	for (sb = 512; sb < data->phy_block_size; sb = sb << 1)
+		shift++;
+
+	if (data->geo.heads == 15) {
+		/* assume DASD */
+		data->partnum = stats->st_rdev & DASD_PARTN_MASK;
+		data->device = stats->st_rdev & ~DASD_PARTN_MASK;
+
+		rc = misc_temp_dev(data->device, 1, &device);
+		if (rc)
+			goto out_err;
+
+		fd = open(device, O_RDONLY);
+
+		/* read 3rd record, containing the volume label */
+		read_block_by_offset(fd, data->phy_block_size,
+				     2 * data->phy_block_size, buffer);
+		misc_ebcdic_to_ascii((unsigned char *) buffer,
+				     (unsigned char *) buffer + 4);
+		/* determine dasd type by label */
+		if (!strncmp(buffer, "VOL1", 4)) {
+			data->type = disk_type_eckd_cdl;
+			data->geo.start >>= shift;
+		} else if (!strncmp(buffer, "LNX1", 4)) {
+			data->type = disk_type_eckd_ldl;
+			data->geo.start >>= shift;
+		} else if (!strncmp(buffer, "CMS1", 4)) {
+			data->type = disk_type_eckd_ldl;
+			data->geo.start >>= shift;
+		} else {
+			/* DASD label was not found,
+			 * type has to be specified by hand
+			 */
+			error_text("Failed to read DASD label, "
+				   "please specify type manually");
+			rc = -1;
+		}
+		close(fd);
+		misc_free_temp_dev(device);
+	} else {
+		data->type = disk_type_scsi;
+		data->partnum = stats->st_rdev & SCSI_PARTN_MASK;
+		data->device = stats->st_rdev & ~SCSI_PARTN_MASK;
+	}
+
+out_err:
+	free(buffer);
+	return rc;
 }
 
 int
@@ -99,8 +187,8 @@ disk_get_info(const char* device, struct
 {
 	struct stat stats;
 	struct stat script_stats;
-	struct proc_part_entry part_entry;
-	struct proc_dev_entry dev_entry;
+	struct util_proc_part_entry part_entry;
+	struct util_proc_dev_entry dev_entry;
 	struct dasd_information dasd_info;
 	struct disk_info *data;
 	int fd;
@@ -133,9 +221,9 @@ disk_get_info(const char* device, struct
 	}
 	memset((void *) data, 0, sizeof(struct disk_info));
 	/* Try to get device driver name */
-	if (proc_dev_get_entry(stats.st_rdev, 1, &dev_entry) == 0) {
+	if (util_proc_dev_get_entry(stats.st_rdev, 1, &dev_entry) == 0) {
 		data->drv_name = misc_strdup(dev_entry.name);
-		proc_dev_free_entry(&dev_entry);
+		util_proc_dev_free_entry(&dev_entry);
 	} else {
 		fprintf(stderr, "Warning: Could not determine driver name for "
 			"major %d from /proc/devices\n", major(stats.st_rdev));
@@ -153,8 +241,15 @@ disk_get_info(const char* device, struct
 		data->source = source_script;
 		/* Run targetbase script */
 		strcpy(ppn_cmd, script_file);
-		strcat(ppn_cmd, " ");
-		strcat(ppn_cmd, target->bootmap_dir);
+		if (target->bootmap_dir == NULL) {
+			/* happens in case of partition dump */
+			snprintf(ppn_cmd, sizeof(ppn_cmd), "%s %d:%d",
+				 script_file, major(stats.st_rdev),
+				 minor(stats.st_rdev));
+		} else {
+			strcat(ppn_cmd, " ");
+			strcat(ppn_cmd, target->bootmap_dir);
+		}
 		printf("Run %s\n", ppn_cmd);
 		fh = popen(ppn_cmd, "r");
 		if (fh == NULL) {
@@ -223,24 +318,6 @@ disk_get_info(const char* device, struct
 	if ((data->source == source_user) || (data->source == source_script)) {
 		data->devno = -1;
 		data->phy_block_size = target->targetblocksize;
-	} else {
-		/* Get DASD information */
-		if (ioctl(fd, BIODASDINFO, &dasd_info))
-			data->devno = -1;
-		else
-			data->devno = dasd_info.devno;
-		/* Get physical block size */
-		if (ioctl(fd, BLKSSZGET, &data->phy_block_size)) {
-			error_reason("Could not get blocksize");
-			goto out_close;
-		}
-	}
-	/* Get size of device in sectors (512 byte) */
-	if (ioctl(fd, BLKGETSIZE, &devsize)) {
-		error_reason("Could not get device size");
-		goto out_close;
-	}
-	if ((data->source == source_user) || (data->source == source_script)) {
 		data->type = target->targettype;
 		data->partnum = 0;
 		/* Get file information */
@@ -248,6 +325,7 @@ disk_get_info(const char* device, struct
 		    == 2) {
 			data->device = makedev(majnum, minnum);
 			data->targetbase = defined_as_device;
+			data->partnum = minor(stats.st_rdev) - minnum;
 		}
 		else {
 			if (stat(target->targetbase, &stats)) {
@@ -267,10 +345,15 @@ disk_get_info(const char* device, struct
 		}
 		goto type_determined;
 	}
+	if (ioctl(fd, BLKSSZGET, &data->phy_block_size)) {
+		error_reason("Could not get blocksize");
+		goto out_close;
+	}
 	/* Determine disk type */
 	if (!data->drv_name) {
 		/* Driver name cannot be read */
-		if (data->devno == -1) {
+		if (ioctl(fd, BIODASDINFO, &dasd_info)) {
+			data->devno = -1;
 			if (data->geo.start) {
 				/* SCSI partition */
 				data->type = disk_type_scsi;
@@ -284,6 +367,7 @@ disk_get_info(const char* device, struct
 			}
 		} else {
 			/* DASD */
+			data->devno = dasd_info.devno;
 			if (disk_determine_dasd_type(data, dasd_info))
 				goto out_close;
 			data->partnum = stats.st_rdev & DASD_PARTN_MASK;
@@ -291,25 +375,34 @@ disk_get_info(const char* device, struct
 		}
 	} else if (strcmp(data->drv_name, "dasd") == 0) {
 		/* Driver name is 'dasd' */
-		if (data->devno == -1) {
+		if (ioctl(fd, BIODASDINFO, &dasd_info)) {
 			error_reason("Could not determine DASD type");
 			goto out_close;
 		}
+		data->devno = dasd_info.devno;
 		if (disk_determine_dasd_type(data, dasd_info))
 			goto out_close;
 		data->partnum = stats.st_rdev & DASD_PARTN_MASK;
 		data->device = stats.st_rdev & ~DASD_PARTN_MASK;
-	} else if (strcmp(data->drv_name, "sd") == 0 ||
-		   strcmp(data->drv_name, "virtblk") == 0) {
-		/* Driver name is 'sd' or 'virtblk' */
-		if (data->devno != -1) {
-			error_reason("Unsupported device driver '%s' "
-				     "for disk type DASD", data->drv_name);
-			goto out_close;
-		}
+	} else if (strcmp(data->drv_name, "sd") == 0) {
+		/* Driver name is 'sd' */
+		data->devno = -1;
 		data->type = disk_type_scsi;
 		data->partnum = stats.st_rdev & SCSI_PARTN_MASK;
 		data->device = stats.st_rdev & ~SCSI_PARTN_MASK;
+
+	} else if (strcmp(data->drv_name, "virtblk") == 0) {
+
+		if (ioctl(fd, HDIO_GETGEO, &data->geo) != 0)
+			perror("Could not retrieve disk geometry information.");
+		if (ioctl(fd, BLKSSZGET, &data->phy_block_size) != 0)
+			perror("Could not retrieve blocksize information.");
+
+		if (determine_virtblk_type(data, &stats)) {
+			error_reason("Virtblk device type not clearly "
+				     "determined.");
+			goto out_close;
+		}
 	} else {
 		/* Driver name is unknown */
 		error_reason("Unsupported device driver '%s'", data->drv_name);
@@ -317,6 +410,12 @@ disk_get_info(const char* device, struct
 	}
 
 type_determined:
+	/* Get size of device in sectors (512 byte) */
+	if (ioctl(fd, BLKGETSIZE, &devsize)) {
+		error_reason("Could not get device size");
+		goto out_close;
+	}
+
 	/* Check for valid CHS geometry data. */
 	if (disk_is_eckd(data->type) && (data->geo.cylinders == 0 ||
 	    data->geo.heads == 0 || data->geo.sectors == 0)) {
@@ -330,9 +429,9 @@ type_determined:
 	if (data->partnum != 0)
 		data->partition = stats.st_rdev;
 	/* Try to get device name */
-	if (proc_part_get_entry(data->device, &part_entry) == 0) {
+	if (util_proc_part_get_entry(data->device, &part_entry) == 0) {
 		data->name = misc_strdup(part_entry.name);
-		proc_part_free_entry(&part_entry);
+		util_proc_part_free_entry(&part_entry);
 		if (data->name == NULL)
 			goto out_close;
 	}
@@ -350,6 +449,34 @@ out_close:
 
 }
 
+int
+disk_is_tape(const char* device)
+{
+	int fd, rc = 0;
+
+	/* Check for tape */
+	fd = open(device, O_RDWR);
+	if (fd == -1)
+		return 0;
+	if (rewind_tape(fd) == 0)
+		rc = 1;
+	close(fd);
+	return rc;
+}
+
+int
+disk_is_scsi(const char* device, struct job_target_data* target)
+{
+	struct disk_info* info;
+	int rc = 0;
+
+	if (disk_get_info(device, target, &info) == -1)
+		return 0;
+	if (info->type == disk_type_scsi)
+		rc = 1;
+	disk_free_info(info);
+	return rc;
+}
 
 int
 disk_get_info_from_file(const char* filename, struct job_target_data* target,
@@ -417,14 +544,23 @@ disk_free_info(struct disk_info* info)
  * blocknumber in the variable pointed to by PHYSICAL. Return non-zero
  * otherwise. */
 int
-disk_get_blocknum(int fd, blocknum_t logical, blocknum_t* physical,
-		  struct disk_info* info)
+disk_get_blocknum(int fd, int fd_is_basedisk, blocknum_t logical,
+		  blocknum_t* physical, struct disk_info* info)
 {
 	struct statfs buf;
 	blocknum_t phy_per_fs;
 	int mapped;
 	int subblock;
 
+	/* No file system: partition or raw disk */
+	if (info->fs_block_size == -1) {
+		if (fd_is_basedisk)
+			*physical = logical;
+		else
+			*physical = logical + info->geo.start;
+		return 0;
+	}
+
 	/* Get file system type */
 	if (fstatfs(fd, &buf)) {
 		error_reason(strerror(errno));
@@ -500,8 +636,8 @@ disk_blockptr_from_blocknum(disk_blockpt
 		ptr->linear.size = info->phy_block_size;
 		ptr->linear.blockct = 0;
 		break;
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		if (blocknum == 0) {
 			/* Special case: zero blocknum will be expanded to
 			 * size * (blockct+1) bytes of zeroes. */
@@ -528,9 +664,10 @@ disk_blockptr_from_blocknum(disk_blockpt
  * bytes are written. INFO provides information about the disk layout. Upon
  * success, return 0 and store the pointer to the resulting disk block to BLOCK
  * (if BLOCK is not NULL). Return non-zero otherwise. */
-int
-disk_write_block_aligned(int fd, const void* data, size_t bytecount,
-			 disk_blockptr_t* block, struct disk_info* info)
+static int
+disk_write_block_aligned_base(int fd, int is_base_disk, const void* data,
+			      size_t bytecount, disk_blockptr_t* block,
+			      struct disk_info* info)
 {
 	blocknum_t current_block;
 	blocknum_t blocknum;
@@ -560,13 +697,21 @@ disk_write_block_aligned(int fd, const v
 		return -1;
 	if (block != NULL) {
 		/* Store block pointer */
-		if (disk_get_blocknum(fd, current_block, &blocknum, info))
+		if (disk_get_blocknum(fd, is_base_disk, current_block,
+				      &blocknum, info))
 			return -1;
 		disk_blockptr_from_blocknum(block, blocknum, info);
 	}
 	return 0;
 }
 
+int
+disk_write_block_aligned(int fd, const void* data, size_t bytecount,
+			 disk_blockptr_t* block, struct disk_info* info)
+{
+	return disk_write_block_aligned_base(fd, 0, data, bytecount, block,
+					     info);
+}
 
 /* Write BYTECOUNT bytes from memory at location BUFFER to the file identified
  * by file descriptor FD and return the list of pointers to the disk blocks
@@ -575,8 +720,8 @@ disk_write_block_aligned(int fd, const v
  * otherwise. Note that the data is written to a file position which is aligned
  * on a block size boundary. */
 blocknum_t
-disk_write_block_buffer(int fd, const void* buffer, size_t bytecount,
-			disk_blockptr_t** blocklist,
+disk_write_block_buffer(int fd, int fd_is_basedisk, const void* buffer,
+			size_t bytecount, disk_blockptr_t** blocklist,
 			struct disk_info* info)
 {
 	disk_blockptr_t* list;
@@ -599,7 +744,8 @@ disk_write_block_buffer(int fd, const vo
 		chunk_size = bytecount - written;
 		if (chunk_size > (size_t) info->phy_block_size)
 			chunk_size = info->phy_block_size;
-		rc = disk_write_block_aligned(fd, VOID_ADD(buffer, written),
+		rc = disk_write_block_aligned_base(fd, fd_is_basedisk,
+						   VOID_ADD(buffer, written),
 				chunk_size,
 				&list[i], info);
 		if (rc) {
@@ -631,9 +777,9 @@ disk_get_type_name(disk_type_t type)
 		return "FBA disk layout";
 	case disk_type_diag:
 		return "DIAG disk layout";
-	case disk_type_eckd_classic:
+	case disk_type_eckd_ldl:
 		return "ECKD/linux disk layout";
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_cdl:
 		return "ECKD/compatible disk layout";
 	default:
 		return "Unknown disk type";
@@ -645,8 +791,8 @@ disk_get_type_name(disk_type_t type)
 int
 disk_is_large_volume(struct disk_info* info)
 {
-	return (info->type == disk_type_eckd_classic ||
-	        info->type == disk_type_eckd_compatible) &&
+	return (info->type == disk_type_eckd_ldl ||
+		info->type == disk_type_eckd_cdl) &&
 		info->geo.cylinders == 0xfffe;
 }
 
@@ -682,8 +828,8 @@ disk_print_info(struct disk_info* info)
 	}
 	if (((info->type == disk_type_fba) ||
 	     (info->type == disk_type_diag) ||
-	     (info->type == disk_type_eckd_classic) ||
-	     (info->type == disk_type_eckd_compatible)) &&
+	     (info->type == disk_type_eckd_ldl) ||
+	     (info->type == disk_type_eckd_cdl)) &&
 	     (info->source == source_auto)) {
 		printf("  DASD device number..............: %04x\n",
 		       info->devno);
@@ -721,6 +867,16 @@ disk_print_info(struct disk_info* info)
 		printf("  *) Data provided by script.\n");
 }
 
+/* Print textual representation of geo structure. */
+void
+disk_print_geo(struct disk_info *data)
+{
+		printf("  geo.heads.........:%u\n", data->geo.heads);
+		printf("  geo.sectors.......:%u\n", data->geo.sectors);
+		printf("  geo.cylinders.....:%u\n", data->geo.cylinders);
+		printf("  geo.start.........:%lu\n", data->geo.start);
+		printf("  blksize...........:%u\n", data->phy_block_size);
+}
 
 /* Check whether a block is a zero block which identifies a hole in a file.
  * Return non-zero if BLOCK is a zero block, 0 otherwise. */
@@ -731,8 +887,8 @@ disk_is_zero_block(disk_blockptr_t* bloc
 	case disk_type_scsi:
 	case disk_type_fba:
 		return block->linear.block == 0;
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		return (block->chs.cyl == 0) && (block->chs.head == 0) &&
 		       (block->chs.sec == 0);
 	default:
@@ -773,8 +929,8 @@ can_merge_blocks(disk_blockptr_t* first,
 		    second->linear.block)
 			return 1;
 		break;
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		/* Check link count limits */
 		if (((int) first->chs.blockct) +
 		    ((int) second->chs.blockct) + 1 > max_count)
@@ -804,8 +960,8 @@ merge_blocks(disk_blockptr_t* first, dis
 	case disk_type_fba:
 		first->linear.blockct += second->linear.blockct + 1;
 		break;
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		first->chs.blockct += second->chs.blockct + 1;
 		break;
 	case disk_type_diag:
@@ -883,7 +1039,7 @@ disk_get_blocklist_from_file(const char*
 	memset((void *) list, 0, sizeof(disk_blockptr_t) * count);
 	/* Build list */
 	for (i=0; i < count; i++) {
-		if (disk_get_blocknum(fd, i, &blocknum, info)) {
+		if (disk_get_blocknum(fd, 0, i, &blocknum, info)) {
 			free(list);
 			close(fd);
 			return 0;
--- a/zipl/src/install.c
+++ b/zipl/src/install.c
@@ -30,9 +30,16 @@
 #include "error.h"
 #include "misc.h"
 
-/* From linux/fs.h */
-#define BLKFLSBUF	_IO(0x12, 97)
+#define ECKD_CDL_DUMP_REC 3 /* Start record (0 based) for stage 2 and 1b */
+/* CDL record 2 = 148 byte, independent from bs, bootinfo is last structure */
+#define CDL_BOOTINFO_ADDR 112
+/* ADDRESS for bootinfo structure to be BIOS compatible in MBR */
+#define DEFAULT_BOOTINFO_ADDR 408
 
+static inline unsigned long blk_cnt(int size, struct disk_info *info)
+{
+	return (size + info->phy_block_size - 1) / info->phy_block_size;
+}
 
 /* Types of SCSI disk layouts */
 enum scsi_layout {
@@ -42,6 +49,9 @@ enum scsi_layout {
 	scsi_layout_unknown
 };
 
+/* From linux/fs.h */
+#define BLKFLSBUF	_IO(0x12, 97)
+
 
 /* Determine SCSI disk layout from the specified BOOTBLOCK. */
 static enum scsi_layout
@@ -60,19 +70,25 @@ get_scsi_layout(unsigned char* bootblock
 
 #define DISK_LAYOUT_ID 0x00000001
 
+static int
+overwrite_partition_start(int fd, struct disk_info* info, int mv_dump_magic);
+
 /* Create an IPL master boot record data structure for SCSI MBRs in memory
  * at location BUFFER. TABLE contains a pointer to the program table. INFO
  * provides information about the disk. */
 static int
 update_scsi_mbr(void* bootblock, disk_blockptr_t* table,
-		struct disk_info* info)
+		struct disk_info* info, disk_blockptr_t* scsi_dump_sb_blockptr)
 {
 	struct scsi_mbr {
 		uint8_t		magic[4];
 		uint32_t	version_id;
 		uint8_t		reserved[8];
 		uint8_t		program_table_pointer[16];
+		uint8_t		reserved2[0x50];
+		struct boot_info boot_info;
 	}  __attribute__ ((packed))* mbr;
+	struct scsi_dump_param param;
 	void* buffer;
 
 	switch (get_scsi_layout(bootblock)) {
@@ -101,6 +117,13 @@ update_scsi_mbr(void* bootblock, disk_bl
 	memcpy(&mbr->magic, ZIPL_MAGIC, ZIPL_MAGIC_SIZE);
 	mbr->version_id = DISK_LAYOUT_ID;
 	bootmap_store_blockptr(&mbr->program_table_pointer, table, info);
+	if (scsi_dump_sb_blockptr->linear.block != 0) {
+		/* Write dump boot_info */
+		param.block = scsi_dump_sb_blockptr->linear.block *
+			      scsi_dump_sb_blockptr->linear.size;
+		boot_get_dump_info(&mbr->boot_info, BOOT_INFO_DEV_TYPE_SCSI,
+				   &param);
+	}
 	return 0;
 }
 
@@ -110,7 +133,8 @@ update_scsi_mbr(void* bootblock, disk_bl
  * to the disk block containing the program table. INFO provides
  * information about the disk type. Return 0 on success, non-zero otherwise. */
 static int
-install_scsi(int fd, disk_blockptr_t* program_table, struct disk_info* info)
+install_scsi(int fd, disk_blockptr_t* program_table, struct disk_info* info,
+	     disk_blockptr_t* scsi_dump_sb_blockptr)
 {
 	unsigned char* bootblock;
 	int rc;
@@ -119,9 +143,7 @@ install_scsi(int fd, disk_blockptr_t* pr
 	if (bootblock == NULL)
 		return -1;
 	/* Read bootblock */
-	if (lseek(fd, 0, SEEK_SET) != 0) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	if (misc_seek(fd, 0)) {
 		free(bootblock);
 		return -1;
 	}
@@ -132,7 +154,8 @@ install_scsi(int fd, disk_blockptr_t* pr
 		return rc;
 	}
 	/* Put zIPL data into MBR */
-	rc = update_scsi_mbr(bootblock, program_table, info);
+	rc = update_scsi_mbr(bootblock, program_table, info,
+			     scsi_dump_sb_blockptr);
 	if (rc) {
 		free(bootblock);
 		return -1;
@@ -140,9 +163,7 @@ install_scsi(int fd, disk_blockptr_t* pr
 	/* Write MBR back to disk */
 	if (verbose)
 		printf("Writing SCSI master boot record.\n");
-	if (lseek(fd, 0, SEEK_SET) != 0) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	if (misc_seek(fd, 0)) {
 		free(bootblock);
 		return -1;
 	}
@@ -156,142 +177,116 @@ install_scsi(int fd, disk_blockptr_t* pr
 
 /* Install bootloader for initial program load from an FBA type disk. */
 static int
-install_fba(int fd, disk_blockptr_t* program_table,
-	    disk_blockptr_t* stage2_list, blocknum_t stage2_count,
-	    struct disk_info* info)
+install_fba(int fd, disk_blockptr_t *program_table,
+	    disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
+	    struct disk_info *info)
 {
 	struct boot_fba_stage0 stage0;
-	int rc;
 
-	/* Initialize stage 0 data */
-	rc = boot_init_fba_stage0(&stage0, stage2_list, stage2_count);
-	if (rc == 0) {
-		/* Store program table pointer in stage 0 loader */
-		bootmap_store_blockptr(&stage0.param1, program_table, info);
-		/* Install stage 0 */
-		rc = DRY_RUN_FUNC(misc_write(
-			fd, &stage0, sizeof(struct boot_fba_stage0)));
-	}
-	if (rc)
-		error_text("Could not write boot loader");
-	return rc;
+	/* Install stage 0 and store program table pointer */
+	if (boot_init_fba_stage0(&stage0, stage1b_list, stage1b_count))
+		return -1;
+
+	boot_get_ipl_info(&stage0.boot_info,  BOOT_INFO_DEV_TYPE_FBA,
+			  program_table, info);
+
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
+		return -1;
+
+	return 0;
 }
 
+/* Install stage1b bootloader for ECKD type disk */
+int
+install_eckd_stage1b(int fd, disk_blockptr_t **stage1b_list,
+		     blocknum_t *stage1b_count, disk_blockptr_t *stage2_list,
+		     blocknum_t stage2_count, struct disk_info *info)
+{
+	struct boot_eckd_stage1b *stage1b;
+	int stage1b_size, rc = -1;
+
+	*stage1b_list = NULL;
+	*stage1b_count = 0;
+	stage1b_size = ROUNDUP(sizeof(*stage1b), info->phy_block_size);
+	stage1b = misc_malloc(stage1b_size);
+	if (stage1b == NULL)
+		goto out;
+	memset(stage1b, 0, stage1b_size);
+	if (boot_init_eckd_stage1b(stage1b, stage2_list, stage2_count))
+		goto out_free_stage1b;
+	*stage1b_count = disk_write_block_buffer(fd, 1, stage1b, stage1b_size,
+						 stage1b_list, info);
+	if (*stage1b_count == 0)
+		goto out_free_stage1b;
+	rc = 0;
+out_free_stage1b:
+	free(stage1b);
+out:
+	return rc;
+}
 
 /* Install bootloader for initial program load from an ECKD type disk with
- * Linux/390 classic disk layout. */
+ * Linux Disk Layout. */
 static int
-install_eckd_classic(int fd, disk_blockptr_t* program_table,
-		     disk_blockptr_t* stage2_list, blocknum_t stage2_count,
-		     struct disk_info* info)
+install_eckd_ldl(int fd, disk_blockptr_t *program_table,
+		 disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
+		 struct disk_info *info)
 {
-	struct boot_eckd_stage0 stage0;
-	struct boot_eckd_classic_stage1 stage1;
-	int rc;
+	struct boot_eckd_ldl_stage0 stage0;
+	struct boot_eckd_stage1 stage1;
 
-	/* Prepare stage 0 */
-	boot_init_eckd_classic_stage0(&stage0);
 	/* Install stage 0 */
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_eckd_stage0)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return rc;
-	}
-	/* Prepare stage 1 */
-	rc = boot_init_eckd_classic_stage1(&stage1, stage2_list, stage2_count);
-	if (rc)
-		return rc;
-	/* Store program table pointer in stage 1 loader */
-	bootmap_store_blockptr(&stage1.param1, program_table, info);
-	/* Install stage 1 */
-	if (lseek(fd, info->phy_block_size, SEEK_SET) !=
-	    info->phy_block_size) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	boot_init_eckd_ldl_stage0(&stage0);
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
 		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage1,
-		sizeof(struct boot_eckd_classic_stage1)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return rc;
-	}
-	return rc;
-}
+	/* Install stage 1 and store program table pointer */
+	if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
+		return -1;
+
+	boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
+			  program_table, info);
 
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
+				     sizeof(stage0))))
+		return -1;
 
+	return 0;
+}
 
 /* Install bootloader for initial program load from an ECKD type disk with
  * OS/390 compatible disk layout. */
 static int
-install_eckd_compatible(int fd, disk_blockptr_t* program_table,
-			struct disk_info* info, struct job_data* job)
+install_eckd_cdl(int fd, disk_blockptr_t *program_table,
+		 disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
+		 struct disk_info *info)
 {
-	struct boot_eckd_stage0 stage0;
-	struct boot_eckd_compatible_stage1 stage1;
-	void* buffer;
-	size_t size;
-	int rc;
+	struct boot_eckd_cdl_stage0 stage0;
+	struct boot_eckd_stage1 stage1;
 
-	/* Prepare stage 0 */
-	boot_init_eckd_compatible_stage0(&stage0);
 	/* Install stage 0 */
-	if (lseek(fd, 4, SEEK_SET) != 4) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	boot_init_eckd_cdl_stage0(&stage0);
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 4)))
 		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_eckd_stage0)));
-	if (rc) {
-		error_text("Could not write boot loader");
+	/* Install stage 1 and store program table pointer */
+	if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
 		return -1;
-	}
-	/* Prepare stage 1 */
-	rc = boot_init_eckd_compatible_stage1(&stage1, info);
-	if (rc)
-		return rc;
-	/* Store program table pointer in stage 1 loader */
-	bootmap_store_blockptr(&stage1.param1, program_table, info);
-	/* Install stage 1 */
-	if (lseek(fd, 4 + info->phy_block_size, SEEK_SET) !=
-	    4 + info->phy_block_size) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage1,
-		sizeof(struct boot_eckd_compatible_stage1)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return -1;
-	}
-	/* Install stage 2 */
-	if (lseek(fd, 3 * info->phy_block_size, SEEK_SET) !=
-	    3 * info->phy_block_size) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = boot_get_eckd_stage2(&buffer, &size, job);
-	if (rc)
+
+	boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
+			  program_table, info);
+
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
+				     4 + info->phy_block_size)))
 		return -1;
-	rc = DRY_RUN_FUNC(misc_write(fd, buffer, size));
-	if (rc)
-		error_text("Could not write boot loader");
-	free(buffer);
-	return rc;
+	return 0;
 }
 
-
 int
-install_bootloader(const char* device, disk_blockptr_t *program_table,
-		   disk_blockptr_t* stage2_list, blocknum_t stage2_count,
-		   struct disk_info* info, struct job_data* job)
+install_bootloader(const char *device, disk_blockptr_t *program_table,
+		   disk_blockptr_t *scsi_dump_sb_blockptr,
+		   disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
+		   struct disk_info *info, struct job_data *job)
 {
-	int fd;
-	int rc;
+	int fd, rc;
 
 	/* Inform user about what we're up to */
 	printf("Preparing boot device: ");
@@ -326,18 +321,22 @@ install_bootloader(const char* device, d
 	rc = -1;
 	switch (info->type) {
 	case disk_type_scsi:
-		rc = install_scsi(fd, program_table, info);
+		rc = install_scsi(fd, program_table, info,
+				  scsi_dump_sb_blockptr);
+		if (rc == 0 && job->id == job_dump_partition)
+			rc = overwrite_partition_start(fd, info, 0);
 		break;
 	case disk_type_fba:
-		rc = install_fba(fd, program_table, stage2_list, stage2_count,
-				 info);
+		rc = install_fba(fd, program_table, stage1b_list,
+				 stage1b_count, info);
 		break;
-	case disk_type_eckd_classic:
-		rc = install_eckd_classic(fd, program_table, stage2_list,
-					  stage2_count, info);
+	case disk_type_eckd_ldl:
+		rc = install_eckd_ldl(fd, program_table, stage1b_list,
+				      stage1b_count, info);
 		break;
-	case disk_type_eckd_compatible:
-		rc = install_eckd_compatible(fd, program_table, info, job);
+	case disk_type_eckd_cdl:
+		rc = install_eckd_cdl(fd, program_table, stage1b_list,
+				      stage1b_count, info);
 		break;
 	case disk_type_diag:
 		/* Should not happen */
@@ -367,7 +366,7 @@ install_bootloader(const char* device, d
 
 /* Rewind the tape device identified by FD. Return 0 on success, non-zero
  * otherwise. */
-static int
+int
 rewind_tape(int fd)
 {
 	struct mtop op;
@@ -381,7 +380,6 @@ rewind_tape(int fd)
 		return 0;
 }
 
-
 static int
 ask_for_confirmation(const char* fmt, ...)
 {
@@ -638,11 +636,8 @@ overwrite_partition_start(int fd, struct
 	const char dump_magic[] = {0xa8, 0x19, 0x01, 0x73,
 		0x61, 0x8f, 0x23, 0xfd};
 
-	if (lseek(fd, info->geo.start * info->phy_block_size, SEEK_SET) !=
-	    (off_t) info->geo.start * info->phy_block_size) {
-		error_text("Could not seek on device");
+	if (misc_seek(fd, info->geo.start * info->phy_block_size))
 		return -1;
-	}
 	if (info->phy_block_size * info->phy_blocks < bytes)
 		bytes = info->phy_block_size * info->phy_blocks;
 	buffer = calloc(1, bytes);
@@ -686,270 +681,241 @@ static int check_eckd_dump_partition(str
 	return 0;
 }
 
-struct eckd_dump_param {
-	uint32_t	start_blk;
-	uint32_t	end_blk;
-	uint16_t	blocksize;
-	uint8_t		num_heads;
-	uint8_t		bpt;
-	char		reserved[4];
-} __attribute((packed, may_alias));
-
-static void eckd_dump_store_param(struct eckd_dump_param* param,
-				  struct disk_info* info)
+static void eckd_dump_store_param(struct eckd_dump_param *param,
+				  struct disk_info *info, blocknum_t count)
 {
 	param->start_blk = info->geo.start;
-	param->end_blk = info->geo.start + info->phy_blocks - 1;
+	param->end_blk = info->geo.start + info->phy_blocks - 1 - count;
 	param->num_heads = info->geo.heads;
 	param->blocksize = info->phy_block_size;
-	param->bpt = disk_sec_from_blocknum(param->end_blk, info);
+	param->bpt = info->geo.sectors;
 }
 
-static int
-install_dump_eckd_classic(int fd, struct disk_info* info, uint64_t mem)
+static int install_svdump_eckd_ldl(int fd, struct disk_info *info, uint64_t mem)
 {
-	struct boot_eckd_stage0 stage0;
-	struct boot_eckd_classic_stage1 stage1;
-	void* buffer;
-	size_t size;
-	int rc;
+	disk_blockptr_t *stage2_list, *stage1b_list;
+	blocknum_t stage2_count, stage1b_count;
+	struct boot_eckd_ldl_stage0 stage0;
+	struct boot_eckd_stage1 stage1;
+	struct eckd_dump_param param;
+	size_t stage2_size;
+	void *stage2;
+	int rc = -1;
+
+	if (boot_get_eckd_dump_stage2(&stage2, &stage2_size, mem))
+		goto out;
+	if (blk_cnt(stage2_size, info) > STAGE2_BLK_CNT_MAX) {
+		error_reason("ECKD dump record is too large");
+		goto out_free_stage2;
+	}
+	if (overwrite_partition_start(fd, info, 0))
+		goto out_free_stage2;
+	/* Install stage 2 and stage 1b to beginning of partition */
+	if (misc_seek(fd, info->geo.start * info->phy_block_size))
+		goto out_free_stage2;
+	stage2_count = disk_write_block_buffer(fd, 1, stage2, stage2_size,
+					       &stage2_list, info);
+	if (stage2_count == 0)
+		goto out_free_stage2_list;
+	if (install_eckd_stage1b(fd, &stage1b_list, &stage1b_count,
+				 stage2_list, stage2_count, info))
+		goto out_free_stage2_list;
+	/* Install stage 0 - afterwards we are at stage 1 position*/
+	boot_init_eckd_ldl_stage0(&stage0);
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
+		goto out_free_stage1b_list;
+	/* Install stage 1 and fill in dump partition parameter */
+	if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
+		goto out_free_stage1b_list;
+
+	eckd_dump_store_param(&param, info, 0);
+	boot_get_dump_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD, &param);
+
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
+				     sizeof(stage0))))
+		goto out_free_stage1b_list;
+	rc = 0;
+out_free_stage1b_list:
+	free(stage1b_list);
+out_free_stage2_list:
+	free(stage2_list);
+out_free_stage2:
+	free(stage2);
+out:
+	return rc;
+}
 
-	/* Prepare stage 0 */
-	boot_init_eckd_classic_stage0(&stage0);
-	/* Install stage 0 */
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_eckd_stage0)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return rc;
-	}
-	/* Prepare stage 1 */
-	rc = boot_init_eckd_classic_dump_stage1(&stage1, info);
-	if (rc)
-		return rc;
-	/* Fill in dump partition parameter */
-	eckd_dump_store_param((struct eckd_dump_param *) &stage1.param1, info);
-	/* Install stage 1 */
-	if (lseek(fd, info->phy_block_size, SEEK_SET) !=
-	    info->phy_block_size) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage1,
-		sizeof(struct boot_eckd_classic_stage1)));
-	if (rc) {
-		error_text("Could not write dump record");
-		return rc;
-	}
-	/* Overwrite first 64k of partition */
-	rc = overwrite_partition_start(fd, info, 0);
-	if (rc)
-		return rc;
-	/* Install stage 2 dump record at beginning of partition */
-	if (lseek(fd, info->geo.start * info->phy_block_size, SEEK_SET) !=
-	    (off_t) info->geo.start * info->phy_block_size) {
-		error_text("Could not seek on device");
-		return -1;
+static int install_dump_eckd_cdl(int fd, struct disk_info *info, void *stage2,
+				 size_t stage2_size, int mvdump, int force)
+{
+	blocknum_t count, stage2_count, stage1b_count;
+	disk_blockptr_t *stage2_list, *stage1b_list;
+	struct boot_eckd_cdl_stage0 stage0_cdl;
+	struct boot_eckd_stage1 stage1;
+	struct eckd_dump_param param;
+	int rc = -1;
+
+	count = blk_cnt(stage2_size, info);
+	if (count > STAGE2_BLK_CNT_MAX) {
+		error_reason("ECKD dump record is too large");
+		goto out;
+	}
+	count += blk_cnt(sizeof(struct boot_eckd_stage1b), info);
+	if (count > (blocknum_t) info->geo.sectors - ECKD_CDL_DUMP_REC) {
+		error_reason("ECKD dump record is too large");
+		goto out;
 	}
-	rc = boot_get_eckd_dump_stage2(&buffer, &size, mem);
-	if (rc)
-		return rc;
-	rc = DRY_RUN_FUNC(misc_write(fd, buffer, size));
-	if (rc)
-		error_text("Could not write dump record");
-	free(buffer);
+	/* Install stage 2 */
+	if (misc_seek(fd, ECKD_CDL_DUMP_REC * info->phy_block_size))
+		goto out;
+	stage2_count = disk_write_block_buffer(fd, 1, stage2, stage2_size,
+					       &stage2_list, info);
+	if (stage2_count == 0)
+		goto out;
+	/* Install stage 1b behind stage 2*/
+	if (install_eckd_stage1b(fd, &stage1b_list, &stage1b_count,
+				 stage2_list, stage2_count, info))
+		goto out_free_stage2_list;
+	/* Install stage 0 */
+	boot_init_eckd_cdl_stage0(&stage0_cdl);
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0_cdl, sizeof(stage0_cdl), 4)))
+		goto out_free_stage1b_list;
+	/* Install stage 1 and fill in dump partition parameter */
+	if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
+		goto out_free_stage1b_list;
+
+	eckd_dump_store_param(&param, info, 0);
+	boot_get_dump_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD, &param);
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
+				     info->phy_block_size + 4)))
+		goto out_free_stage1b_list;
+	if (!force && overwrite_partition_start(fd, info, mvdump))
+		goto out_free_stage1b_list;
+	rc = 0;
+out_free_stage1b_list:
+	free(stage1b_list);
+out_free_stage2_list:
+	free(stage2_list);
+out:
 	return rc;
 }
 
-
 static int
-install_dump_eckd_compatible(int fd, struct disk_info* info, uint64_t mem)
+install_svdump_eckd_cdl(int fd, struct disk_info *info, uint64_t mem)
 {
-	struct boot_eckd_stage0 stage0;
-	struct boot_eckd_compatible_stage1 stage1;
-	void* buffer;
-	size_t size;
+	size_t stage2_size;
+	void *stage2;
 	int rc;
 
-	/* Prepare stage 0 */
-	boot_init_eckd_compatible_stage0(&stage0);
-	/* Install stage 0 */
-	if (lseek(fd, 4, SEEK_SET) != 4) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_eckd_stage0)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return rc;
-	}
-	/* Prepare stage 1 */
-	rc = boot_init_eckd_compatible_dump_stage1(&stage1, info, 0);
-	if (rc)
-		return rc;
-	/* Fill in dump partition parameter */
-	eckd_dump_store_param((struct eckd_dump_param *) &stage1.param1, info);
-	/* Install stage 1 */
-	if (lseek(fd, info->phy_block_size + 4, SEEK_SET) !=
-	    info->phy_block_size + 4) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	if (boot_get_eckd_dump_stage2(&stage2, &stage2_size, mem))
 		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage1,
-			sizeof(struct boot_eckd_compatible_stage1)));
-	if (rc) {
-		error_text("Could not write dump record");
-		return rc;
-	}
-	/* Install stage 2 dump record */
-	if (lseek(fd, 3 * info->phy_block_size, SEEK_SET) !=
-	    3 * info->phy_block_size) {
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = boot_get_eckd_dump_stage2(&buffer, &size, mem);
-	if (rc)
-		return rc;
-	rc = DRY_RUN_FUNC(misc_write(fd, buffer, size));
-	if (rc) {
-		error_text("Could not write dump record");
-		return rc;
-	}
-	free(buffer);
-	return overwrite_partition_start(fd, info, 0);
+	rc = install_dump_eckd_cdl(fd, info, stage2, stage2_size, 0, 0);
+	free(stage2);
+	return rc;
 }
 
-
 static int
-install_mvdump_eckd_compatible(int fd, struct disk_info* info, uint64_t mem,
-			       uint8_t force, struct mvdump_parm_table parm)
+install_mvdump_eckd_cdl(int fd, struct disk_info *info, uint64_t mem,
+			uint8_t force, struct mvdump_parm_table parm)
 {
-	struct boot_eckd_stage0 stage0;
-	struct boot_eckd_compatible_stage1 stage1;
-	void* buffer;
-	size_t size;
+	size_t stage2_size;
+	void *stage2;
 	int rc;
 
-	/* Prepare stage 0 */
-	boot_init_eckd_compatible_stage0(&stage0);
-	/* Install stage 0 */
-	if (lseek(fd, 4, SEEK_SET) != 4) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
+	/* Write stage 2 + parameter block */
+	if (boot_get_eckd_mvdump_stage2(&stage2, &stage2_size, mem,
+					force, parm))
 		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_eckd_stage0)));
-	if (rc) {
-		error_text("Could not write boot loader");
-		return rc;
-	}
-	/* Prepare stage 1 */
-	rc = boot_init_eckd_compatible_dump_stage1(&stage1, info, 1);
-	if (rc)
-		return rc;
-	/* Install stage 1 */
-	if (lseek(fd, info->phy_block_size + 4, SEEK_SET) !=
-	    info->phy_block_size + 4) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage1,
-			sizeof(struct boot_eckd_compatible_stage1)));
-	if (rc) {
-		error_text("Could not write dump record");
-		return rc;
-	}
-	/* Install stage 2 dump record */
-	if (lseek(fd, 3 * info->phy_block_size, SEEK_SET) !=
-	    3 * info->phy_block_size) {
-		error_text("Could not seek on device");
-		return -1;
-	}
-	rc = boot_get_eckd_mvdump_stage2(&buffer, &size, mem, force, parm);
-	if (rc)
-		return rc;
-	rc = DRY_RUN_FUNC(misc_write(fd, buffer, size));
-	free(buffer);
-	if (rc) {
-		error_text("Could not write dump record");
-		return rc;
-	}
-	return overwrite_partition_start(fd, info, 1);
+	rc = install_dump_eckd_cdl(fd, info, stage2, stage2_size, 1, force);
+	free(stage2);
+	return rc;
 }
 
+int
+install_fba_stage1b(int fd, disk_blockptr_t **stage1b_list,
+		    blocknum_t *stage1b_count, disk_blockptr_t *stage2_list,
+		    blocknum_t stage2_count, struct disk_info *info)
+{
+	struct boot_fba_stage1b *stage1b;
+	int stage1b_size, rc = -1;
+
+	*stage1b_list = NULL;
+	*stage1b_count = 0;
+	stage1b_size = ROUNDUP(sizeof(*stage1b), info->phy_block_size);
+	stage1b = misc_malloc(stage1b_size);
+	if (stage1b == NULL)
+		goto out;
+	memset(stage1b, 0, stage1b_size);
+	if (boot_init_fba_stage1b(stage1b, stage2_list, stage2_count))
+		goto out_free_stage1b;
+	*stage1b_count = disk_write_block_buffer(fd, 1, stage1b, stage1b_size,
+						 stage1b_list, info);
+	if (*stage1b_count == 0)
+		goto out_free_stage1b;
+	rc = 0;
+out_free_stage1b:
+	free(stage1b);
+out:
+	return rc;
+}
 
 static int
-install_dump_fba(int fd, struct disk_info* info, uint64_t mem)
+install_svdump_fba(int fd, struct disk_info *info, uint64_t mem)
 {
+	blocknum_t stage1b_count, stage2_count, blk;
+	disk_blockptr_t *stage1b_list, *stage2_list;
 	struct boot_fba_stage0 stage0;
-	disk_blockptr_t stage2_list[16];
-	blocknum_t block;
-	blocknum_t count;
-	void* buffer;
-	size_t size;
-	int rc;
-	blocknum_t  i;
+	struct fba_dump_param param;
+	size_t stage2_size;
+	void *stage2;
+	int rc = -1;
 
 	/* Overwrite first 64k of partition */
-	rc = overwrite_partition_start(fd, info, 0);
-	if (rc)
-		return rc;
-	/* Install stage 2 dump record at end of partition */
-	rc = boot_get_fba_dump_stage2(&buffer, &size, mem);
-	if (rc)
-		return rc;
-	count = (size + info->phy_block_size - 1) / info->phy_block_size;
-	if (count > 16) {
+	if (overwrite_partition_start(fd, info, 0))
+		goto out;
+	/* Install stage 2 at end of partition */
+	if (boot_get_fba_dump_stage2(&stage2, &stage2_size, mem))
+		goto out;
+	if (blk_cnt(stage2_size, info) > STAGE2_BLK_CNT_MAX) {
 		error_reason("FBA dump record is too large");
-		free(buffer);
-		return -1;
-	}
-	block = info->geo.start + info->phy_blocks - count;
-	if (lseek(fd, block * info->phy_block_size, SEEK_SET) !=
-	    (off_t) block * info->phy_block_size) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		free(buffer);
-		return -1;
-	}
-	rc = DRY_RUN_FUNC(misc_write(fd, buffer, size));
-	free(buffer);
-	if (rc) {
-		error_text("Could not write to device");
-		return rc;
-	}
-	for (i=0; i < count; i++) {
-		stage2_list[i].linear.block = block + i;
-		stage2_list[i].linear.size = info->phy_block_size;
-		stage2_list[i].linear.blockct = 0;
-	}
-	/* Prepare stage 0 */
-	rc = boot_init_fba_stage0(&stage0, stage2_list, count);
-	if (rc)
-		return rc;
-	/* Fill in dump parameters */
-	stage0.param1 = (uint64_t) info->geo.start;
-	stage0.param2 = (uint64_t) block - 1;
-	/* Install stage 0 */
-	if (lseek(fd, 0, SEEK_SET) != 0) {
-		error_reason(strerror(errno));
-		error_text("Could not seek on device");
-		return -1;
+		goto out_free_stage2;
 	}
-	rc = DRY_RUN_FUNC(misc_write(fd, &stage0,
-		sizeof(struct boot_fba_stage0)));
-	if (rc)
-		error_text("Could not write dump record");
+	blk = (info->geo.start + info->phy_blocks - blk_cnt(stage2_size, info));
+	if (misc_seek(fd, blk * info->phy_block_size))
+		goto out_free_stage2;
+	stage2_count = disk_write_block_buffer(fd, 1, stage2, stage2_size,
+					       &stage2_list, info);
+	if (stage2_count == 0)
+		goto out_free_stage2;
+	/* Install stage 1b in front of stage 2 */
+	blk -= blk_cnt(sizeof(struct boot_fba_stage1b), info);
+	if (misc_seek(fd, blk * info->phy_block_size))
+		goto out_free_stage2_list;
+	if (install_fba_stage1b(fd, &stage1b_list, &stage1b_count,
+				stage2_list, stage2_count, info))
+		goto out_free_stage2_list;
+	/* Install stage 0/1 fill in dump partition parameter */
+	if (boot_init_fba_stage0(&stage0, stage1b_list, stage1b_count))
+		goto out_free_stage1b_list;
+
+	param.start_blk = (uint64_t) info->geo.start;
+	param.blockct = (uint64_t) blk - 1;
+	boot_get_dump_info(&stage0.boot_info, BOOT_INFO_DEV_TYPE_FBA, &param);
+
+	if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
+		goto out_free_stage1b_list;
+
+	rc = 0;
+out_free_stage1b_list:
+	free(stage1b_list);
+out_free_stage2_list:
+	free(stage2_list);
+out_free_stage2:
+	free(stage2);
+out:
 	return rc;
 }
 
-
 static int
 install_dump_tape(int fd, uint64_t mem)
 {
@@ -977,9 +943,8 @@ install_dump(const char* device, struct
 	int fd;
 	int rc;
 
-	fd = open(device, O_RDWR);
+	fd = misc_open_exclusive(device);
 	if (fd == -1) {
-		error_reason(strerror(errno));
 		error_text("Could not open dump device '%s'", device);
 		return -1;
 	}
@@ -1040,8 +1005,8 @@ install_dump(const char* device, struct
 		return -1;
 	}
 	switch (info->type) {
-	case disk_type_eckd_classic:
-	case disk_type_eckd_compatible:
+	case disk_type_eckd_ldl:
+	case disk_type_eckd_cdl:
 		if (check_eckd_dump_partition(info)) {
 			error_text("Dump target '%s'", device);
 			rc = -1;
@@ -1050,8 +1015,8 @@ install_dump(const char* device, struct
 		/* Fall through. */
 	case disk_type_fba:
 		part_size = info->phy_block_size * info->phy_blocks;
-		printf("Dump target: partition '%s' with a size of "
-		       "%ld MB.\n", device, (long) part_size >> 20);
+		printf("Dump target: partition '%s' with a size of %llu MB.\n",
+		       device, (unsigned long long) part_size >> 20);
 		rc = ask_for_confirmation("Warning: All information on "
 					  "partition '%s' will be lost!\n"
 					  "Do you want to continue creating "
@@ -1062,12 +1027,12 @@ install_dump(const char* device, struct
 			printf("Installing dump record on partition with %s\n",
 			       disk_get_type_name(info->type));
 		}
-		if (info->type == disk_type_eckd_classic)
-			rc = install_dump_eckd_classic(fd, info, mem);
-		else if (info->type == disk_type_eckd_compatible)
-			rc = install_dump_eckd_compatible(fd, info, mem);
+		if (info->type == disk_type_eckd_ldl)
+			rc = install_svdump_eckd_ldl(fd, info, mem);
+		else if (info->type == disk_type_eckd_cdl)
+			rc = install_svdump_eckd_cdl(fd, info, mem);
 		else
-			rc = install_dump_fba(fd, info, mem);
+			rc = install_svdump_fba(fd, info, mem);
 		break;
 	case disk_type_scsi:
 		error_reason("%s: Unsupported disk type '%s' (try --dumptofs)",
@@ -1106,9 +1071,8 @@ install_mvdump(char* const device[], str
 	parm.num_param = count;
 	parm.timestamp = (time.tv_sec << 20) + time.tv_usec;
 	for (i = 0; i < count; i++) {
-		fd = open(device[i], O_RDWR);
+		fd = misc_open_exclusive(device[i]);
 		if (fd == -1) {
-			error_reason(strerror(errno));
 			error_text("Could not open dump target '%s'",
 				   device[i]);
 			rc = -1;
@@ -1136,7 +1100,7 @@ install_mvdump(char* const device[], str
 			rc = -1;
 			goto out;
 		}
-		if (info[i]->type != disk_type_eckd_compatible) {
+		if (info[i]->type != disk_type_eckd_cdl) {
 			error_reason("Dump target '%s' has to be ECKD DASD "
 				     "with cdl format.", device[i]);
 			rc = -1;
@@ -1164,10 +1128,7 @@ install_mvdump(char* const device[], str
 		parm.param[i].start_blk = info[i]->geo.start;
 		parm.param[i].end_blk = info[i]->geo.start +
 					info[i]->phy_blocks - 1;
-		parm.param[i].end_sec =
-			disk_sec_from_blocknum(info[i]->geo.start +
-					       info[i]->phy_blocks - 1,
-					       info[i]);
+		parm.param[i].bpt = info[i]->geo.sectors;
 		parm.param[i].num_heads = info[i]->geo.heads;
 		parm.param[i].blocksize = info[i]->phy_block_size >> 8;
 		parm.param[i].devno = info[i]->devno;
@@ -1200,7 +1161,7 @@ install_mvdump(char* const device[], str
 			rc = -1;
 			goto out;
 		}
-		fd = open(tempdev, O_RDWR);
+		fd = misc_open_exclusive(tempdev);
 		if (fd == -1) {
 			error_text("Could not open temporary device node '%s'",
 				   tempdev);
@@ -1211,8 +1172,7 @@ install_mvdump(char* const device[], str
 		if (verbose)
 			printf("Installing dump record on target partition "
 			       "'%s'\n", device[i]);
-		rc = install_mvdump_eckd_compatible(fd, info[i], mem, force,
-						    parm);
+		rc = install_mvdump_eckd_cdl(fd, info[i], mem, force, parm);
 		misc_free_temp_dev(tempdev);
 
 		if (fsync(fd))
--- a/zipl/src/job.c
+++ b/zipl/src/job.c
@@ -50,11 +50,12 @@ static struct option options[] = {
 	{ "tape",		required_argument,	NULL, 'T'},
 	{ "dry-run",		no_argument,		NULL, '0'},
 	{ "force",		no_argument,		NULL, 'f'},
+	{ "kdump",		required_argument,	NULL, 'k'},
 	{ NULL,			0,			NULL, 0 }
 };
 
 /* Command line option abbreviations */
-static const char option_string[] = "-c:t:i:r:p:P:d:D:M:s:m:hHnVvaT:f";
+static const char option_string[] = "-c:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
 
 struct command_line {
 	char* data[SCAN_KEYWORD_NUM];
@@ -109,9 +110,9 @@ get_command_line(int argc, char* argv[],
 					  optarg);
 			break;
 		case 'D':
-			is_keyword = 1;
-			rc = store_option(&cmdline, scan_keyword_dumptofs,
-					  optarg);
+			error_reason("dumptofs has been deprecated, use "
+				     "--dump instead");
+			rc = -1;
 			break;
 		case 'M':
 			is_keyword = 1;
@@ -183,6 +184,11 @@ get_command_line(int argc, char* argv[],
 			rc = store_option(&cmdline, scan_keyword_tape,
 					  optarg);
 			break;
+		case 'k':
+			is_keyword = 1;
+			rc = store_option(&cmdline, scan_keyword_kdump,
+					  optarg);
+			break;
 		case 'c':
 			if (cmdline.config != NULL) {
 				error_reason("Option 'config' specified more "
@@ -337,10 +343,10 @@ free_segment_data(struct job_segment_dat
 
 
 static void
-free_dump_fs_data(struct job_dump_fs_data* data)
+free_dump_data(struct job_dump_data* data)
 {
-	if (data->partition != NULL)
-		free(data->partition);
+	if (data->device != NULL)
+		free(data->device);
 	if (data->image != NULL)
 		free(data->image);
 	if (data->parmline != NULL)
@@ -363,9 +369,9 @@ free_menu_data(struct job_menu_data* dat
 			case job_ipl:
 				free_ipl_data(&data->entry[i].data.ipl);
 				break;
-			case job_dump_fs:
-				free_dump_fs_data(
-					&data->entry[i].data.dump_fs);
+			case job_dump_partition:
+				free_dump_data(
+					&data->entry[i].data.dump);
 				break;
 			default:
 				break;
@@ -377,14 +383,6 @@ free_menu_data(struct job_menu_data* dat
 
 
 void
-free_dump_data(struct job_dump_data* data)
-{
-	if (data->device != NULL)
-		free(data->device);
-}
-
-
-void
 free_mvdump_data(struct job_mvdump_data* data)
 {
 	int i;
@@ -421,9 +419,6 @@ job_free(struct job_data* job)
 	case job_mvdump:
 		free_mvdump_data(&job->data.mvdump);
 		break;
-	case job_dump_fs:
-		free_dump_fs_data(&job->data.dump_fs);
-		break;
 	case job_ipl_tape:
 		free_ipl_tape_data(&job->data.ipl_tape);
 		break;
@@ -534,7 +529,7 @@ error:
 
 
 static int
-get_dump_fs_components(struct job_dump_fs_data *dump_fs,
+get_dump_components(struct job_dump_data *dump,
 		       struct component_loc **clp, int *nump)
 {
 	struct component_loc *cl;
@@ -547,19 +542,19 @@ get_dump_fs_components(struct job_dump_f
 		return -1;
 	/* Fill in component data */
 	num = 0;
-	rc = set_cl_element(&cl[num++], "kernel image", dump_fs->image,
-			    &dump_fs->image_addr, 0, 0x10000,
+	rc = set_cl_element(&cl[num++], "kernel image", dump->image,
+			    &dump->image_addr, 0, 0x10000,
 			    MAXIMUM_PHYSICAL_BLOCKSIZE);
 	if (rc)
 		goto error;
-	rc = set_cl_element(&cl[num++], "parmline", NULL, &dump_fs->parm_addr,
+	rc = set_cl_element(&cl[num++], "parmline", NULL, &dump->parm_addr,
 			    MAXIMUM_PARMLINE_SIZE, 0,
 			    MAXIMUM_PHYSICAL_BLOCKSIZE);
 	if (rc)
 		goto error;
-	if (dump_fs->ramdisk) {
+	if (dump->ramdisk) {
 		rc = set_cl_element(&cl[num++], "initial ramdisk",
-				    dump_fs->ramdisk, &dump_fs->ramdisk_addr,
+				    dump->ramdisk, &dump->ramdisk_addr,
 				    0, 0, 0x10000);
 		if (rc)
 			goto error;
@@ -619,7 +614,8 @@ error:
 
 
 static int
-check_component_address_data(struct component_loc *cl, int num, char *name)
+check_component_address_data(struct component_loc *cl, int num, char *name,
+			     unsigned long address_limit)
 {
 	int i;
 
@@ -627,12 +623,12 @@ check_component_address_data(struct comp
 	for (i = 0; i < num; i++) {
 		if (*cl[i].addrp == UNSPECIFIED_ADDRESS)
 			continue;
-		if (*cl[i].addrp + cl[i].size > ADDRESS_LIMIT) {
+		if (*cl[i].addrp + cl[i].size > address_limit) {
 			if (name != NULL)
 				error_text("Section '%s'", name);
 			error_reason("Component '%s' exceeds available address "
 				     "space (limit is 0x%08x)", cl[i].name,
-				     ADDRESS_LIMIT);
+				     address_limit);
 			return -1;
 		}
 		if (*cl[i].addrp < MINIMUM_ADDRESS) {
@@ -662,7 +658,8 @@ check_component_address_data(struct comp
 
 
 static int
-finalize_component_address_data(struct component_loc *cl, int num)
+finalize_component_address_data(struct component_loc *cl, int num,
+				unsigned long address_limit)
 {
 	struct component_loc swap;
 	address_t addr;
@@ -685,7 +682,7 @@ finalize_component_address_data(struct c
 					addr = MINIMUM_ADDRESS;
 			}
 			addr = ALIGN(addr, cl[i].align);
-			if (addr + cl[i].size > ADDRESS_LIMIT) {
+			if (addr + cl[i].size > address_limit) {
 				error_text("Could not fit component '%s' into "
 					   "available address space",
 					   cl[i].name);
@@ -715,18 +712,20 @@ finalize_component_address_data(struct c
 static int
 finalize_ipl_address_data(struct job_ipl_data* ipl, char *name)
 {
+	unsigned long address_limit;
 	struct component_loc *cl;
 	int num;
 	int rc;
 
+	address_limit = ipl->is_kdump ? ADDRESS_LIMIT_KDUMP : ADDRESS_LIMIT;
 	rc = get_ipl_components(ipl, &cl, &num);
 	if (rc)
 		return rc;
 	sort_cl_array(cl, num);
-	rc = check_component_address_data(cl, num, name);
+	rc = check_component_address_data(cl, num, name, address_limit);
 	if (rc)
 		goto out_free;
-	rc = finalize_component_address_data(cl, num);
+	rc = finalize_component_address_data(cl, num, address_limit);
 out_free:
 	free(cl);
 	return rc;
@@ -734,20 +733,20 @@ out_free:
 
 
 static int
-finalize_dump_fs_address_data(struct job_dump_fs_data* dump_fs, char *name)
+finalize_dump_address_data(struct job_dump_data* dump, char *name)
 {
 	struct component_loc *cl;
 	int num;
 	int rc;
 
-	rc = get_dump_fs_components(dump_fs, &cl, &num);
+	rc = get_dump_components(dump, &cl, &num);
 	if (rc)
 		return rc;
 	sort_cl_array(cl, num);
-	rc = check_component_address_data(cl, num, name);
+	rc = check_component_address_data(cl, num, name, ADDRESS_LIMIT);
 	if (rc)
 		goto out_free;
-	rc = finalize_component_address_data(cl, num);
+	rc = finalize_component_address_data(cl, num, ADDRESS_LIMIT);
 out_free:
 	free(cl);
 	return rc;
@@ -766,10 +765,10 @@ finalize_ipl_tape_address_data(struct jo
 	if (rc)
 		return rc;
 	sort_cl_array(cl, num);
-	rc = check_component_address_data(cl, num, name);
+	rc = check_component_address_data(cl, num, name, ADDRESS_LIMIT);
 	if (rc)
 		goto out_free;
-	rc = finalize_component_address_data(cl, num);
+	rc = finalize_component_address_data(cl, num, ADDRESS_LIMIT);
 	/* The loader needs a ramdisk_addr anyway */
 	if (ipl_tape->ramdisk_addr == 0) {
 		for (i = 0; i < num; i++) {
@@ -860,50 +859,34 @@ check_job_dump_data(struct job_dump_data
 }
 
 
-static int
-check_job_dump_fs_data(struct job_dump_fs_data* dump_fs, char* name)
+int
+check_job_dump_images(struct job_dump_data* dump, char* name)
 {
 	int rc;
-
-	if (dump_fs->partition != NULL) {
-		rc = misc_check_writable_device(dump_fs->partition, 1, 0);
-		if (rc) {
-			if (name == NULL) {
-				error_text("Dump partition '%s'",
-					dump_fs->partition);
-			} else {
-				error_text("Dump partition '%s' in "
-					"section '%s'", dump_fs->partition,
-					name);
-			}
-			return rc;
-		}
-	}
-
 	/* Add data needed to convert fs dump job to IPL job */
-	rc = misc_check_readable_file(FSDUMP_IMAGE);
+	rc = misc_check_readable_file(FSDUMP_PART_IMAGE);
 	if (rc) {
-		error_text("Need external file '%s' for file system dump",
-			   FSDUMP_IMAGE);
+		error_text("Need external file '%s' for partition dump",
+			   FSDUMP_PART_IMAGE);
 		return rc;
 	}
-	dump_fs->image = misc_strdup(FSDUMP_IMAGE);
-	if (dump_fs->image == NULL)
+	dump->image = misc_strdup(FSDUMP_PART_IMAGE);
+	if (dump->image == NULL)
 		return -1;
-	dump_fs->image_addr = DEFAULT_IMAGE_ADDRESS;
+	dump->image_addr = DEFAULT_IMAGE_ADDRESS;
 
 	/* Ramdisk is no longer required with new initramfs dump system */
-	if (misc_check_readable_file(FSDUMP_RAMDISK))
-		dump_fs->ramdisk = NULL;
+	if (misc_check_readable_file(FSDUMP_PART_RAMDISK))
+		dump->ramdisk = NULL;
 	else {
-		dump_fs->ramdisk = misc_strdup(FSDUMP_RAMDISK);
-		if (dump_fs->ramdisk == NULL)
+		dump->ramdisk = misc_strdup(FSDUMP_PART_RAMDISK);
+		if (dump->ramdisk == NULL)
 			return -1;
-		dump_fs->ramdisk_addr = UNSPECIFIED_ADDRESS;
+		dump->ramdisk_addr = UNSPECIFIED_ADDRESS;
 	}
 
-	dump_fs->parm_addr = UNSPECIFIED_ADDRESS;
-	return finalize_dump_fs_address_data(dump_fs, name);
+	dump->parm_addr = UNSPECIFIED_ADDRESS;
+	return finalize_dump_address_data(dump, name);
 }
 
 
@@ -921,13 +904,6 @@ check_job_menu_data(struct job_menu_data
 			if (rc)
 				return rc;
 			break;
-		case job_dump_fs:
-			rc = check_job_dump_fs_data(
-					&menu->entry[i].data.dump_fs,
-					menu->entry[i].name);
-			if (rc)
-				return rc;
-			break;
 		case job_print_usage:
 		case job_print_version:
 		case job_segment:
@@ -1086,9 +1062,6 @@ check_job_data(struct job_data* job)
 	case job_dump_partition:
 		rc = check_job_dump_data(&job->data.dump, job->name);
 		break;
-	case job_dump_fs:
-		rc = check_job_dump_fs_data(&job->data.dump_fs, job->name);
-		break;
 	case job_ipl_tape:
 		rc = check_job_ipl_tape_data(&job->data.ipl_tape, job->name);
 		break;
@@ -1270,10 +1243,10 @@ type_from_target(char *target, disk_type
 		*type = disk_type_fba;
 		return 0;
 	case target_type_ldl:
-		*type = disk_type_eckd_classic;
+		*type = disk_type_eckd_ldl;
 		return 0;
 	case target_type_cdl:
-		*type = disk_type_eckd_compatible;
+		*type = disk_type_eckd_cdl;
 		return 0;
 	default:
 		return -1;
@@ -1351,6 +1324,17 @@ get_job_from_section_data(char* data[],
 					UNSPECIFIED_ADDRESS;
 			}
 		}
+		/* Fill in kdump */
+		if (data[(int) scan_keyword_kdump] != NULL) {
+			if (strcmp(data[(int) scan_keyword_kdump],
+				   "auto") == 0) {
+				job->data.ipl.is_kdump = 1;
+			} else {
+				error_reason("Invalid kdump setting '%s'",
+					     data[(int) scan_keyword_kdump]);
+				return -1;
+			}
+		}
 		break;
 	case section_ipl_tape:
 		/* Tape IPL job */
@@ -1420,46 +1404,14 @@ get_job_from_section_data(char* data[],
 			job->data.dump.mem =
 				(job->data.dump.mem + MEGABYTE_MASK) &
 					~MEGABYTE_MASK;
-			printf("Setting dump size limit to %lldMB\n",
+			printf("Found specification of dump size limit "
+			       "to %lldMB\n",
 			       (unsigned long long) job->data.dump.mem /
 			       		(1024LL * 1024LL));
 		}
 		else
 			job->data.dump.mem = -1LL;
 		break;
-	case section_dumpfs:
-		/* DUMP TO FILESYSTEM job */
-		job->id = job_dump_fs;
-		/* Fill in name of bootmap directory */
-		job->target.bootmap_dir =
-			misc_strdup(data[(int) scan_keyword_target]);
-		if (job->target.bootmap_dir == NULL)
-			return -1;
-		/* Fill in partition name */
-		job->data.dump_fs.partition =
-			misc_strdup(data[(int) scan_keyword_dumptofs]);
-		if (job->data.dump_fs.partition == NULL)
-			return -1;
-		/* Check for mem size specification */
-		if (extract_memsize(job->data.dump_fs.partition,
-				    &job->data.dump_fs.mem) == 0) {
-			/* Ensure megabyte alignment of size */
-			job->data.dump_fs.mem =
-				(job->data.dump_fs.mem + MEGABYTE_MASK) &
-					~MEGABYTE_MASK;
-			printf("Setting dump size limit to %lldMB\n",
-			       (unsigned long long) job->data.dump_fs.mem /
-			       		(1024LL * 1024LL));
-		} else
-			job->data.dump_fs.mem = -1LL;
-		/* Fill in parmline */
-		rc = get_parmline(data[(int) scan_keyword_parmfile],
-				  data[(int) scan_keyword_parameters],
-				  &job->data.dump_fs.parmline,
-				  &job->data.dump_fs.parm_addr, section);
-		if (rc)
-			return rc;
-		break;
 	case section_mvdump:
 		/* DUMP TO MULTI-VOLUME job */
 		job->id = job_mvdump;
@@ -1475,7 +1427,8 @@ get_job_from_section_data(char* data[],
 			job->data.mvdump.mem =
 				(job->data.mvdump.mem + MEGABYTE_MASK) &
 					~MEGABYTE_MASK;
-			printf("Setting dump size limit to %lldMB\n",
+			printf("Found specification of dump size limit "
+			       "to %lldMB\n",
 			       (unsigned long long) job->data.mvdump.mem /
 			       		(1024LL * 1024LL));
 		} else
@@ -1643,13 +1596,6 @@ get_menu_job(struct scan_token* scan, ch
 				memset((void *) &temp_job->data.ipl, 0,
 				       sizeof(struct job_ipl_data));
 				break;
-			case job_dump_fs:
-				job->data.menu.entry[current].id = job_dump_fs;
-				job->data.menu.entry[current].data.dump_fs =
-					temp_job->data.dump_fs;
-				memset((void *) &temp_job->data.dump_fs, 0,
-				       sizeof(struct job_dump_fs_data));
-				break;
 			default:
 				error_reason("Section '%s' cannot be included "
 					     "in menu '%s'", section, menu);
@@ -1760,19 +1706,6 @@ get_section_job(struct scan_token* scan,
 			if (buffer == NULL)
 				return -1;
 			break;
-		case job_dump_fs:
-			if (job->data.dump_fs.parmline == NULL)
-				buffer = misc_strdup(extra_parmline);
-			else {
-				buffer = append_parmline(
-					job->data.dump_fs.parmline,
-					extra_parmline);
-				free(job->data.dump_fs.parmline);
-			}
-			job->data.dump_fs.parmline = buffer;
-			if (buffer == NULL)
-				return -1;
-			break;
 		case job_segment:
 			error_reason("Option 'parameters' cannot be used with "
 				     "section '%s'", section);
--- a/zipl/src/misc.c
+++ b/zipl/src/misc.c
@@ -7,6 +7,7 @@
  * Author(s): Carsten Otte <cotte@de.ibm.com>
  *            Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
  */
+#define _GNU_SOURCE /* for asprintf */
 
 #include "misc.h"
 
@@ -18,6 +19,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 
 #include "error.h"
 
@@ -38,6 +40,21 @@ misc_malloc(size_t size)
 }
 
 
+/* asprintf with misc error checking */
+int misc_asprintf(char** out, const char* fmt, ...)
+{
+	va_list ap;
+	int rc;
+
+	va_start(ap, fmt);
+	rc = vasprintf(out, fmt, ap);
+	va_end(ap);
+	if (rc == -1)
+		error_reason("Could not allocate space for new string");
+	return rc;
+}
+
+
 /* Allocate N * SIZE bytes of memory. Upon success, return pointer to memory.
  * Return NULL otherwise. */
 void *
@@ -71,6 +88,21 @@ misc_strdup(const char* s)
 }
 
 
+/* Open file exclusive */
+int
+misc_open_exclusive(const char* filename)
+{
+	int fd;
+
+	fd = open(filename, O_RDWR | O_EXCL);
+	if (fd == -1 && errno == EBUSY)
+		error_reason("Device is in use (probably mounted)");
+	else if (fd == -1)
+		error_reason(strerror(errno));
+	return fd;
+}
+
+
 /* Read COUNT bytes of data from file identified by file descriptor FD to
  * memory at location BUFFER. Return 0 when all bytes were successfully read,
  * non-zero otherwise. */
@@ -350,16 +382,33 @@ misc_write(int fd, const void* data, siz
 		rc = write(fd, VOID_ADD(data, written), count - written);
 		if (rc == -1) {
 			error_reason(strerror(errno));
+			error_text("Could not write to device");
 			return -1;
 		}
 		if (rc == 0) {
 			error_reason("Write failed");
+			error_text("Could not write to device");
 			return -1;
 		}
 	}
 	return 0;
 }
 
+int misc_seek(int fd, off_t off)
+{
+	if (lseek(fd, off, SEEK_SET) == off)
+		return 0;
+	error_reason(strerror(errno));
+	error_text("Could not seek on device");
+	return -1;
+}
+
+int misc_pwrite(int fd, void *buf, size_t size, off_t off)
+{
+	if (misc_seek(fd, off))
+		return -1;
+	return misc_write(fd, buf, size);
+}
 
 int
 misc_check_writable_directory(const char* directory)
@@ -436,3 +485,123 @@ misc_check_writable_device(const char* d
 }
 
 
+
+/* ASCII to EBCDIC conversion table. */
+unsigned char ascebc[256] =
+{
+	0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+	0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+	0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+	0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+	0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+	0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+	0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+	0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+	0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+	0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+	0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+	0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+	0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/* EBCDIC to ASCII conversion table. */
+unsigned char ebcasc[256] =
+{
+/* 0x00  NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+	0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08  -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+	0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10  DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC */
+	0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18  CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB */
+	0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20  -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC */
+	0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28  -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL */
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+	0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+	0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40   SP   RSP           ?              ----       */
+	0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48                      .     <     (     +     | */
+	0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50    &                                      ---- */
+	0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58          ?     !     $     *     )     ;       */
+	0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60    -     /  ----     ?  ----  ----  ----       */
+	0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68             ----     ,     %     _     >     ? */
+	0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70  ---        ----  ----  ----  ----  ----  ---- */
+	0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78    *     `     :     #     @     '     =     " */
+	0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80    *     a     b     c     d     e     f     g */
+	0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88    h     i              ----  ----  ----       */
+	0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90    ?     j     k     l     m     n     o     p */
+	0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98    q     r                    ----        ---- */
+	0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0          ~     s     t     u     v     w     x */
+	0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8    y     z              ----  ----  ----  ---- */
+	0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0    ^                    ----     ?  ----       */
+	0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8       ----     [     ]  ----  ----  ----  ---- */
+	0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0    {     A     B     C     D     E     F     G */
+	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8    H     I  ----           ?              ---- */
+	0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0    }     J     K     L     M     N     O     P */
+	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8    Q     R  ----           ?                   */
+	0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0    \           S     T     U     V     W     X */
+	0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8    Y     Z        ----     ?  ----  ----  ---- */
+	0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0    0     1     2     3     4     5     6     7 */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8    8     9  ----  ----     ?  ----  ----  ---- */
+	0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+void misc_ebcdic_to_ascii(unsigned char *from, unsigned char *to)
+{
+	for (; from != to; from++)
+		*from = ebcasc[*from];
+}
+
+void misc_ascii_to_ebcdic(unsigned char *from, unsigned char *to)
+{
+	for (; from != to; from++)
+		*from = ascebc[*from];
+}
+
+
--- a/zipl/src/proc.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * s390-tools/zipl/src/proc.c
- *   Scanner for the /proc/ files
- *
- * Copyright IBM Corp. 2001, 2007.
- *
- * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
- */
-
-#include "proc.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-
-#include "misc.h"
-
-static const char proc_part_filename[] = "/proc/partitions";
-static const char proc_dev_filename[] = "/proc/devices";
-
-struct file_buffer {
-	char* buffer;
-	off_t pos;
-	size_t length;
-};
-
-
-/* Get the contents of a file and fill in the respective fields of
- * FILE. Return 0 on success, non-zero otherwise. */
-static int
-get_file_buffer(struct file_buffer* file, const char *filename)
-{
-	int rc;
-
-	rc = misc_read_special_file(filename, &file->buffer, &file->length, 0);
-	file->pos = 0;
-	return rc;
-}
-
-
-/* Free resources allocated for file buffer identified by
- * FILE. */
-static void
-free_file_buffer(struct file_buffer* file)
-{
-	if (file->buffer != NULL) {
-		free(file->buffer);
-		file->buffer = NULL;
-		file->pos = 0;
-		file->length = 0;
-	}
-}
-
-
-/* Return character at current FILE buffer position or EOF if at end of
- * file. */
-static int
-current_char(struct file_buffer* file)
-{
-	if (file->buffer != NULL)
-		if (file->pos < (off_t) file->length)
-			return file->buffer[file->pos];
-	return EOF;
-}
-
-
-/* Advance the current file pointer of file buffer FILE until the current
- * character is no longer a whitespace or until the end of line or file is
- * reached. Return 0 if at least one whitespace character was encountered,
- * non-zero otherwise. */
-static int
-skip_whitespaces(struct file_buffer* file)
-{
-	int rc;
-
-	rc = -1;
-	while ((current_char(file) != '\n') && isspace(current_char(file))) {
-		rc = 0;
-		file->pos++;
-	}
-	return rc;
-}
-
-
-/* Scan a positive integer number at the current position of file buffer FILE
- * and advance the position respectively. Upon success, return zero and set
- * NUMBER to contain the scanned number. Return non-zero otherwise. */
-static int
-scan_number(struct file_buffer* file, size_t* number)
-{
-	int rc;
-	size_t old_number;
-
-	*number=0;
-	rc = -1;
-	while (isdigit(current_char(file))) {
-		rc = 0;
-		old_number = *number;
-		*number = *number * 10 + current_char(file) - '0';
-		/* Check for overflow */
-		if (old_number > *number) {
-			rc = -1;
-			break;
-		}
-		file->pos++;
-	}
-	return rc;
-}
-
-
-/* Scan a device node name at the current position of file buffer FILE and
- * advance the position respectively. Upon success, return zero and set
- * NAME to contain a copy of the scanned name. Return non-zero otherwise. */
-static int
-scan_name(struct file_buffer* file, char** name)
-{
-	off_t start_pos;
-
-	start_pos = file->pos;
-	while (!isspace(current_char(file)) &&
-	       (current_char(file) != EOF))
-			file->pos++;
-	if (file->pos > start_pos) {
-		*name = (char *) malloc(file->pos - start_pos + 1);
-		if (*name == NULL)
-			return -1;
-		memcpy((void *) *name, (void *) &file->buffer[start_pos],
-		       file->pos - start_pos);
-		(*name)[file->pos - start_pos] = 0;
-		return 0;
-	} else
-		return -1;
-}
-
-/* Scan for the specified STRING at the current position of file buffer FILE
- * and advance the position respectively. Upon success, return zero. Return
- * non-zero otherwise. */
-static int
-scan_string(struct file_buffer* file, const char *string)
-{
-	int i;
-
-	i=0;
-	for (i=0; string[i] && (current_char(file) == string[i]);
-	     i++, file->pos++);
-	if (string[i] == '\0')
-		return 0;
-	return -1;
-}
-
-
-/* Advance the current file position to beginning of next line in file buffer
- * FILE or to end of file. */
-static void
-skip_line(struct file_buffer* file)
-{
-	while ((current_char(file) != '\n') && (current_char(file) != EOF))
-		file->pos++;
-	if (current_char(file) == '\n')
-		file->pos++;
-}
-
-
-/* Return non-zero if the current file position of file buffer FILE is at the
- * end of file. Return zero otherwise. */
-static int
-eof(struct file_buffer* file)
-{
-	return file->pos >= (off_t) file->length;
-}
-
-
-/* Scan a line of the specified /proc/partitions FILE buffer and advance the
- * current file position pointer respectively. If the current line matches
- * the correct pattern, fill in the corresponding data into ENTRY and return 0.
- * Return non-zero otherwise. */
-static int
-scan_part_entry(struct file_buffer* file, struct proc_part_entry* entry)
-{
-	int rc;
-	size_t dev_major;
-	size_t dev_minor;
-	size_t blockcount;
-	char* name;
-
-	/* Scan for: (\s*)(\d+)(\s+)(\d+)(\s+)(\d+)(\s+)(\S+)(\.*)$ */
-	skip_whitespaces(file);
-	rc = scan_number(file, &dev_major);
-	if (rc)
-		return rc;
-	rc = skip_whitespaces(file);
-	if (rc)
-		return rc;
-	rc = scan_number(file, &dev_minor);
-	if (rc)
-		return rc;
-	rc = skip_whitespaces(file);
-	if (rc)
-		return rc;
-	rc = scan_number(file, &blockcount);
-	if (rc)
-		return rc;
-	rc = skip_whitespaces(file);
-	if (rc)
-		return rc;
-	rc = scan_name(file, &name);
-	if (rc)
-		return rc;
-	skip_line(file);
-	entry->device = makedev(dev_major, dev_minor);
-	entry->blockcount = blockcount;
-	entry->name = name;
-	return 0;
-}
-
-
-/* Release resources associated with ENTRY. */
-void
-proc_part_free_entry(struct proc_part_entry* entry)
-{
-	if (entry->name != NULL) {
-		free(entry->name);
-		entry->name = NULL;
-	}
-}
-
-/* Scan a line of the specified /proc/devices FILE buffer and advance the
- * current file position pointer respectively. If the current line matches
- * the correct pattern, fill in the corresponding data into ENTRY and return 0.
- * Return non-zero otherwise. */
-static int
-scan_dev_entry(struct file_buffer* file, struct proc_dev_entry* entry,
-	       int blockdev)
-{
-	int rc;
-	size_t dev_major;
-	char* name;
-
-	/* Scan for: (\s*)(\d+)(\s+)(\S+)(\.*)$ */
-	skip_whitespaces(file);
-	rc = scan_number(file, &dev_major);
-	if (rc)
-		return rc;
-	rc = skip_whitespaces(file);
-	if (rc)
-		return rc;
-	rc = scan_name(file, &name);
-	if (rc)
-		return rc;
-	skip_line(file);
-	entry->device = makedev(dev_major, 0);
-	entry->name = name;
-	entry->blockdev = blockdev;
-	return 0;
-}
-
-
-/* Release resources associated with ENTRY. */
-void
-proc_dev_free_entry(struct proc_dev_entry* entry)
-{
-	if (entry->name != NULL) {
-		free(entry->name);
-		entry->name = NULL;
-	}
-}
-
-
-/* Scan /proc/partitions for an entry matching DEVICE. When there is a match,
- * store entry data in ENTRY and return 0. Return non-zero otherwise. */
-int
-proc_part_get_entry(dev_t device, struct proc_part_entry* entry)
-{
-	struct file_buffer file;
-	int rc;
-
-	rc = get_file_buffer(&file, proc_part_filename);
-	if (rc)
-		return rc;
-	rc = -1;
-	while (!eof(&file)) {
-		if (scan_part_entry(&file, entry) == 0) {
-			if (entry->device == device) {
-				rc = 0;
-				break;
-			}
-			proc_part_free_entry(entry);
-		} else
-			skip_line(&file);
-	}
-	free_file_buffer(&file);
-	return rc;
-}
-
-/* Scan /proc/devices for a blockdevice (BLOCKDEV is 1) or a character
- * device (BLOCKDEV is 0) with a major number matching the major number of DEV.
- * When there is a match, store entry data in ENTRY and return 0. Return
- * non-zero otherwise. */
-int
-proc_dev_get_entry(dev_t device, int blockdev, struct proc_dev_entry* entry)
-{
-	struct file_buffer file;
-	int rc;
-	int scan_blockdev = 0;
-
-	rc = get_file_buffer(&file, proc_dev_filename);
-	if (rc)
-		return rc;
-	rc = -1;
-	while (!eof(&file)) {
-		if (scan_string(&file, "Block") == 0) {
-			skip_line(&file);
-			scan_blockdev = 1;
-			continue;
-		} else if (scan_dev_entry(&file, entry, scan_blockdev) == 0) {
-			if ((major(entry->device) == major(device)) &&
-			    blockdev == scan_blockdev) {
-				rc = 0;
-				break;
-			}
-			proc_dev_free_entry(entry);
-		} else
-			skip_line(&file);
-	}
-	free_file_buffer(&file);
-	return rc;
-}
--- a/zipl/src/scan.c
+++ b/zipl/src/scan.c
@@ -33,45 +33,45 @@ enum scan_key_state scan_key_table[SCAN_
  *	 ult  to   tofs e    mete file isk  ent  et   pt   out  ultm      dump
  *			     rs                                 enu
  *
- *       targ targ targ targ targ defa
- *       etba etty etge etbl etof ulta
+ *       targ targ targ targ targ defa kdum
+ *       etba etty etge etbl etof ulta p
  *       se   pe   omet ocks fset uto
  *                 ry   ize
  */
 /* default auto */
 	{opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
-	 opt, opt, opt, opt, opt, opt},
+	 opt, opt, opt, opt, opt, opt, inv},
 /* default menu */
 	{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* default section */
 	{req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* ipl		*/
 	{inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv,
-	 opt, opt, opt, opt, opt, inv},
+	 opt, opt, opt, opt, opt, inv, opt},
 /* segment load */
 	{inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* part dump	*/
 	{inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* fs dump	*/
 	{inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* ipl tape	*/
 	{inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv,
-	 inv, inv, inv, inv, inv, inv},
+	 inv, inv, inv, inv, inv, inv, inv},
 /* multi volume dump	*/
 	{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req,
-	 inv, inv, inv, inv, inv, inv}
+	 inv, inv, inv, inv, inv, inv, inv}
 };
 
 /* Determines which keyword may be present in a menu section */
 enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = {
 /* menu section */
 	 opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
-	 opt, opt, opt, opt, opt, inv
+	 opt, opt, opt, opt, opt, inv, inv
 };
 
 /* Mapping of keyword IDs to strings */
@@ -97,7 +97,8 @@ static const struct {
 	{ "target", scan_keyword_target},
 	{ "prompt", scan_keyword_prompt},
 	{ "timeout", scan_keyword_timeout},
-	{ "tape", scan_keyword_tape}
+	{ "tape", scan_keyword_tape},
+	{ "kdump", scan_keyword_kdump},
 };
 
 /* List of keywords that are used without an assignment */
@@ -701,8 +702,6 @@ scan_get_target_type(char *type)
 	return target_type_invalid;
 }
 
-#define MAX(a,b)	((a)>(b)?(a):(b))
-
 /* Check section data for correctness. KEYWORD[keyword_id] defines whether
  * a keyword is present, LINE[keyword_id] specifies in which line a keyword
  * was found or NULL when specified on command line, NAME specifies the
@@ -730,8 +729,9 @@ scan_check_section_data(char* keyword[],
 			*type = section_dump;
 			main_keyword = scan_keyword_name(scan_keyword_dumpto);
 		} else if (keyword[(int) scan_keyword_dumptofs]) {
-			*type = section_dumpfs;
-			main_keyword = scan_keyword_name(scan_keyword_dumptofs);
+			error_reason("Option dumptofs is deprecated, "
+				     "use dumpto instead");
+			return -1;
 		} else if (keyword[(int) scan_keyword_mvdump]) {
 			*type = section_mvdump;
 			main_keyword = scan_keyword_name(scan_keyword_mvdump);
--- a/zipl/src/zipl.c
+++ b/zipl/src/zipl.c
@@ -1,8 +1,7 @@
 /*
- * s390-tools/zipl/src/zipl.c
- *   zSeries Initial Program Loader tool.
+ * zipl - zSeries Initial Program Loader tool
  *
- * Copyright IBM Corp. 2001, 2009.
+ * Copyright IBM Corp. 2001, 2014
  *
  * Author(s): Carsten Otte <cotte@de.ibm.com>
  *            Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
@@ -41,7 +40,7 @@ int dry_run = 1;
 static const char tool_name[] = "zipl: zSeries Initial Program Loader";
 
 /* Copyright notice */
-static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2009";
+static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2014";
 
 /* Usage information */
 static const char* usage_text[] = {
@@ -72,8 +71,6 @@ static const char* usage_text[] = {
 "                                disk partition listed in file DEVLIST",
 "-f, --force                     Disable sanity check while producing a",
 "                                multi-volume dump",
-"-D, --dumptofs DUMPDEV[,SIZE]   Install a system dump record for dumping to",
-"                                filesystem on partition identified by DUMPDEV",
 "-m, --menu MENU                 Install multi-boot configuration MENU",
 "-n, --noninteractive            Answer all confirmation questions with 'yes'",
 "-V, --verbose                   Provide more verbose output",
@@ -120,9 +117,8 @@ int
 main(int argc, char* argv[])
 {
 	struct disk_info* info;
-	disk_blockptr_t program_table;
-	disk_blockptr_t* stage2_list;
-	blocknum_t stage2_count;
+	disk_blockptr_t program_table, scsi_dump_sb_blockptr, *stage1b_list;
+	blocknum_t stage1b_count;
 	struct job_data* job;
 	char* device;
 	int rc;
@@ -167,21 +163,40 @@ main(int argc, char* argv[])
 	umask(077);
 	/* Do it */
 	switch (job->id) {
+	case job_dump_partition:
+		if (disk_is_tape(job->data.dump.device) ||
+		    !disk_is_scsi(job->data.dump.device, &job->target)) {
+			rc = install_dump(job->data.dump.device, &job->target,
+					  job->data.dump.mem);
+			break;
+		}
+		/* Dump to a raw SCSI partition */
+		if (job->data.dump.mem != -1uLL) {
+			error_reason("Dump size can not be limited for "
+				     "partition dump on a SCSI disk");
+			rc = -1;
+			break;
+		}
+		rc = check_job_dump_images(&job->data.dump, job->name);
+		if (rc != 0)
+			break;
+		/* Fall through. */
 	case job_ipl:
 	case job_segment:
-	case job_dump_fs:
 	case job_menu:
 		/* Create bootmap */
-		stage2_list = NULL;
-		rc = bootmap_create(job, &program_table, &stage2_list,
-				    &stage2_count, &device, &info);
+		stage1b_list = NULL;
+		rc = bootmap_create(job, &program_table, &scsi_dump_sb_blockptr,
+				    &stage1b_list, &stage1b_count, &device,
+				    &info);
 		if (rc)
 			break;
 		/* Install boot loader */
 		rc = install_bootloader(device, &program_table,
-					stage2_list, stage2_count, info, job);
-		if (stage2_list != NULL)
-			free(stage2_list);
+					&scsi_dump_sb_blockptr, stage1b_list,
+					stage1b_count, info, job);
+		if (stage1b_list != NULL)
+			free(stage1b_list);
 		misc_free_temp_dev(device);
 		disk_free_info(info);
 		break;
@@ -194,11 +209,6 @@ main(int argc, char* argv[])
 					job->data.ipl_tape.parm_addr,
 					job->data.ipl_tape.ramdisk_addr);
 		break;
-	case job_dump_partition:
-		/* Retrieve target device information */
-		rc = install_dump(job->data.dump.device, &job->target,
-				  job->data.dump.mem);
-		break;
 	case job_mvdump:
 		rc = install_mvdump(job->data.mvdump.device,
 				    &job->target,
--- a/zipl/src/zipl_helper.device-mapper
+++ b/zipl/src/zipl_helper.device-mapper
@@ -9,17 +9,18 @@
 # Depending on the name by which the script is called, it serves one of two
 # purposes:
 #
-# 1. Usage: zipl_helper.device-mapper <target directory>
+# 1. Usage: zipl_helper.device-mapper <target directory> or
+#                                     <major:minor of target device>
 #
-# This tool attempts to obtain zipl parameters for a target directory located
-# on a device-mapper device. It assumes that the device-mapper table for this
-# device conforms to the following rules:
+# This tool attempts to obtain zipl parameters for a target directory or
+# partition located on a device-mapper device. It assumes that the
+# device-mapper table for this device conforms to the following rules:
 # - directory is located on a device consisting of a single device-mapper
 #   target
 # - only linear, mirror and multipath targets are supported
 # - supported physical device types are DASD and SCSI devices
 # - all of the device which contains the directory must be located on a single
-#   physical device (which may be mirrorred or accessed through a multipath
+#   physical device (which may be mirrored or accessed through a multipath
 #   target)
 # - any mirror in the device-mapper setup must include block 0 of the
 #   physical device
@@ -94,6 +95,7 @@ sub get_type_name($);
 sub check_for_mirror($@);
 sub get_target_base($$$$@);
 sub get_device_name($$);
+sub check_tools();
 
 my $phy_geometry;	# Disk geometry of physical device
 my $phy_blocksize;	# Blocksize of physical device
@@ -132,12 +134,24 @@ if ($toolname eq "chreipl_helper.device-
 
 $directory = $ARGV[0];
 if (!defined($directory)) {
-	die("Usage: $toolname <target directory>\n");
+	die("Usage: $toolname <target directory> or <major:minor of target devies>\n");
+}
+
+# check if needed tools are available
+check_tools();
+
+if (($ARGV[0] =~ /^\s*(\d+)\s*:\s*(\d+)\s*$/)) {
+    	# Determine physical (non-dm) device on which partition is located
+	($phy_major, $phy_minor, $phy_offset, @target_list) =
+		get_physical_device($1,$2);
+}
+else
+{
+	# Determine physical (non-dm) device on which directory is located
+	($phy_major, $phy_minor, $phy_offset, @target_list) =
+		get_physical_device_dir($directory);
 }
 
-# Determine physical (non-dm) device on which directory is located
-($phy_major, $phy_minor, $phy_offset, @target_list) =
-	get_physical_device_dir($directory);
 # Determine type and characteristics of physical device
 ($phy_type, $phy_blocksize, $phy_geometry, $phy_bootsectors, $phy_partstart) =
 	get_device_characteristics($phy_major, $phy_minor);
@@ -753,3 +767,17 @@ sub get_device_name($$)
 out:
 	return $name;
 }
+
+sub check_tools()
+{
+system("$dmsetup --version &> /dev/null") >> 8 != 127
+    or die("Error: dmsetup not found\n");
+system("$mknod --version &> /dev/null") >> 8 != 127
+    or die("Error: mknod not found\n");
+system("$dasdview --version &> /dev/null") >> 8 != 127
+    or die("Error: dasdview not found\n");
+system("$blockdev --version &> /dev/null") >> 8 != 127
+    or die("Error: blockdev not found\n");
+
+return 0;
+}
