* Don't stop at the first unbootable device, continue scanning
* Fix corner cases in booting from ECKD * s390x-ccw bios cleanup part 2 -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAl98tMoRHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbWioA//bp1fp++Apn8w+Bbw3YY30wIG6/OLgjlw k//MtdcNasDswrWEES77lyR9ud22B/MSKqdfFpnTI1vQ8+e6BuH82iu3d7yNS0cd 8tgb8jr1dO4gMjExJZ6ada5gY/ZkNWyM7gJooqVqTd+lEnIeo8yMAIPHE/3OyfeA xIIA0+owppxEQc3UuE3hS7Cu0ph03HDugWDEqMA6LcD2E8Yl2bP3Sh5uztVdjqmI CH1nuB62WR0kNheU+9woKPDBZP/NPwFvLRnJmNZptKensPotiwX1QjK9aqE15iU5 Mr28qVxubRIMxfmlzJ+3NImTNjdJnOgKFxDwP/hCjJ5lBSHgM/69+nZcDt49Cg4k 52LH9y+9RsDvOz7jNle0xn2V+T48ykkzLKvAHT/2wzSqE8eccpKilqP8ZoFPq11c WcyP68C6ag28AK72JRdNN43aM0clTeUVdUMgy4nqu6HzBDDHKhwTyj6W1zbs+aJC bBtITOxZyjrqPi156pJQCKWYrQQyq2SZV7BBAKSq56nkR+wkj4lxSbor2Am8h3Xk 2QQBXtMgsmwcQTOfGlKer9KXWh7bEINh3iGtJ6QDL0KJtUFn2Uyi2U7uiSq4SlGS QH0AIxTKkYZ8VlRNgCCTf4XXJM0LGjX3XKIDePAnY5aA5F5bYdd7vFfCBChUWMML ARN7JMSXL70= =T7wc -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2020-10-06' into staging * Don't stop at the first unbootable device, continue scanning * Fix corner cases in booting from ECKD * s390x-ccw bios cleanup part 2 # gpg: Signature made Tue 06 Oct 2020 19:17:46 BST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * remotes/huth-gitlab/tags/pull-request-2020-10-06: tests/qtest/cdrom: Add more s390x-related boot tests pc-bios/s390: Update the s390-ccw bios binaries pc-bios: s390x: Go into disabled wait when encountering a PGM exception pc-bios: s390x: Use reset PSW if avaliable pc-bios: s390x: Save PSW rework pc-bios: s390x: Fix bootmap.c zipl component entry data handling pc-bios/s390-ccw: break loop if a null block number is reached pc-bios/s390-ccw: fix off-by-one error pc-bios/s390-ccw/main: Remove superfluous call to enable_subchannel() pc-bios/s390-ccw: Allow booting in case the first virtio-blk disk is bad pc-bios/s390-ccw: Scan through all devices if no boot device specified pc-bios/s390-ccw: Do not bail out early if not finding a SCSI disk pc-bios/s390-ccw: Move the inner logic of find_subch() to a separate function pc-bios/s390-ccw: Introduce ENODEV define and remove guards of others pc-bios/s390-ccw: Move ipl-related code from main() into a separate function pc-bios/s390-ccw/Makefile: Compile with -std=gnu99, -fwrapv and -fno-common Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6eeea6725a
Binary file not shown.
|
@ -30,10 +30,11 @@ OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
|
|||
virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o
|
||||
|
||||
QEMU_CFLAGS := -Wall $(filter -W%, $(QEMU_CFLAGS))
|
||||
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
|
||||
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
|
||||
QEMU_CFLAGS += -fno-asynchronous-unwind-tables
|
||||
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
|
||||
QEMU_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
|
||||
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
|
||||
QEMU_CFLAGS += -msoft-float -march=z900
|
||||
QEMU_CFLAGS += -std=gnu99
|
||||
LDFLAGS += -Wl,-pie -nostdlib
|
||||
|
||||
build-all: s390-ccw.img s390-netboot.img
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "libc.h"
|
||||
#include "s390-ccw.h"
|
||||
#include "s390-arch.h"
|
||||
#include "bootmap.h"
|
||||
#include "virtio.h"
|
||||
#include "bswap.h"
|
||||
|
@ -163,7 +164,7 @@ static bool find_zipl_boot_menu_banner(int *offset)
|
|||
int i;
|
||||
|
||||
/* Menu banner starts with "zIPL" */
|
||||
for (i = 0; i < virtio_get_block_size() - 4; i++) {
|
||||
for (i = 0; i <= virtio_get_block_size() - 4; i++) {
|
||||
if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
|
||||
*offset = i;
|
||||
return true;
|
||||
|
@ -192,7 +193,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
|
|||
for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
|
||||
cur_block_nr = eckd_block_num(&s1b->seek[i].chs);
|
||||
|
||||
if (!cur_block_nr) {
|
||||
if (!cur_block_nr || is_null_block_number(cur_block_nr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -272,7 +273,8 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
|
|||
|
||||
IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC,
|
||||
"Unknown script entry type");
|
||||
jump_to_IPL_code(bms->entry[i].address.load_address); /* no return */
|
||||
write_reset_psw(bms->entry[i].address.load_address); /* no return */
|
||||
jump_to_IPL_code(0); /* no return */
|
||||
}
|
||||
|
||||
static void ipl_eckd_cdl(void)
|
||||
|
@ -289,11 +291,18 @@ static void ipl_eckd_cdl(void)
|
|||
read_block(1, ipl2, "Cannot read IPL2 record at block 1");
|
||||
|
||||
mbr = &ipl2->mbr;
|
||||
IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 record.");
|
||||
IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
|
||||
"Bad block size in zIPL section of IPL2 record.");
|
||||
IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
|
||||
"Non-ECKD device type in zIPL section of IPL2 record.");
|
||||
if (!magic_match(mbr, ZIPL_MAGIC)) {
|
||||
sclp_print("No zIPL section in IPL2 record.\n");
|
||||
return;
|
||||
}
|
||||
if (!block_size_ok(mbr->blockptr.xeckd.bptr.size)) {
|
||||
sclp_print("Bad block size in zIPL section of IPL2 record.\n");
|
||||
return;
|
||||
}
|
||||
if (!mbr->dev_type == DEV_TYPE_ECKD) {
|
||||
sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* save pointer to Boot Map Table */
|
||||
bmt_block_nr = eckd_block_num(&mbr->blockptr.xeckd.bptr.chs);
|
||||
|
@ -303,10 +312,14 @@ static void ipl_eckd_cdl(void)
|
|||
|
||||
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
|
||||
read_block(2, vlbl, "Cannot read Volume Label at block 2");
|
||||
IPL_assert(magic_match(vlbl->key, VOL1_MAGIC),
|
||||
"Invalid magic of volume label block");
|
||||
IPL_assert(magic_match(vlbl->f.key, VOL1_MAGIC),
|
||||
"Invalid magic of volser block");
|
||||
if (!magic_match(vlbl->key, VOL1_MAGIC)) {
|
||||
sclp_print("Invalid magic of volume label block.\n");
|
||||
return;
|
||||
}
|
||||
if (!magic_match(vlbl->f.key, VOL1_MAGIC)) {
|
||||
sclp_print("Invalid magic of volser block.\n");
|
||||
return;
|
||||
}
|
||||
print_volser(vlbl->f.volser);
|
||||
|
||||
run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
|
||||
|
@ -398,7 +411,8 @@ static void ipl_eckd(void)
|
|||
read_block(0, mbr, "Cannot read block 0 on DASD");
|
||||
|
||||
if (magic_match(mbr->magic, IPL1_MAGIC)) {
|
||||
ipl_eckd_cdl(); /* no return */
|
||||
ipl_eckd_cdl(); /* only returns in case of error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* LDL/CMS? */
|
||||
|
@ -436,7 +450,7 @@ static void zipl_load_segment(ComponentEntry *entry)
|
|||
char *blk_no = &err_msg[30]; /* where to print blockno in (those ZZs) */
|
||||
|
||||
blockno = entry->data.blockno;
|
||||
address = entry->load_address;
|
||||
address = entry->compdat.load_addr;
|
||||
|
||||
debug_print_int("loading segment at block", blockno);
|
||||
debug_print_int("addr", address);
|
||||
|
@ -514,7 +528,8 @@ static void zipl_run(ScsiBlockPtr *pte)
|
|||
IPL_assert(entry->component_type == ZIPL_COMP_ENTRY_EXEC, "No EXEC entry");
|
||||
|
||||
/* should not return */
|
||||
jump_to_IPL_code(entry->load_address);
|
||||
write_reset_psw(entry->compdat.load_psw);
|
||||
jump_to_IPL_code(0);
|
||||
}
|
||||
|
||||
static void ipl_scsi(void)
|
||||
|
@ -825,5 +840,5 @@ void zipl_load(void)
|
|||
panic("\n! Unknown IPL device type !\n");
|
||||
}
|
||||
|
||||
panic("\n* this can never happen *\n");
|
||||
sclp_print("zIPL load failed.\n");
|
||||
}
|
||||
|
|
|
@ -64,11 +64,16 @@ typedef struct BootMapTable {
|
|||
BootMapPointer entry[];
|
||||
} __attribute__ ((packed)) BootMapTable;
|
||||
|
||||
typedef union ComponentEntryData {
|
||||
uint64_t load_psw;
|
||||
uint64_t load_addr;
|
||||
} ComponentEntryData;
|
||||
|
||||
typedef struct ComponentEntry {
|
||||
ScsiBlockPtr data;
|
||||
uint8_t pad[7];
|
||||
uint8_t component_type;
|
||||
uint64_t load_address;
|
||||
ComponentEntryData compdat;
|
||||
} __attribute((packed)) ComponentEntry;
|
||||
|
||||
typedef struct ComponentHeader {
|
||||
|
|
|
@ -12,21 +12,24 @@
|
|||
|
||||
#define KERN_IMAGE_START 0x010000UL
|
||||
#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_64)
|
||||
#define RESET_PSW ((uint64_t)&jump_to_IPL_addr | RESET_PSW_MASK)
|
||||
|
||||
typedef struct ResetInfo {
|
||||
uint64_t ipl_psw;
|
||||
uint32_t ipl_continue;
|
||||
} ResetInfo;
|
||||
static uint64_t *reset_psw = 0, save_psw, ipl_continue;
|
||||
|
||||
static ResetInfo save;
|
||||
|
||||
static void jump_to_IPL_2(void)
|
||||
void write_reset_psw(uint64_t psw)
|
||||
{
|
||||
ResetInfo *current = 0;
|
||||
*reset_psw = psw;
|
||||
}
|
||||
|
||||
void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
|
||||
*current = save;
|
||||
ipl(); /* should not return */
|
||||
static void jump_to_IPL_addr(void)
|
||||
{
|
||||
__attribute__((noreturn)) void (*ipl)(void) = (void *)ipl_continue;
|
||||
|
||||
/* Restore reset PSW */
|
||||
write_reset_psw(save_psw);
|
||||
|
||||
ipl();
|
||||
/* should not return */
|
||||
}
|
||||
|
||||
void jump_to_IPL_code(uint64_t address)
|
||||
|
@ -46,15 +49,12 @@ void jump_to_IPL_code(uint64_t address)
|
|||
* content of non-BIOS memory after we loaded the guest, so we
|
||||
* save the original content and restore it in jump_to_IPL_2.
|
||||
*/
|
||||
ResetInfo *current = 0;
|
||||
|
||||
save = *current;
|
||||
|
||||
current->ipl_psw = (uint64_t) &jump_to_IPL_2;
|
||||
current->ipl_psw |= RESET_PSW_MASK;
|
||||
current->ipl_continue = address & PSW_MASK_SHORT_ADDR;
|
||||
|
||||
debug_print_int("set IPL addr to", current->ipl_continue);
|
||||
if (address) {
|
||||
save_psw = *reset_psw;
|
||||
write_reset_psw(RESET_PSW);
|
||||
ipl_continue = address;
|
||||
}
|
||||
debug_print_int("set IPL addr to", address ?: *reset_psw & PSW_MASK_SHORT_ADDR);
|
||||
|
||||
/* Ensure the guest output starts fresh */
|
||||
sclp_print("\n");
|
||||
|
@ -84,7 +84,12 @@ void jump_to_low_kernel(void)
|
|||
|
||||
/* Trying to get PSW at zero address */
|
||||
if (*((uint64_t *)0) & RESET_PSW_MASK) {
|
||||
jump_to_IPL_code((*((uint64_t *)0)) & PSW_MASK_SHORT_ADDR);
|
||||
/*
|
||||
* Surely nobody will try running directly from lowcore, so
|
||||
* let's use 0 as an indication that we want to load the reset
|
||||
* psw at 0x0 and not jump to the entry.
|
||||
*/
|
||||
jump_to_IPL_code(0);
|
||||
}
|
||||
|
||||
/* No other option left, so use the Linux kernel start address */
|
||||
|
|
|
@ -51,6 +51,60 @@ unsigned int get_loadparm_index(void)
|
|||
return atoui(loadparm_str);
|
||||
}
|
||||
|
||||
static int is_dev_possibly_bootable(int dev_no, int sch_no)
|
||||
{
|
||||
bool is_virtio;
|
||||
Schib schib;
|
||||
int r;
|
||||
|
||||
blk_schid.sch_no = sch_no;
|
||||
r = stsch_err(blk_schid, &schib);
|
||||
if (r == 3 || r == -EIO) {
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!schib.pmcw.dnv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enable_subchannel(blk_schid);
|
||||
cutype = cu_type(blk_schid);
|
||||
|
||||
/*
|
||||
* Note: we always have to run virtio_is_supported() here to make
|
||||
* sure that the vdev.senseid data gets pre-initialized correctly
|
||||
*/
|
||||
is_virtio = virtio_is_supported(blk_schid);
|
||||
|
||||
/* No specific devno given, just return whether the device is possibly bootable */
|
||||
if (dev_no < 0) {
|
||||
switch (cutype) {
|
||||
case CU_TYPE_VIRTIO:
|
||||
if (is_virtio) {
|
||||
/*
|
||||
* Skip net devices since no IPLB is created and therefore
|
||||
* no network bootloader has been loaded
|
||||
*/
|
||||
if (virtio_get_device_type() != VIRTIO_ID_NET) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case CU_TYPE_DASD_3990:
|
||||
case CU_TYPE_DASD_2107:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Caller asked for a specific devno */
|
||||
if (schib.pmcw.dev == dev_no) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the subchannel connected to the given device (dev_no) and fill in the
|
||||
* subchannel information block (schib) with the connected subchannel's info.
|
||||
|
@ -62,53 +116,14 @@ unsigned int get_loadparm_index(void)
|
|||
*/
|
||||
static bool find_subch(int dev_no)
|
||||
{
|
||||
Schib schib;
|
||||
int i, r;
|
||||
bool is_virtio;
|
||||
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
blk_schid.sch_no = i;
|
||||
r = stsch_err(blk_schid, &schib);
|
||||
if ((r == 3) || (r == -EIO)) {
|
||||
r = is_dev_possibly_bootable(dev_no, i);
|
||||
if (r < 0) {
|
||||
break;
|
||||
}
|
||||
if (!schib.pmcw.dnv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enable_subchannel(blk_schid);
|
||||
cutype = cu_type(blk_schid);
|
||||
|
||||
/*
|
||||
* Note: we always have to run virtio_is_supported() here to make
|
||||
* sure that the vdev.senseid data gets pre-initialized correctly
|
||||
*/
|
||||
is_virtio = virtio_is_supported(blk_schid);
|
||||
|
||||
/* No specific devno given, just return 1st possibly bootable device */
|
||||
if (dev_no < 0) {
|
||||
switch (cutype) {
|
||||
case CU_TYPE_VIRTIO:
|
||||
if (is_virtio) {
|
||||
/*
|
||||
* Skip net devices since no IPLB is created and therefore
|
||||
* no network bootloader has been loaded
|
||||
*/
|
||||
if (virtio_get_device_type() != VIRTIO_ID_NET) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case CU_TYPE_DASD_3990:
|
||||
case CU_TYPE_DASD_2107:
|
||||
return true;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Caller asked for a specific devno */
|
||||
if (schib.pmcw.dev == dev_no) {
|
||||
if (r == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -167,20 +182,8 @@ static void boot_setup(void)
|
|||
static void find_boot_device(void)
|
||||
{
|
||||
VDev *vdev = virtio_get_device();
|
||||
int ssid;
|
||||
bool found;
|
||||
|
||||
if (!have_iplb) {
|
||||
for (ssid = 0; ssid < 0x3; ssid++) {
|
||||
blk_schid.ssid = ssid;
|
||||
found = find_subch(-1);
|
||||
if (found) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
panic("Could not find a suitable boot device (none specified)\n");
|
||||
}
|
||||
|
||||
switch (iplb.pbt) {
|
||||
case S390_IPL_TYPE_CCW:
|
||||
debug_print_int("device no. ", iplb.ccw.devno);
|
||||
|
@ -203,7 +206,7 @@ static void find_boot_device(void)
|
|||
IPL_assert(found, "Boot device not found\n");
|
||||
}
|
||||
|
||||
static void virtio_setup(void)
|
||||
static int virtio_setup(void)
|
||||
{
|
||||
VDev *vdev = virtio_get_device();
|
||||
QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
|
||||
|
@ -218,9 +221,56 @@ static void virtio_setup(void)
|
|||
sclp_print("Network boot device detected\n");
|
||||
vdev->netboot_start_addr = qipl.netboot_start_addr;
|
||||
} else {
|
||||
virtio_blk_setup_device(blk_schid);
|
||||
int ret = virtio_blk_setup_device(blk_schid);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipl_boot_device(void)
|
||||
{
|
||||
switch (cutype) {
|
||||
case CU_TYPE_DASD_3990:
|
||||
case CU_TYPE_DASD_2107:
|
||||
dasd_ipl(blk_schid, cutype); /* no return */
|
||||
break;
|
||||
case CU_TYPE_VIRTIO:
|
||||
if (virtio_setup() == 0) {
|
||||
zipl_load(); /* Only returns in case of errors */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print_int("Attempting to boot from unexpected device type", cutype);
|
||||
panic("\nBoot failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No boot device has been specified, so we have to scan through the
|
||||
* channels to find one.
|
||||
*/
|
||||
static void probe_boot_device(void)
|
||||
{
|
||||
int ssid, sch_no, ret;
|
||||
|
||||
for (ssid = 0; ssid < 0x3; ssid++) {
|
||||
blk_schid.ssid = ssid;
|
||||
for (sch_no = 0; sch_no < 0x10000; sch_no++) {
|
||||
ret = is_dev_possibly_bootable(-1, sch_no);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
if (ret == true) {
|
||||
ipl_boot_device(); /* Only returns if unsuccessful */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sclp_print("Could not find a suitable boot device (none specified)\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
@ -228,21 +278,11 @@ int main(void)
|
|||
sclp_setup();
|
||||
css_setup();
|
||||
boot_setup();
|
||||
find_boot_device();
|
||||
enable_subchannel(blk_schid);
|
||||
|
||||
switch (cutype) {
|
||||
case CU_TYPE_DASD_3990:
|
||||
case CU_TYPE_DASD_2107:
|
||||
dasd_ipl(blk_schid, cutype); /* no return */
|
||||
break;
|
||||
case CU_TYPE_VIRTIO:
|
||||
virtio_setup();
|
||||
zipl_load(); /* no return */
|
||||
break;
|
||||
default:
|
||||
print_int("Attempting to boot from unexpected device type", cutype);
|
||||
panic("");
|
||||
if (have_iplb) {
|
||||
find_boot_device();
|
||||
ipl_boot_device();
|
||||
} else {
|
||||
probe_boot_device();
|
||||
}
|
||||
|
||||
panic("Failed to load OS from hard disk\n");
|
||||
|
|
|
@ -27,12 +27,10 @@ typedef unsigned long long __u64;
|
|||
#define false 0
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#ifndef EIO
|
||||
#define EIO 1
|
||||
#endif
|
||||
#ifndef EBUSY
|
||||
#define EBUSY 2
|
||||
#endif
|
||||
#define ENODEV 3
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
@ -71,13 +69,14 @@ int sclp_read(char *str, size_t count);
|
|||
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
|
||||
ulong subchan_id, void *load_addr);
|
||||
bool virtio_is_supported(SubChannelId schid);
|
||||
void virtio_blk_setup_device(SubChannelId schid);
|
||||
int virtio_blk_setup_device(SubChannelId schid);
|
||||
int virtio_read(ulong sector, void *load_addr);
|
||||
|
||||
/* bootmap.c */
|
||||
void zipl_load(void);
|
||||
|
||||
/* jump2ipl.c */
|
||||
void write_reset_psw(uint64_t psw);
|
||||
void jump_to_IPL_code(uint64_t address);
|
||||
void jump_to_low_kernel(void);
|
||||
|
||||
|
|
|
@ -34,7 +34,10 @@ remainder:
|
|||
larl %r2,memsetxc
|
||||
ex %r3,0(%r2)
|
||||
done:
|
||||
j main /* And call C */
|
||||
/* set up a pgm exception disabled wait psw */
|
||||
larl %r2, disabled_wait_psw
|
||||
mvc 0x01d0(16), 0(%r2)
|
||||
j main /* And call C */
|
||||
|
||||
memsetxc:
|
||||
xc 0(1,%r1),0(%r1)
|
||||
|
|
|
@ -263,9 +263,10 @@ uint64_t virtio_get_blocks(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void virtio_blk_setup_device(SubChannelId schid)
|
||||
int virtio_blk_setup_device(SubChannelId schid)
|
||||
{
|
||||
VDev *vdev = virtio_get_device();
|
||||
int ret = 0;
|
||||
|
||||
vdev->schid = schid;
|
||||
virtio_setup_ccw(vdev);
|
||||
|
@ -288,9 +289,11 @@ void virtio_blk_setup_device(SubChannelId schid)
|
|||
"Config: CDB size mismatch");
|
||||
|
||||
sclp_print("Using virtio-scsi.\n");
|
||||
virtio_scsi_setup(vdev);
|
||||
ret = virtio_scsi_setup(vdev);
|
||||
break;
|
||||
default:
|
||||
panic("\n! No IPL device available !\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -194,7 +194,12 @@ static bool scsi_read_capacity(VDev *vdev,
|
|||
|
||||
/* virtio-scsi routines */
|
||||
|
||||
static void virtio_scsi_locate_device(VDev *vdev)
|
||||
/*
|
||||
* Tries to locate a SCSI device and and adds the information for the found
|
||||
* device to the vdev->scsi_device structure.
|
||||
* Returns 0 if SCSI device could be located, or a error code < 0 otherwise
|
||||
*/
|
||||
static int virtio_scsi_locate_device(VDev *vdev)
|
||||
{
|
||||
const uint16_t channel = 0; /* again, it's what QEMU does */
|
||||
uint16_t target;
|
||||
|
@ -220,7 +225,7 @@ static void virtio_scsi_locate_device(VDev *vdev)
|
|||
IPL_check(sdev->channel == 0, "non-zero channel requested");
|
||||
IPL_check(sdev->target <= vdev->config.scsi.max_target, "target# high");
|
||||
IPL_check(sdev->lun <= vdev->config.scsi.max_lun, "LUN# high");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (target = 0; target <= vdev->config.scsi.max_target; target++) {
|
||||
|
@ -247,18 +252,20 @@ static void virtio_scsi_locate_device(VDev *vdev)
|
|||
*/
|
||||
sdev->lun = r->lun[0].v16[0]; /* it's returned this way */
|
||||
debug_print_int("Have to use LUN", sdev->lun);
|
||||
return; /* we have to use this device */
|
||||
return 0; /* we have to use this device */
|
||||
}
|
||||
for (i = 0; i < luns; i++) {
|
||||
if (r->lun[i].v64) {
|
||||
/* Look for non-zero LUN - we have where to choose from */
|
||||
sdev->lun = r->lun[i].v16[0];
|
||||
debug_print_int("Will use LUN", sdev->lun);
|
||||
return; /* we have found a device */
|
||||
return 0; /* we have found a device */
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("\n! Cannot locate virtio-scsi device !\n");
|
||||
|
||||
sclp_print("Warning: Could not locate a usable virtio-scsi device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int virtio_scsi_read_many(VDev *vdev,
|
||||
|
@ -322,17 +329,20 @@ static void scsi_parse_capacity_report(void *data,
|
|||
}
|
||||
}
|
||||
|
||||
void virtio_scsi_setup(VDev *vdev)
|
||||
int virtio_scsi_setup(VDev *vdev)
|
||||
{
|
||||
int retry_test_unit_ready = 3;
|
||||
uint8_t data[256];
|
||||
uint32_t data_size = sizeof(data);
|
||||
ScsiInquiryEvpdPages *evpd = &scsi_inquiry_evpd_pages_response;
|
||||
ScsiInquiryEvpdBl *evpd_bl = &scsi_inquiry_evpd_bl_response;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
vdev->scsi_device = &default_scsi_device;
|
||||
virtio_scsi_locate_device(vdev);
|
||||
ret = virtio_scsi_locate_device(vdev);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We have to "ping" the device before it becomes readable */
|
||||
while (!scsi_test_unit_ready(vdev)) {
|
||||
|
@ -417,4 +427,6 @@ void virtio_scsi_setup(VDev *vdev)
|
|||
}
|
||||
scsi_parse_capacity_report(data, &vdev->scsi_last_block,
|
||||
(uint32_t *) &vdev->scsi_block_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
|
|||
return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD;
|
||||
}
|
||||
|
||||
void virtio_scsi_setup(VDev *vdev);
|
||||
int virtio_scsi_setup(VDev *vdev);
|
||||
int virtio_scsi_read_many(VDev *vdev,
|
||||
ulong sector, void *load_addr, int sec_num);
|
||||
|
||||
|
|
Binary file not shown.
|
@ -163,6 +163,18 @@ static void add_s390x_tests(void)
|
|||
qtest_add_data_func("cdrom/boot/virtio-scsi",
|
||||
"-device virtio-scsi -device scsi-cd,drive=cdr "
|
||||
"-blockdev file,node-name=cdr,filename=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/with-bootindex",
|
||||
"-device virtio-serial -device virtio-scsi "
|
||||
"-device virtio-blk,drive=d1 "
|
||||
"-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
|
||||
"-device virtio-blk,drive=d2,bootindex=1 "
|
||||
"-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
|
||||
qtest_add_data_func("cdrom/boot/without-bootindex",
|
||||
"-device virtio-scsi -device virtio-serial "
|
||||
"-device x-terminal3270 -device virtio-blk,drive=d1 "
|
||||
"-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
|
||||
"-device virtio-blk,drive=d2 "
|
||||
"-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
|
Loading…
Reference in New Issue