pc-bios/s390-ccw: Enable failed IPL to return after error
Remove panic-on-error from IPL functions such that a return code is propagated back to the main IPL calling function (rather than terminating immediately), which facilitates possible error recovery in the future. A select few panics remain, which indicate fatal non-devices errors that must result in termination. Signed-off-by: Jared Rossi <jrossi@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-ID: <20241020012953.1380075-13-jrossi@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
f1a2a6e41e
commit
0181e23713
@ -62,15 +62,34 @@ static void *s2_prev_blk = _s2;
|
|||||||
static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
|
static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
|
||||||
static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
|
static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
|
||||||
|
|
||||||
static inline void verify_boot_info(BootInfo *bip)
|
static inline int verify_boot_info(BootInfo *bip)
|
||||||
{
|
{
|
||||||
IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL sig in BootInfo");
|
if (!magic_match(bip->magic, ZIPL_MAGIC)) {
|
||||||
IPL_assert(bip->version == BOOT_INFO_VERSION, "Wrong zIPL version");
|
puts("No zIPL sig in BootInfo");
|
||||||
IPL_assert(bip->bp_type == BOOT_INFO_BP_TYPE_IPL, "DASD is not for IPL");
|
return -EINVAL;
|
||||||
IPL_assert(bip->dev_type == BOOT_INFO_DEV_TYPE_ECKD, "DASD is not ECKD");
|
}
|
||||||
IPL_assert(bip->flags == BOOT_INFO_FLAGS_ARCH, "Not for this arch");
|
if (bip->version != BOOT_INFO_VERSION) {
|
||||||
IPL_assert(block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size),
|
puts("Wrong zIPL version");
|
||||||
"Bad block size in zIPL section of the 1st record.");
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (bip->bp_type != BOOT_INFO_BP_TYPE_IPL) {
|
||||||
|
puts("DASD is not for IPL");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
if (bip->dev_type != BOOT_INFO_DEV_TYPE_ECKD) {
|
||||||
|
puts("DASD is not ECKD");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
if (bip->flags != BOOT_INFO_FLAGS_ARCH) {
|
||||||
|
puts("Not for this arch");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size)) {
|
||||||
|
puts("Bad block size in zIPL section of 1st record");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eckd_format_chs(ExtEckdBlockPtr *ptr, bool ldipl,
|
static void eckd_format_chs(ExtEckdBlockPtr *ptr, bool ldipl,
|
||||||
@ -367,8 +386,8 @@ static int run_eckd_boot_script(block_number_t bmt_block_nr,
|
|||||||
puts("Unknown script entry type");
|
puts("Unknown script entry type");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
write_reset_psw(bms->entry[i].address.load_address); /* no return */
|
write_reset_psw(bms->entry[i].address.load_address);
|
||||||
jump_to_IPL_code(0); /* no return */
|
jump_to_IPL_code(0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,16 +1086,19 @@ void zipl_load(void)
|
|||||||
|
|
||||||
if (vdev->is_cdrom) {
|
if (vdev->is_cdrom) {
|
||||||
ipl_iso_el_torito();
|
ipl_iso_el_torito();
|
||||||
panic("\n! Cannot IPL this ISO image !\n");
|
puts("Failed to IPL this ISO image!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virtio_get_device_type() == VIRTIO_ID_NET) {
|
if (virtio_get_device_type() == VIRTIO_ID_NET) {
|
||||||
netmain();
|
netmain();
|
||||||
panic("\n! Cannot IPL from this network !\n");
|
puts("Failed to IPL from this network!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipl_scsi()) {
|
if (ipl_scsi()) {
|
||||||
panic("\n! Cannot IPL this SCSI device !\n");
|
puts("Failed to IPL from this SCSI device!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (virtio_get_device_type()) {
|
switch (virtio_get_device_type()) {
|
||||||
@ -1087,8 +1109,9 @@ void zipl_load(void)
|
|||||||
zipl_load_vscsi();
|
zipl_load_vscsi();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("\n! Unknown IPL device type !\n");
|
puts("Unknown IPL device type!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("zIPL load failed.");
|
puts("zIPL load failed!");
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,8 @@ uint16_t cu_type(SubChannelId schid)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
|
if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
|
||||||
panic("Failed to run SenseID CCw\n");
|
puts("Failed to run SenseID CCW");
|
||||||
|
return CU_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sense_data.cu_type;
|
return sense_data.cu_type;
|
||||||
|
@ -33,7 +33,7 @@ static void jump_to_IPL_addr(void)
|
|||||||
/* should not return */
|
/* should not return */
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump_to_IPL_code(uint64_t address)
|
int jump_to_IPL_code(uint64_t address)
|
||||||
{
|
{
|
||||||
/* store the subsystem information _after_ the bootmap was loaded */
|
/* store the subsystem information _after_ the bootmap was loaded */
|
||||||
write_subsystem_identification();
|
write_subsystem_identification();
|
||||||
@ -68,7 +68,8 @@ void jump_to_IPL_code(uint64_t address)
|
|||||||
asm volatile("lghi %%r1,1\n\t"
|
asm volatile("lghi %%r1,1\n\t"
|
||||||
"diag %%r1,%%r1,0x308\n\t"
|
"diag %%r1,%%r1,0x308\n\t"
|
||||||
: : : "1", "memory");
|
: : : "1", "memory");
|
||||||
panic("\n! IPL returns !\n");
|
puts("IPL code jump failed");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump_to_low_kernel(void)
|
void jump_to_low_kernel(void)
|
||||||
|
@ -77,6 +77,9 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
|
|||||||
|
|
||||||
enable_subchannel(blk_schid);
|
enable_subchannel(blk_schid);
|
||||||
cutype = cu_type(blk_schid);
|
cutype = cu_type(blk_schid);
|
||||||
|
if (cutype == CU_TYPE_UNKNOWN) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: we always have to run virtio_is_supported() here to make
|
* Note: we always have to run virtio_is_supported() here to make
|
||||||
@ -194,10 +197,10 @@ static void boot_setup(void)
|
|||||||
have_iplb = store_iplb(&iplb);
|
have_iplb = store_iplb(&iplb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_boot_device(void)
|
static bool find_boot_device(void)
|
||||||
{
|
{
|
||||||
VDev *vdev = virtio_get_device();
|
VDev *vdev = virtio_get_device();
|
||||||
bool found;
|
bool found = false;
|
||||||
|
|
||||||
switch (iplb.pbt) {
|
switch (iplb.pbt) {
|
||||||
case S390_IPL_TYPE_CCW:
|
case S390_IPL_TYPE_CCW:
|
||||||
@ -215,10 +218,10 @@ static void find_boot_device(void)
|
|||||||
found = find_subch(iplb.scsi.devno);
|
found = find_subch(iplb.scsi.devno);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("List-directed IPL not supported yet!\n");
|
puts("Unsupported IPLB");
|
||||||
}
|
}
|
||||||
|
|
||||||
IPL_assert(found, "Boot device not found\n");
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_setup(void)
|
static int virtio_setup(void)
|
||||||
@ -244,11 +247,13 @@ static int virtio_setup(void)
|
|||||||
ret = virtio_scsi_setup_device(blk_schid);
|
ret = virtio_scsi_setup_device(blk_schid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("\n! No IPL device available !\n");
|
puts("\n! No IPL device available !\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret && !virtio_ipl_disk_is_valid()) {
|
||||||
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
|
puts("No valid IPL device detected");
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -259,16 +264,16 @@ static void ipl_boot_device(void)
|
|||||||
switch (cutype) {
|
switch (cutype) {
|
||||||
case CU_TYPE_DASD_3990:
|
case CU_TYPE_DASD_3990:
|
||||||
case CU_TYPE_DASD_2107:
|
case CU_TYPE_DASD_2107:
|
||||||
dasd_ipl(blk_schid, cutype); /* no return */
|
dasd_ipl(blk_schid, cutype);
|
||||||
break;
|
break;
|
||||||
case CU_TYPE_VIRTIO:
|
case CU_TYPE_VIRTIO:
|
||||||
if (virtio_setup() == 0) {
|
if (virtio_setup()) {
|
||||||
zipl_load(); /* Only returns in case of errors */
|
return; /* Only returns in case of errors */
|
||||||
}
|
}
|
||||||
|
zipl_load();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
|
printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
|
||||||
panic("\nBoot failed.\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,12 +306,11 @@ void main(void)
|
|||||||
sclp_setup();
|
sclp_setup();
|
||||||
css_setup();
|
css_setup();
|
||||||
boot_setup();
|
boot_setup();
|
||||||
if (have_iplb) {
|
if (have_iplb && find_boot_device()) {
|
||||||
find_boot_device();
|
|
||||||
ipl_boot_device();
|
ipl_boot_device();
|
||||||
} else {
|
} else {
|
||||||
probe_boot_device();
|
probe_boot_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Failed to load OS from hard disk\n");
|
panic("Failed to IPL. Halting...");
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ void zipl_load(void);
|
|||||||
|
|
||||||
/* jump2ipl.c */
|
/* jump2ipl.c */
|
||||||
void write_reset_psw(uint64_t psw);
|
void write_reset_psw(uint64_t psw);
|
||||||
void jump_to_IPL_code(uint64_t address);
|
int jump_to_IPL_code(uint64_t address);
|
||||||
void jump_to_low_kernel(void);
|
void jump_to_low_kernel(void);
|
||||||
|
|
||||||
/* menu.c */
|
/* menu.c */
|
||||||
|
@ -59,7 +59,7 @@ int virtio_read_many(unsigned long sector, void *load_addr, int sec_num)
|
|||||||
case VIRTIO_ID_SCSI:
|
case VIRTIO_ID_SCSI:
|
||||||
return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
|
return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
|
||||||
}
|
}
|
||||||
panic("\n! No readable IPL device !\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,16 +217,19 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_setup_ccw(VDev *vdev)
|
int virtio_setup_ccw(VDev *vdev)
|
||||||
{
|
{
|
||||||
int i, rc, cfg_size = 0;
|
int i, cfg_size = 0;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
struct VirtioFeatureDesc {
|
struct VirtioFeatureDesc {
|
||||||
uint32_t features;
|
uint32_t features;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
} __attribute__((packed)) feats;
|
} __attribute__((packed)) feats;
|
||||||
|
|
||||||
IPL_assert(virtio_is_supported(vdev->schid), "PE");
|
if (!virtio_is_supported(vdev->schid)) {
|
||||||
|
puts("Virtio unsupported for this device ID");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
/* device ID has been established now */
|
/* device ID has been established now */
|
||||||
|
|
||||||
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
|
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
|
||||||
@ -235,8 +238,10 @@ void virtio_setup_ccw(VDev *vdev)
|
|||||||
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
|
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
|
||||||
|
|
||||||
status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
|
||||||
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
|
||||||
IPL_assert(rc == 0, "Could not write ACKNOWLEDGE status to host");
|
puts("Could not write ACKNOWLEDGE status to host");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
switch (vdev->senseid.cu_model) {
|
switch (vdev->senseid.cu_model) {
|
||||||
case VIRTIO_ID_NET:
|
case VIRTIO_ID_NET:
|
||||||
@ -255,27 +260,37 @@ void virtio_setup_ccw(VDev *vdev)
|
|||||||
cfg_size = sizeof(vdev->config.scsi);
|
cfg_size = sizeof(vdev->config.scsi);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unsupported virtio device\n");
|
puts("Unsupported virtio device");
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
status |= VIRTIO_CONFIG_S_DRIVER;
|
status |= VIRTIO_CONFIG_S_DRIVER;
|
||||||
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
|
||||||
IPL_assert(rc == 0, "Could not write DRIVER status to host");
|
puts("Could not write DRIVER status to host");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* Feature negotiation */
|
/* Feature negotiation */
|
||||||
for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
|
for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
|
||||||
feats.features = 0;
|
feats.features = 0;
|
||||||
feats.index = i;
|
feats.index = i;
|
||||||
rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false);
|
if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
|
||||||
IPL_assert(rc == 0, "Could not get features bits");
|
puts("Could not get features bits");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
vdev->guest_features[i] &= bswap32(feats.features);
|
vdev->guest_features[i] &= bswap32(feats.features);
|
||||||
feats.features = bswap32(vdev->guest_features[i]);
|
feats.features = bswap32(vdev->guest_features[i]);
|
||||||
rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false);
|
if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
|
||||||
IPL_assert(rc == 0, "Could not set features bits");
|
puts("Could not set features bits");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false);
|
if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
|
||||||
IPL_assert(rc == 0, "Could not get virtio device configuration");
|
puts("Could not get virtio device configuration");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < vdev->nr_vqs; i++) {
|
for (i = 0; i < vdev->nr_vqs; i++) {
|
||||||
VqInfo info = {
|
VqInfo info = {
|
||||||
@ -289,19 +304,27 @@ void virtio_setup_ccw(VDev *vdev)
|
|||||||
.num = 0,
|
.num = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false);
|
if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
|
||||||
IPL_assert(rc == 0, "Could not get virtio device VQ configuration");
|
false)) {
|
||||||
|
puts("Could not get virtio device VQ config");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
info.num = config.num;
|
info.num = config.num;
|
||||||
vring_init(&vdev->vrings[i], &info);
|
vring_init(&vdev->vrings[i], &info);
|
||||||
vdev->vrings[i].schid = vdev->schid;
|
vdev->vrings[i].schid = vdev->schid;
|
||||||
IPL_assert(
|
if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
|
||||||
run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
|
puts("Cannot set VQ info");
|
||||||
"Cannot set VQ info");
|
return -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status |= VIRTIO_CONFIG_S_DRIVER_OK;
|
status |= VIRTIO_CONFIG_S_DRIVER_OK;
|
||||||
rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
|
if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
|
||||||
IPL_assert(rc == 0, "Could not write DRIVER_OK status to host");
|
puts("Could not write DRIVER_OK status to host");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool virtio_is_supported(SubChannelId schid)
|
bool virtio_is_supported(SubChannelId schid)
|
||||||
|
@ -274,7 +274,7 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags);
|
|||||||
int vr_poll(VRing *vr);
|
int vr_poll(VRing *vr);
|
||||||
int vring_wait_reply(void);
|
int vring_wait_reply(void);
|
||||||
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
|
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
|
||||||
void virtio_setup_ccw(VDev *vdev);
|
int virtio_setup_ccw(VDev *vdev);
|
||||||
|
|
||||||
int virtio_net_init(void *mac_addr);
|
int virtio_net_init(void *mac_addr);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user