Files
s390-tools/zipl/boot/tape2dump.c
Jan Höppner 145c21a9ca zipl/tape2dump: Remove load display command
Load Display (LDD) X'9F' is still accepted by the Virtual Tape Server
(VTS) but does not perform any action. Remove code that still uses this
command in tape2dump.c.

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

196 lines
4.3 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 READ_DEV_CHAR 0x64 /* Read device characteristics */
#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);
}
/*
* 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;
}
}
/*
* 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();
}