Subject: [PATCH] [BZ 127839] zipl/zfcpdump: Re-add file system based dump
From: Stefan Haberland <stefan.haberland@de.ibm.com>

Description:  zipl/zfcpdump: Re-add file system based dump
Symptom:      The zipl -D option is no longer working.
Problem:      With patch "s390-tools-sles11sp4-zipl_rebase.patch" by
              accident the file system based zfcpdump feature
              (-D option) has been removed and the partition dump
              feature (-d option) has been added.
Solution:     Re-add the -D option and remove the -d option for
              zfcpdump.
Reproduction: Prepare SCSI device for zfcpdump with -D option:
              # mount /dev/sda1 /dump
              # zipl -D /dev/sda1 -t /mnt
Upstream-ID:  -
Problem-ID:   127839

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
---
 zipl/include/boot.h                |    3 
 zipl/include/bootmap.h             |    1 
 zipl/include/disk.h                |    6 -
 zipl/include/install.h             |    4 
 zipl/include/job.h                 |   28 +++--
 zipl/include/misc.h                |    3 
 zipl/include/zipl.h                |    8 -
 zipl/man/zipl.8                    |   36 ++++---
 zipl/man/zipl.conf.5               |   30 +++++
 zipl/src/Makefile                  |    5 
 zipl/src/boot.c                    |    6 -
 zipl/src/bootmap.c                 |  187 +++++++++++--------------------------
 zipl/src/disk.c                    |   89 +++--------------
 zipl/src/install.c                 |   53 +++-------
 zipl/src/job.c                     |  160 ++++++++++++++++++++++++-------
 zipl/src/misc.c                    |   32 ------
 zipl/src/scan.c                    |    5 
 zipl/src/zipl.c                    |   36 ++-----
 zipl/src/zipl_helper.device-mapper |   26 +----
 19 files changed, 315 insertions(+), 403 deletions(-)

--- a/zipl/include/boot.h
+++ b/zipl/include/boot.h
@@ -28,7 +28,6 @@
 
 #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
@@ -86,7 +85,6 @@ 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));
@@ -304,7 +302,6 @@ int boot_init_fba_stage1b(struct boot_fb
 			  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, uint16_t flags);
--- a/zipl/include/bootmap.h
+++ b/zipl/include/bootmap.h
@@ -18,7 +18,6 @@
 
 
 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
@@ -93,8 +93,6 @@ 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);
@@ -108,8 +106,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, int fd_is_basedisk,
-				   const void* buffer, size_t bytecount,
+blocknum_t disk_write_block_buffer(int fd, const void* buffer,
+				   size_t bytecount,
 				   disk_blockptr_t** blocklist,
 				   struct disk_info* info);
 void disk_print_devt(dev_t d);
--- a/zipl/include/install.h
+++ b/zipl/include/install.h
@@ -18,9 +18,8 @@
 
 
 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);
