Files
s390-tools/zipl/boot/tape2dump.c
Jan Höppner 5af1e8cc69 zipl/tape2dump: Remove check for data compaction support
Data compaction is only supported by 3490 tape devices. For Virtual Tape
Server (VTS) this is the only supported device. Reading device
characteristics and checking the type is unnecessary.

Remove the corresponding code and simply enable data compaction.

Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-03-11 11:24:02 +01:00

180 lines
3.9 KiB
C

/*
* zipl - zSeries Initial Program Loader tool
*
* Dump tool for channel-attached tape devices
*
* Copyright IBM Corp. 2013, 2023
*
* 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 "libc.h"
#include "lib/zt_common.h"
#include "boot/error.h"
#include "boot/loaders_layout.h"
#include "boot/s390.h"
#include "dump/s390_dump.h"
#include "cio.h"
#include "stage2dump.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 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;
static const struct tape_head __used __section(.stage2.head) tape_head = {
.psw = PSW_LOAD | STAGE2_ENTRY, /* 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, 1);
}
/*
* Enable data compaction
*/
static void setup_idrc_compression(void)
{
ccw_init(&ccw_program.compress, MODE_SET_DB, CCW_FLAG_CC, 0x1, &mode_set_byte);
orb.cpa = __pa32(&ccw_program.compress);
}
/*
* 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, 1);
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");
}
/*
* Dump all memory to tape
*/
void dt_dump_mem(void)
{
unsigned long addr, page;
page = get_zeroed_page();
setup_idrc_compression();
ccw_write_tapemark();
total_dump_size = 0;
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);
total_dump_size += BLK_SIZE;
progress_print(addr + BLK_SIZE);
}
df_s390_em_page_init(page);
ccw_write_block(page, sizeof(struct df_s390_em), 0);
free_page(page);
ccw_write_tapemark();
}