mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
234 lines
5.0 KiB
C
234 lines
5.0 KiB
C
/*
|
|
* zgetdump - Tool for copying and converting System z dumps
|
|
*
|
|
* Single-volume SCSI dump tool
|
|
*
|
|
* Copyright IBM Corp. 2013, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <stdio.h>
|
|
|
|
#include "lib/util_part.h"
|
|
#include "zgetdump.h"
|
|
|
|
/*
|
|
* Single volume SCSI dump superblock
|
|
*/
|
|
struct scsi_dump_sb {
|
|
uint64_t magic;
|
|
uint64_t version;
|
|
uint64_t part_start;
|
|
uint64_t part_size;
|
|
uint64_t dump_off;
|
|
uint64_t dump_size;
|
|
uint64_t csum_off;
|
|
uint64_t csum_size;
|
|
uint64_t csum;
|
|
} __attribute((packed));
|
|
|
|
/*
|
|
* File local static data
|
|
*/
|
|
static struct {
|
|
struct scsi_dump_sb sb;
|
|
int blk_size;
|
|
} l;
|
|
|
|
/*
|
|
* zipl on-disc / bootloader structs from zipl includes
|
|
*/
|
|
struct scsi_blockptr {
|
|
uint64_t blockno;
|
|
uint16_t size;
|
|
uint16_t blockct;
|
|
uint8_t reserved[4];
|
|
} __attribute__((__packed__));
|
|
|
|
enum component_entry_type {
|
|
component_execute = 0x01,
|
|
component_load = 0x02
|
|
};
|
|
|
|
struct component_entry {
|
|
struct scsi_blockptr data;
|
|
uint8_t pad[7];
|
|
uint8_t component_type;
|
|
union {
|
|
uint64_t load_address;
|
|
uint64_t load_psw;
|
|
} address;
|
|
} __attribute__((__packed__));
|
|
|
|
enum component_header_type {
|
|
component_header_ipl = 0x00,
|
|
component_header_dump = 0x01
|
|
};
|
|
|
|
struct component_header {
|
|
uint8_t magic[4];
|
|
uint8_t type;
|
|
uint8_t reserved[27];
|
|
} __attribute__((__packed__));
|
|
|
|
struct boot_info {
|
|
char magic[4];
|
|
uint8_t version;
|
|
uint8_t bp_type;
|
|
uint8_t dev_type;
|
|
uint8_t flags;
|
|
uint64_t sb_off;
|
|
} __attribute__ ((packed));
|
|
|
|
struct scsi_mbr {
|
|
char magic[4];
|
|
uint32_t version;
|
|
uint8_t reserved1[8];
|
|
struct scsi_blockptr blockptr;
|
|
uint8_t reserved2[0x50];
|
|
struct boot_info boot_info;
|
|
} __attribute__((__packed__));
|
|
|
|
#define BOOT_INFO_VERSION 1
|
|
#define BOOT_INFO_MAGIC "zIPL"
|
|
#define BOOT_INFO_DEV_TYPE_SCSI 0x02
|
|
#define BOOT_INFO_BP_TYPE_DUMP 0x01
|
|
|
|
/*
|
|
* Check the zIPL magic number
|
|
*/
|
|
static int check_zipl_magic(void *buf)
|
|
{
|
|
if (memcmp(buf, "zIPL", 4))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Final step looks into program to find dump flag
|
|
*/
|
|
static int check_dump_program(struct scsi_blockptr *blockptr)
|
|
{
|
|
uint64_t off = blockptr->blockno * l.blk_size;
|
|
struct component_header header;
|
|
|
|
zg_seek(g.fh, off, ZG_CHECK_ERR);
|
|
zg_read(g.fh, &header, sizeof(header), ZG_CHECK_ERR);
|
|
if (check_zipl_magic(&header.magic))
|
|
return -1;
|
|
return (header.type == component_header_dump) ? 0 : -1;
|
|
}
|
|
|
|
/*
|
|
* Parse program table, see zipl docu to understand table structures
|
|
*/
|
|
static int check_program_table(uint64_t blockno)
|
|
{
|
|
struct scsi_blockptr entries[l.blk_size / sizeof(struct scsi_blockptr)];
|
|
unsigned int i;
|
|
|
|
/* Entry 0, holds the magic, entry 1 the default */
|
|
zg_seek(g.fh, blockno * l.blk_size, ZG_CHECK);
|
|
zg_read(g.fh, &entries, l.blk_size, ZG_CHECK);
|
|
if (check_zipl_magic(&entries[0]))
|
|
return -1;
|
|
for (i = 1; i < l.blk_size / sizeof(struct scsi_blockptr); i++) {
|
|
if (entries[i].blockno == 0)
|
|
break;
|
|
if (check_dump_program(&entries[i]) == 0)
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Check magic number and checksum of superblock at given offset
|
|
*/
|
|
static int check_sb(void)
|
|
{
|
|
char buf[l.sb.csum_size];
|
|
|
|
if (l.sb.magic != 0x5a46435044554d50ULL) /* ZFCPDUMP */
|
|
return -1;
|
|
/*
|
|
* Verify checksum
|
|
*/
|
|
zg_seek(g.fh, l.sb.part_start + l.sb.csum_off, ZG_CHECK);
|
|
zg_read(g.fh, &buf, sizeof(buf), ZG_CHECK);
|
|
if (zg_csum_partial(&buf, l.sb.csum_size, 0x12345678) != l.sb.csum)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Check the SCSI dump boot info
|
|
*/
|
|
static int check_boot_info(struct boot_info *info)
|
|
{
|
|
if (memcmp(&info->magic, BOOT_INFO_MAGIC, sizeof(info->magic)))
|
|
return -1;
|
|
if (info->dev_type != BOOT_INFO_DEV_TYPE_SCSI)
|
|
return -1;
|
|
if (info->bp_type != BOOT_INFO_BP_TYPE_DUMP)
|
|
return -1;
|
|
zg_seek(g.fh, info->sb_off, ZG_CHECK);
|
|
zg_read(g.fh, &l.sb, sizeof(l.sb), ZG_CHECK);
|
|
return check_sb();
|
|
}
|
|
|
|
/*
|
|
* Detect if the bootmap contains ZFCPDUMP.
|
|
* Walks through bootmap structs to find the dump flag
|
|
*/
|
|
static int dt_scsi_init(void)
|
|
{
|
|
struct scsi_mbr mbr;
|
|
|
|
zg_read(g.fh, &mbr, sizeof(mbr), ZG_CHECK);
|
|
if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK_NONE))
|
|
return -1;
|
|
if (check_zipl_magic(mbr.magic))
|
|
return -1;
|
|
if (check_program_table(mbr.blockptr.blockno))
|
|
return -1;
|
|
if (check_boot_info(&mbr.boot_info))
|
|
return -1;
|
|
dt_arch_set(DFI_ARCH_64);
|
|
dt_version_set(l.sb.version);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Print partition information for dump device
|
|
*/
|
|
static void dt_scsi_info(void)
|
|
{
|
|
int part_num, part_ext;
|
|
size_t start, cnt;
|
|
|
|
start = l.sb.part_start / l.blk_size;
|
|
cnt = l.sb.part_size / l.blk_size;
|
|
part_num = util_part_search_fh(g.fh->fh, start, cnt, l.blk_size,
|
|
&part_ext);
|
|
|
|
STDERR("Partition info:\n");
|
|
if (part_num > 0)
|
|
STDERR(" Partition number..: %d\n", part_num);
|
|
else
|
|
STDERR(" Partition number..: unknown\n");
|
|
STDERR(" Maximum dump size.: %llu MB\n",
|
|
(unsigned long long) TO_MIB(l.sb.dump_size));
|
|
}
|
|
|
|
/*
|
|
* Single-volume SCSI DT operations
|
|
*/
|
|
struct dt dt_scsi = {
|
|
.desc = "Single-volume SCSI dump tool",
|
|
.init = dt_scsi_init,
|
|
.info = dt_scsi_info,
|
|
};
|