+		       struct disk_info* info);
 int install_tapeloader(const char* device, const char* image,
 		       const char* parmline, const char* ramdisk,
 		       address_t image_addr, address_t parm_addr,
@@ -37,6 +36,5 @@ int install_eckd_stage1b(int fd, disk_bl
 			 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,9 +22,10 @@ enum job_id {
 	job_ipl = 3,
 	job_segment = 4,
 	job_dump_partition = 5,
-	job_menu = 6,
-	job_ipl_tape = 7,
-	job_mvdump = 8,
+	job_dump_fs = 6,
+	job_menu = 7,
+	job_ipl_tape = 8,
+	job_mvdump = 9,
 };
 
 struct job_target_data {
@@ -55,12 +56,6 @@ 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;
 };
 
@@ -72,6 +67,17 @@ 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;
@@ -85,7 +91,7 @@ struct job_ipl_tape_data {
 
 union job_menu_entry_data {
 	struct job_ipl_data ipl;
-	struct job_dump_data dump;
+	struct job_dump_fs_data dump_fs;
 };
 
 struct job_menu_entry {
@@ -112,6 +118,7 @@ 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;
@@ -126,6 +133,5 @@ 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,10 +25,8 @@ 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);
@@ -53,5 +51,4 @@ void misc_ascii_to_ebcdic(unsigned char
 
 #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/zipl.h
+++ b/zipl/include/zipl.h
@@ -46,12 +46,8 @@
 #define MENU_DEFAULT_PROMPT		0
 #define MENU_DEFAULT_TIMEOUT		0
 
-#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 FSDUMP_IMAGE	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_IMAGE)
+#define FSDUMP_RAMDISK	STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_RD)
 
 #define MAX_DUMP_VOLUMES		32
 
--- a/zipl/man/zipl.8
+++ b/zipl/man/zipl.8
@@ -234,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 SCSI disk partitions, DASD ECKD or FBA disk partitions,
+Supported devices are DASD ECKD or FBA disk partitions
 and IBM 3480/3490/3590/3592 tape devices.
 
-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.
+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
@@ -255,8 +255,21 @@ It is not possible to specify both this
 or configuration section on the command line at the same time.
 
 .TP
-.BR "\-D" " or " "\-\-dumptofs"
-This option has been removed, use --dumpto instead.
+.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.
 
 .TP
 .BR "\-M <DUMPLIST[,SIZE]>" " or " "--mvdump=<DUMPLIST[,SIZE]>"
@@ -299,7 +312,8 @@ This option cannot be used together with
 .BR \-\-parmfile ,
 .BR \-\-parameters ,
 .BR \-\-segment ,
-.BR \-\-dumpto " or"
+.BR \-\-dumpto ,
+.BR \-\-dumptofs " or"
 .BR \-\-mvdump .
 
 .TP
--- 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 dumpto )
+.BR dumptofs )
 may be included in menus. 
 
 Note that position number 0 is reserved and will automatically be assigned to
@@ -348,9 +348,29 @@ will be incomplete.
 .PP
 
 .B dumptofs
+=
+.IR dump\-partition [, size ]
+(configuration only)
 .IP
+.B Configuration section:
 .br
-This option has been removed, use dumpto instead.
+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.
 .PP
 
 .B mvdump
@@ -402,7 +422,8 @@ To change the kernel parameters, use
 .BR 'parameters' .
 
 This option cannot be used together with either
-.BR 'dump' , " or"
+.BR 'dump' ,
+.BR 'dumptofs' " or"
 .BR 'segment' .
 .PP
 
@@ -513,7 +534,8 @@ Specify a IBM 3480/3490/3590 tape device
 
 This option cannot be used together with
 .BR 'target' ", "
-.BR 'dump' ", " " or "
+.BR 'dump' ", "
+.BR 'dumptofs' " or "
 .BR 'segment' .
 .PP
 
--- a/zipl/src/Makefile
+++ b/zipl/src/Makefile
@@ -3,10 +3,7 @@ include ../../common.mak
 
 CPPFLAGS += -I../include -I../boot -I../../include \
 	    -DZFCPDUMP_DIR=$(ZFCPDUMP_DIR) \
-	    -DZFCPDUMP_FS_IMAGE=$(ZFCPDUMP_FS_IMAGE) \
-	    -DZFCPDUMP_FS_RD=$(ZFCPDUMP_FS_RD) \
-	    -DZFCPDUMP_PART_IMAGE=$(ZFCPDUMP_PART_IMAGE) \
-	    -DZFCPDUMP_PART_RD=$(ZFCPDUMP_PART_RD) \
+	    -DZFCPDUMP_IMAGE=$(ZFCPDUMP_IMAGE) -DZFCPDUMP_RD=$(ZFCPDUMP_RD) \
 	    -D_FILE_OFFSET_BITS=64
 LDFLAGS += -Wl,-z,noexecstack
 
--- a/zipl/src/boot.c
+++ b/zipl/src/boot.c
@@ -70,12 +70,6 @@ boot_check_data(void)
 	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
--- a/zipl/src/bootmap.c
+++ b/zipl/src/bootmap.c
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include <stdint.h>
 
-#include "util_part.h"
 #include "boot.h"
 #include "disk.h"
 #include "error.h"
@@ -297,7 +296,7 @@ add_component_file(int fd, const char* f
 			return -1;
 		}
 		/* Write buffer */
-		count = disk_write_block_buffer(fd, 0, buffer + offset,
+		count = disk_write_block_buffer(fd, buffer + offset,
 					size - offset, &list, info);
 		free(buffer);
 		if (count == 0) {
@@ -366,7 +365,7 @@ add_component_buffer(int fd, void* buffe
 	int rc;
 
 	/* Write buffer */
-	count = disk_write_block_buffer(fd, 0, buffer, size, &list, info);
+	count = disk_write_block_buffer(fd, buffer, size, &list, info);
 	if (count == 0) {
 		error_text("Could not write to bootmap file");
 		return -1;
@@ -595,17 +594,18 @@ if (rc) {
 #define DUMP_PARAM_MAX_LEN	896
 
 static char *
-create_dump_parmline(const char* parmline, const char* root_dev,
-		     uint64_t mem, int max_cpus)
+create_dump_fs_parmline(const char* parmline, const char* root_dev,
+			int part_num, 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_mem=%lld "
-		 "possible_cpus=%d cgroup_disable=memory ",
-		 parmline ? parmline : "", parmline ? " " : "", root_dev,
+	snprintf(result, DUMP_PARAM_MAX_LEN, "%s%sroot=%s dump_part=%d "
+		 "dump_mem=%lld possible_cpus=%d cgroup_disable=memory ",
+		 parmline ? parmline : "",
+		 parmline ? " " : "", root_dev, part_num,
 		 (unsigned long long) mem, max_cpus);
 	result[DUMP_PARAM_MAX_LEN - 1] = 0;
 	return result;
@@ -613,9 +613,9 @@ create_dump_parmline(const char* parmlin
 
 
 static int
-get_dump_parmline(char *partition, char *parameters,
-		  struct disk_info *target_info,
-		  struct job_target_data *target, char **result)
+get_dump_fs_parmline(char* partition, char* parameters, uint64_t mem,
+		     struct disk_info* target_info,
+		     struct job_target_data* target, char** result)
 {
 	char* buffer;
 	struct disk_info* info;
@@ -640,8 +640,8 @@ get_dump_parmline(char *partition, char
 		disk_free_info(info);
 		return -1;
 	}
-	buffer = create_dump_parmline(parameters, "/dev/ram0",
-				      info->partnum, 1);
+	buffer = create_dump_fs_parmline(parameters, "/dev/ram0", info->partnum,
+					 mem, 1);
 	disk_free_info(info);
 	if (buffer == NULL)
 		return -1;
@@ -651,7 +651,7 @@ get_dump_parmline(char *partition, char
 
 
 static int
-add_dump_program(int fd, struct job_dump_data* dump,
+add_dump_fs_program(int fd, struct job_dump_fs_data* dump_fs,
 		    disk_blockptr_t* program, int verbose,
 		    component_header_type type,
 		    struct disk_info* info, struct job_target_data* target)
@@ -661,17 +661,17 @@ add_dump_program(int fd, struct job_dump
 
 	/* Convert fs dump job to IPL job */
 	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;
+	ipl.image = dump_fs->image;
+	ipl.image_addr = dump_fs->image_addr;
+	ipl.ramdisk = dump_fs->ramdisk;
+	ipl.ramdisk_addr = dump_fs->ramdisk_addr;
 
 	/* Get file system dump parmline */
-	rc = get_dump_parmline(dump->device, dump->parmline,
-			       info, target, &ipl.parmline);
+	rc = get_dump_fs_parmline(dump_fs->partition, dump_fs->parmline,
+				  dump_fs->mem, info, target, &ipl.parmline);
 	if (rc)
 		return rc;
-	ipl.parm_addr = dump->parm_addr;
+	ipl.parm_addr = dump_fs->parm_addr;
 	return add_ipl_program(fd, &ipl, program, verbose, 1,
 			       type, info, target);
 }
@@ -723,14 +723,13 @@ build_program_table(int fd, struct job_d
 					 job->add_files, component_header_ipl,
 					 info, &job->target);
 		break;
-	case job_dump_partition:
-		/* Only useful for a partition dump that uses a dump kernel*/
+	case job_dump_fs:
 		if (job->command_line)
 			printf("Adding fs-dump section\n");
 		else
 			printf("Adding fs-dump section '%s' (default)\n",
 			       job->name);
-		rc = add_dump_program(fd, &job->data.dump, &table[0],
+		rc = add_dump_fs_program(fd, &job->data.dump_fs, &table[0],
 					 verbose || job->command_line,
 					 component_header_dump,
 					 info, &job->target);
@@ -763,6 +762,20 @@ build_program_table(int fd, struct job_d
 					job->add_files,	component_header,
 					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,
+					info, &job->target);
+				break;
 			case job_print_usage:
 			case job_print_version:
 			case job_segment:
@@ -784,6 +797,7 @@ 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;
@@ -819,53 +833,34 @@ write_empty_block(int fd, disk_blockptr_
 
 int
 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 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;
 	void *stage2_data;
-	int fd, rc, part_ext;
+	int fd;
 
 	/* Get full path of bootmap file */
-	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;
-		}
+	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. */
-	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;
-	}
+	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)",
@@ -883,62 +878,8 @@ bootmap_create(struct job_data *job, dis
 		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 */
 	if (misc_write(fd, header_text, sizeof(header_text))) {
 		error_text("Could not write to file '%s'", filename);
@@ -952,28 +893,12 @@ bootmap_create(struct job_data *job, dis
 	/* Build program table */
 	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:
 		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_count = disk_write_block_buffer(fd, stage2_data,
 						stage2_size, &stage2_list,
 						info);
 		free(stage2_data);
@@ -990,7 +915,7 @@ bootmap_create(struct job_data *job, dis
 	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_count = disk_write_block_buffer(fd, stage2_data,
 						stage2_size, &stage2_list,
 						info);
 		free(stage2_data);
@@ -1013,7 +938,7 @@ bootmap_create(struct job_data *job, dis
 		if (remove(filename) == -1)
 			fprintf(stderr, "Warning: could not remove temporary "
 				"file %s!\n", filename);
-	} else if (job->id != job_dump_partition) {
+	} else {
 		/* Rename to final bootmap name */
 		mapname = misc_make_path(job->target.bootmap_dir,
 				BOOTMAP_FILENAME);
--- a/zipl/src/disk.c
+++ b/zipl/src/disk.c
@@ -27,7 +27,6 @@
 #include "error.h"
 #include "misc.h"
 #include "util_proc.h"
-#include "install.h"
 
 /* from linux/fs.h */
 #define FIBMAP			_IO(0x00,1)
@@ -241,15 +240,8 @@ disk_get_info(const char* device, struct
 		data->source = source_script;
 		/* Run targetbase script */
 		strcpy(ppn_cmd, script_file);
-		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);
-		}
+		strcat(ppn_cmd, " ");
+		strcat(ppn_cmd, target->bootmap_dir);
 		printf("Run %s\n", ppn_cmd);
 		fh = popen(ppn_cmd, "r");
 		if (fh == NULL) {
@@ -325,7 +317,6 @@ 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)) {
@@ -349,6 +340,13 @@ disk_get_info(const char* device, struct
 		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;
+	}
+
 	/* Determine disk type */
 	if (!data->drv_name) {
 		/* Driver name cannot be read */
@@ -410,12 +408,6 @@ 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)) {
@@ -449,34 +441,6 @@ 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,
@@ -544,8 +508,8 @@ 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, int fd_is_basedisk, blocknum_t logical,
-		  blocknum_t* physical, struct disk_info* info)
+disk_get_blocknum(int fd, blocknum_t logical, blocknum_t* physical,
+		  struct disk_info* info)
 {
 	struct statfs buf;
 	blocknum_t phy_per_fs;
@@ -554,10 +518,7 @@ disk_get_blocknum(int fd, int fd_is_base
 
 	/* 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;
+		*physical = logical;
 		return 0;
 	}
 
@@ -664,10 +625,9 @@ 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. */
-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)
+int
+disk_write_block_aligned(int fd, const void* data, size_t bytecount,
+			 disk_blockptr_t* block, struct disk_info* info)
 {
 	blocknum_t current_block;
 	blocknum_t blocknum;
@@ -697,21 +657,13 @@ disk_write_block_aligned_base(int fd, in
 		return -1;
 	if (block != NULL) {
 		/* Store block pointer */
-		if (disk_get_blocknum(fd, is_base_disk, current_block,
-				      &blocknum, info))
+		if (disk_get_blocknum(fd, 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
@@ -720,8 +672,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, int fd_is_basedisk, const void* buffer,
-			size_t bytecount, disk_blockptr_t** blocklist,
+disk_write_block_buffer(int fd, const void* buffer, size_t bytecount,
+			disk_blockptr_t** blocklist,
 			struct disk_info* info)
 {
 	disk_blockptr_t* list;
@@ -744,8 +696,7 @@ disk_write_block_buffer(int fd, int fd_i
 		chunk_size = bytecount - written;
 		if (chunk_size > (size_t) info->phy_block_size)
 			chunk_size = info->phy_block_size;
-		rc = disk_write_block_aligned_base(fd, fd_is_basedisk,
-						   VOID_ADD(buffer, written),
+		rc = disk_write_block_aligned(fd, VOID_ADD(buffer, written),
 				chunk_size,
 				&list[i], info);
 		if (rc) {
@@ -1039,7 +990,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, 0, i, &blocknum, info)) {
+		if (disk_get_blocknum(fd, i, &blocknum, info)) {
 			free(list);
 			close(fd);
 			return 0;
--- a/zipl/src/install.c
+++ b/zipl/src/install.c
@@ -70,25 +70,19 @@ 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, disk_blockptr_t* scsi_dump_sb_blockptr)
+		struct disk_info* info)
 {
 	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)) {
@@ -117,13 +111,6 @@ 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;
 }
 
@@ -133,8 +120,7 @@ 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,
-	     disk_blockptr_t* scsi_dump_sb_blockptr)
+install_scsi(int fd, disk_blockptr_t* program_table, struct disk_info* info)
 {
 	unsigned char* bootblock;
 	int rc;
@@ -154,8 +140,7 @@ install_scsi(int fd, disk_blockptr_t* pr
 		return rc;
 	}
 	/* Put zIPL data into MBR */
-	rc = update_scsi_mbr(bootblock, program_table, info,
-			     scsi_dump_sb_blockptr);
+	rc = update_scsi_mbr(bootblock, program_table, info);
 	if (rc) {
 		free(bootblock);
 		return -1;
@@ -214,7 +199,7 @@ install_eckd_stage1b(int fd, disk_blockp
 	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_count = disk_write_block_buffer(fd, stage1b, stage1b_size,
 						 stage1b_list, info);
 	if (*stage1b_count == 0)
 		goto out_free_stage1b;
@@ -282,9 +267,8 @@ install_eckd_cdl(int fd, disk_blockptr_t
 
 int
 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)
+		   struct disk_info *info)
 {
 	int fd, rc;
 
@@ -321,10 +305,7 @@ install_bootloader(const char *device, d
 	rc = -1;
 	switch (info->type) {
 	case disk_type_scsi:
-		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);
+		rc = install_scsi(fd, program_table, info);
 		break;
 	case disk_type_fba:
 		rc = install_fba(fd, program_table, stage1b_list,
@@ -366,7 +347,7 @@ install_bootloader(const char *device, d
 
 /* Rewind the tape device identified by FD. Return 0 on success, non-zero
  * otherwise. */
-int
+static int
 rewind_tape(int fd)
 {
 	struct mtop op;
@@ -380,6 +361,7 @@ rewind_tape(int fd)
 		return 0;
 }
 
+
 static int
 ask_for_confirmation(const char* fmt, ...)
 {
@@ -713,7 +695,7 @@ static int install_svdump_eckd_ldl(int f
 	/* 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_count = disk_write_block_buffer(fd, stage2, stage2_size,
 					       &stage2_list, info);
 	if (stage2_count == 0)
 		goto out_free_stage2_list;
@@ -768,7 +750,7 @@ static int install_dump_eckd_cdl(int fd,
 	/* 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_count = disk_write_block_buffer(fd, stage2, stage2_size,
 					       &stage2_list, info);
 	if (stage2_count == 0)
 		goto out;
@@ -826,7 +808,8 @@ install_mvdump_eckd_cdl(int fd, struct d
 	if (boot_get_eckd_mvdump_stage2(&stage2, &stage2_size, mem,
 					force, parm))
 		return -1;
-	rc = install_dump_eckd_cdl(fd, info, stage2, stage2_size, 1, force);
+	rc = install_dump_eckd_cdl(fd, info, stage2, stage2_size, 1,
+				   force);
 	free(stage2);
 	return rc;
 }
@@ -848,7 +831,7 @@ install_fba_stage1b(int fd, disk_blockpt
 	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_count = disk_write_block_buffer(fd, stage1b, stage1b_size,
 						 stage1b_list, info);
 	if (*stage1b_count == 0)
 		goto out_free_stage1b;
@@ -883,7 +866,7 @@ install_svdump_fba(int fd, struct disk_i
 	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_count = disk_write_block_buffer(fd, stage2, stage2_size,
 					       &stage2_list, info);
 	if (stage2_count == 0)
 		goto out_free_stage2;
@@ -943,8 +926,9 @@ install_dump(const char* device, struct
 	int fd;
 	int rc;
 
-	fd = misc_open_exclusive(device);
+	fd = open(device, O_RDWR);
 	if (fd == -1) {
+		error_reason(strerror(errno));
 		error_text("Could not open dump device '%s'", device);
 		return -1;
 	}
@@ -1071,8 +1055,9 @@ 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 = misc_open_exclusive(device[i]);
+		fd = open(device[i], O_RDWR);
 		if (fd == -1) {
+			error_reason(strerror(errno));
 			error_text("Could not open dump target '%s'",
 				   device[i]);
 			rc = -1;
@@ -1161,7 +1146,7 @@ install_mvdump(char* const device[], str
 			rc = -1;
 			goto out;
 		}
-		fd = misc_open_exclusive(tempdev);
+		fd = open(tempdev, O_RDWR);
 		if (fd == -1) {
 			error_text("Could not open temporary device node '%s'",
 				   tempdev);
--- a/zipl/src/job.c
+++ b/zipl/src/job.c
@@ -110,9 +110,9 @@ get_command_line(int argc, char* argv[],
 					  optarg);
 			break;
 		case 'D':
-			error_reason("dumptofs has been deprecated, use "
-				     "--dump instead");
-			rc = -1;
+			is_keyword = 1;
+			rc = store_option(&cmdline, scan_keyword_dumptofs,
+					  optarg);
 			break;
 		case 'M':
 			is_keyword = 1;
@@ -343,10 +343,10 @@ free_segment_data(struct job_segment_dat
 
 
 static void
-free_dump_data(struct job_dump_data* data)
+free_dump_fs_data(struct job_dump_fs_data* data)
 {
-	if (data->device != NULL)
-		free(data->device);
+	if (data->partition != NULL)
+		free(data->partition);
 	if (data->image != NULL)
 		free(data->image);
 	if (data->parmline != NULL)
@@ -369,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_partition:
-				free_dump_data(
-					&data->entry[i].data.dump);
+			case job_dump_fs:
+				free_dump_fs_data(
+					&data->entry[i].data.dump_fs);
 				break;
 			default:
 				break;
@@ -383,6 +383,14 @@ 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;
@@ -419,6 +427,9 @@ 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;
@@ -529,7 +540,7 @@ error:
 
 
 static int
-get_dump_components(struct job_dump_data *dump,
+get_dump_fs_components(struct job_dump_fs_data *dump_fs,
 		       struct component_loc **clp, int *nump)
 {
 	struct component_loc *cl;
@@ -542,19 +553,19 @@ get_dump_components(struct job_dump_data
 		return -1;
 	/* Fill in component data */
 	num = 0;
-	rc = set_cl_element(&cl[num++], "kernel image", dump->image,
-			    &dump->image_addr, 0, 0x10000,
+	rc = set_cl_element(&cl[num++], "kernel image", dump_fs->image,
+			    &dump_fs->image_addr, 0, 0x10000,
 			    MAXIMUM_PHYSICAL_BLOCKSIZE);
 	if (rc)
 		goto error;
-	rc = set_cl_element(&cl[num++], "parmline", NULL, &dump->parm_addr,
+	rc = set_cl_element(&cl[num++], "parmline", NULL, &dump_fs->parm_addr,
 			    MAXIMUM_PARMLINE_SIZE, 0,
 			    MAXIMUM_PHYSICAL_BLOCKSIZE);
 	if (rc)
 		goto error;
-	if (dump->ramdisk) {
+	if (dump_fs->ramdisk) {
 		rc = set_cl_element(&cl[num++], "initial ramdisk",
-				    dump->ramdisk, &dump->ramdisk_addr,
+				    dump_fs->ramdisk, &dump_fs->ramdisk_addr,
 				    0, 0, 0x10000);
 		if (rc)
 			goto error;
@@ -733,13 +744,13 @@ out_free:
 
 
 static int
-finalize_dump_address_data(struct job_dump_data* dump, char *name)
+finalize_dump_fs_address_data(struct job_dump_fs_data* dump_fs, char *name)
 {
 	struct component_loc *cl;
 	int num;
 	int rc;
 
-	rc = get_dump_components(dump, &cl, &num);
+	rc = get_dump_fs_components(dump_fs, &cl, &num);
 	if (rc)
 		return rc;
 	sort_cl_array(cl, num);
@@ -859,34 +870,50 @@ check_job_dump_data(struct job_dump_data
 }
 
 
-int
-check_job_dump_images(struct job_dump_data* dump, char* name)
+static int
+check_job_dump_fs_data(struct job_dump_fs_data* dump_fs, 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_PART_IMAGE);
+	rc = misc_check_readable_file(FSDUMP_IMAGE);
 	if (rc) {
-		error_text("Need external file '%s' for partition dump",
-			   FSDUMP_PART_IMAGE);
+		error_text("Need external file '%s' for file system dump",
+			   FSDUMP_IMAGE);
 		return rc;
 	}
-	dump->image = misc_strdup(FSDUMP_PART_IMAGE);
-	if (dump->image == NULL)
+	dump_fs->image = misc_strdup(FSDUMP_IMAGE);
+	if (dump_fs->image == NULL)
 		return -1;
-	dump->image_addr = DEFAULT_IMAGE_ADDRESS;
+	dump_fs->image_addr = DEFAULT_IMAGE_ADDRESS;
 
 	/* Ramdisk is no longer required with new initramfs dump system */
-	if (misc_check_readable_file(FSDUMP_PART_RAMDISK))
-		dump->ramdisk = NULL;
+	if (misc_check_readable_file(FSDUMP_RAMDISK))
+		dump_fs->ramdisk = NULL;
 	else {
-		dump->ramdisk = misc_strdup(FSDUMP_PART_RAMDISK);
-		if (dump->ramdisk == NULL)
+		dump_fs->ramdisk = misc_strdup(FSDUMP_RAMDISK);
+		if (dump_fs->ramdisk == NULL)
 			return -1;
-		dump->ramdisk_addr = UNSPECIFIED_ADDRESS;
+		dump_fs->ramdisk_addr = UNSPECIFIED_ADDRESS;
 	}
 
-	dump->parm_addr = UNSPECIFIED_ADDRESS;
-	return finalize_dump_address_data(dump, name);
+	dump_fs->parm_addr = UNSPECIFIED_ADDRESS;
+	return finalize_dump_fs_address_data(dump_fs, name);
 }
 
 
@@ -904,6 +931,13 @@ 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:
@@ -1062,6 +1096,9 @@ 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;
@@ -1404,14 +1441,46 @@ get_job_from_section_data(char* data[],
 			job->data.dump.mem =
 				(job->data.dump.mem + MEGABYTE_MASK) &
 					~MEGABYTE_MASK;
-			printf("Found specification of dump size limit "
-			       "to %lldMB\n",
+			printf("Setting 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;
@@ -1427,8 +1496,7 @@ get_job_from_section_data(char* data[],
 			job->data.mvdump.mem =
 				(job->data.mvdump.mem + MEGABYTE_MASK) &
 					~MEGABYTE_MASK;
-			printf("Found specification of dump size limit "
-			       "to %lldMB\n",
+			printf("Setting dump size limit to %lldMB\n",
 			       (unsigned long long) job->data.mvdump.mem /
 			       		(1024LL * 1024LL));
 		} else
@@ -1596,6 +1664,13 @@ 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);
@@ -1706,6 +1781,19 @@ 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,7 +7,6 @@
  * Author(s): Carsten Otte <cotte@de.ibm.com>
  *            Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
  */
-#define _GNU_SOURCE /* for asprintf */
 
 #include "misc.h"
 
@@ -19,7 +18,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include <stdarg.h>
 
 #include "error.h"
 
@@ -40,21 +38,6 @@ 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 *
@@ -88,21 +71,6 @@ 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. */
--- a/zipl/src/scan.c
+++ b/zipl/src/scan.c
@@ -729,9 +729,8 @@ scan_check_section_data(char* keyword[],
 			*type = section_dump;
 			main_keyword = scan_keyword_name(scan_keyword_dumpto);
 		} else if (keyword[(int) scan_keyword_dumptofs]) {
-			error_reason("Option dumptofs is deprecated, "
-				     "use dumpto instead");
-			return -1;
+			*type = section_dumpfs;
+			main_keyword = scan_keyword_name(scan_keyword_dumptofs);
 		} 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
@@ -71,6 +71,8 @@ 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",
@@ -117,7 +119,7 @@ int
 main(int argc, char* argv[])
 {
 	struct disk_info* info;
-	disk_blockptr_t program_table, scsi_dump_sb_blockptr, *stage1b_list;
+	disk_blockptr_t program_table, *stage1b_list;
 	blocknum_t stage1b_count;
 	struct job_data* job;
 	char* device;
@@ -163,38 +165,19 @@ 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 */
 		stage1b_list = NULL;
-		rc = bootmap_create(job, &program_table, &scsi_dump_sb_blockptr,
-				    &stage1b_list, &stage1b_count, &device,
-				    &info);
+		rc = bootmap_create(job, &program_table, &stage1b_list,
+				    &stage1b_count, &device, &info);
 		if (rc)
 			break;
 		/* Install boot loader */
 		rc = install_bootloader(device, &program_table,
-					&scsi_dump_sb_blockptr, stage1b_list,
-					stage1b_count, info, job);
+					stage1b_list, stage1b_count, info);
 		if (stage1b_list != NULL)
 			free(stage1b_list);
 		misc_free_temp_dev(device);
@@ -209,6 +192,11 @@ 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,12 +9,11 @@
 # Depending on the name by which the script is called, it serves one of two
 # purposes:
 #
-# 1. Usage: zipl_helper.device-mapper <target directory> or
-#                                     <major:minor of target device>
+# 1. Usage: zipl_helper.device-mapper <target directory>
 #
-# 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:
+# 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:
 # - directory is located on a device consisting of a single device-mapper
 #   target
 # - only linear, mirror and multipath targets are supported
@@ -134,24 +133,15 @@ if ($toolname eq "chreipl_helper.device-
 
 $directory = $ARGV[0];
 if (!defined($directory)) {
-	die("Usage: $toolname <target directory> or <major:minor of target devies>\n");
+	die("Usage: $toolname <target directory>\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);
