aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJared Rossi <jrossi@linux.ibm.com>2024-10-19 21:29:51 -0400
committerThomas Huth <thuth@redhat.com>2024-10-23 06:53:44 +0200
commitf697bed22f58eff9b2893ac2fe3d511847398400 (patch)
tree92ae7e08de86633db4fb731b7ce3179a0c304112
parent455e3bc3f74ee76964efec2e0c646db15095d0d2 (diff)
downloadqemu-f697bed22f58eff9b2893ac2fe3d511847398400.zip
qemu-f697bed22f58eff9b2893ac2fe3d511847398400.tar.gz
qemu-f697bed22f58eff9b2893ac2fe3d511847398400.tar.bz2
pc-bios/s390x: Enable multi-device boot loop
Allow attempts to boot from multiple IPL devices. If the first device fails to IPL, select the pre-built IPLB for the next device in the boot order and attempt to IPL from it. Continue this process until IPL is successful or there are no devices left to try. Signed-off-by: Jared Rossi <jrossi@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-ID: <20241020012953.1380075-18-jrossi@linux.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com>
-rw-r--r--pc-bios/s390-ccw/iplb.h24
-rw-r--r--pc-bios/s390-ccw/jump2ipl.c7
-rw-r--r--pc-bios/s390-ccw/main.c45
-rw-r--r--pc-bios/s390-ccw/netmain.c2
4 files changed, 57 insertions, 21 deletions
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 16643f5..08f259f 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -17,9 +17,11 @@
#endif
#include <qipl.h>
+#include <string.h>
extern QemuIplParameters qipl;
extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+extern bool have_iplb;
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
@@ -49,4 +51,26 @@ static inline bool set_iplb(IplParameterBlock *iplb)
return manage_iplb(iplb, false);
}
+/*
+ * The IPL started on the device, but failed in some way. If the IPLB chain
+ * still has more devices left to try, use the next device in order.
+ */
+static inline bool load_next_iplb(void)
+{
+ IplParameterBlock *next_iplb;
+
+ if (qipl.chain_len < 1) {
+ return false;
+ }
+
+ qipl.index++;
+ next_iplb = (IplParameterBlock *) qipl.next_iplb;
+ memcpy(&iplb, next_iplb, sizeof(IplParameterBlock));
+
+ qipl.chain_len--;
+ qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock);
+
+ return true;
+}
+
#endif /* IPLB_H */
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 99d1894..86321d0 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -45,9 +45,10 @@ int jump_to_IPL_code(uint64_t address)
*/
if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
iplb.devno = qipl.index;
- if (!set_iplb(&iplb)) {
- panic("Failed to set IPLB");
- }
+ }
+
+ if (have_iplb && !set_iplb(&iplb)) {
+ panic("Failed to set IPLB");
}
/*
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index ab4709e..a4d1c05 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -23,7 +23,7 @@ static SubChannelId blk_schid = { .one = 1 };
static char loadparm_str[LOADPARM_LEN + 1];
QemuIplParameters qipl;
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-static bool have_iplb;
+bool have_iplb;
static uint16_t cutype;
LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
@@ -55,6 +55,12 @@ void write_iplb_location(void)
}
}
+static void copy_qipl(void)
+{
+ QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+ memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+}
+
unsigned int get_loadparm_index(void)
{
return atoi(loadparm_str);
@@ -152,6 +158,7 @@ static void menu_setup(void)
/* If loadparm was set to any other value, then do not enable menu */
if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
+ menu_set_parms(qipl.qipl_flags & ~BOOT_MENU_FLAG_MASK, 0);
return;
}
@@ -183,7 +190,6 @@ static void css_setup(void)
static void boot_setup(void)
{
char lpmsg[] = "LOADPARM=[________]\n";
- have_iplb = store_iplb(&iplb);
if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) {
ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN);
@@ -191,6 +197,10 @@ static void boot_setup(void)
sclp_get_loadparm_ascii(loadparm_str);
}
+ if (have_iplb) {
+ menu_setup();
+ }
+
memcpy(lpmsg + 10, loadparm_str, 8);
puts(lpmsg);
@@ -208,6 +218,7 @@ static bool find_boot_device(void)
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
+ vdev->scsi_device_selected = false;
debug_print_int("device no. ", iplb.ccw.devno);
blk_schid.ssid = iplb.ccw.ssid & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
@@ -231,15 +242,8 @@ static bool find_boot_device(void)
static int virtio_setup(void)
{
VDev *vdev = virtio_get_device();
- QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
int ret;
- memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
-
- if (have_iplb) {
- menu_setup();
- }
-
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_NET:
puts("Network boot device detected");
@@ -271,10 +275,9 @@ static void ipl_boot_device(void)
dasd_ipl(blk_schid, cutype);
break;
case CU_TYPE_VIRTIO:
- if (virtio_setup()) {
- return; /* Only returns in case of errors */
+ if (virtio_setup() == 0) {
+ zipl_load();
}
- zipl_load();
break;
default:
printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
@@ -307,14 +310,22 @@ static void probe_boot_device(void)
void main(void)
{
+ copy_qipl();
sclp_setup();
css_setup();
- boot_setup();
- if (have_iplb && find_boot_device()) {
- ipl_boot_device();
- } else {
+ have_iplb = store_iplb(&iplb);
+ if (!have_iplb) {
probe_boot_device();
}
- panic("Failed to IPL. Halting...");
+ while (have_iplb) {
+ boot_setup();
+ if (have_iplb && find_boot_device()) {
+ ipl_boot_device();
+ }
+ have_iplb = load_next_iplb();
+ }
+
+ panic("No suitable device for IPL. Halting...");
+
}
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index d1a6c9a..e46e470 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -478,7 +478,7 @@ static bool virtio_setup(void)
*/
enable_mss_facility();
- if (store_iplb(&iplb)) {
+ if (have_iplb || store_iplb(&iplb)) {
IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
dev_no = iplb.ccw.devno;
debug_print_int("device no. ", dev_no);