265 lines
8.9 KiB
Diff
265 lines
8.9 KiB
Diff
|
From 9d333e9e7614676aac3a39b0f4a5f5d67323b23d Mon Sep 17 00:00:00 2001
|
||
|
From: Jared Rossi <jrossi@linux.ibm.com>
|
||
|
Date: Sat, 19 Oct 2024 21:29:50 -0400
|
||
|
Subject: [PATCH 17/27] s390x: Rebuild IPLB for SCSI device directly from
|
||
|
DIAG308
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
RH-Author: Thomas Huth <thuth@redhat.com>
|
||
|
RH-MergeRequest: 277: Full boot order support for s390x [CentOS 9]
|
||
|
RH-Jira: RHEL-11424
|
||
|
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
|
||
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||
|
RH-Commit: [17/23] d0326ad7958cc82496bf57fd09bbc877c5b8c0ac (thuth/qemu-kvm-cs9)
|
||
|
|
||
|
Because virtio-scsi type devices use a non-architected IPLB pbt code they cannot
|
||
|
be set and stored normally. Instead, the IPLB must be rebuilt during re-ipl.
|
||
|
|
||
|
As s390x does not natively support multiple boot devices, the devno field is
|
||
|
used to store the position in the boot order for the device.
|
||
|
|
||
|
Handling the rebuild as part of DIAG308 removes the need to check the devices
|
||
|
for invalid IPLBs later in the IPL.
|
||
|
|
||
|
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
|
||
|
Acked-by: Thomas Huth <thuth@redhat.com>
|
||
|
Message-ID: <20241020012953.1380075-17-jrossi@linux.ibm.com>
|
||
|
Signed-off-by: Thomas Huth <thuth@redhat.com>
|
||
|
(cherry picked from commit 455e3bc3f74ee76964efec2e0c646db15095d0d2)
|
||
|
---
|
||
|
hw/s390x/ipl.c | 74 ++++++-------------------------------
|
||
|
hw/s390x/ipl.h | 11 ++++--
|
||
|
include/hw/s390x/ipl/qipl.h | 3 +-
|
||
|
pc-bios/s390-ccw/jump2ipl.c | 11 ++++--
|
||
|
target/s390x/diag.c | 9 ++++-
|
||
|
5 files changed, 38 insertions(+), 70 deletions(-)
|
||
|
|
||
|
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
|
||
|
index f4576f8822..5fbd43c346 100644
|
||
|
--- a/hw/s390x/ipl.c
|
||
|
+++ b/hw/s390x/ipl.c
|
||
|
@@ -448,7 +448,6 @@ void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
|
||
|
|
||
|
static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
|
||
|
{
|
||
|
- S390IPLState *ipl = get_ipl_device();
|
||
|
CcwDevice *ccw_dev = NULL;
|
||
|
SCSIDevice *sd;
|
||
|
int devtype;
|
||
|
@@ -481,9 +480,6 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
|
||
|
iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
|
||
|
break;
|
||
|
case CCW_DEVTYPE_VIRTIO_NET:
|
||
|
- /* The S390IPLState netboot is true if ANY IPLB may use netboot */
|
||
|
- ipl->netboot = true;
|
||
|
- /* Fall through to CCW_DEVTYPE_VIRTIO case */
|
||
|
case CCW_DEVTYPE_VIRTIO:
|
||
|
iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
|
||
|
iplb->blk0_len =
|
||
|
@@ -508,6 +504,16 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
+void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
|
||
|
+{
|
||
|
+ S390IPLState *ipl = get_ipl_device();
|
||
|
+ uint16_t index;
|
||
|
+ index = ipl->rebuilt_iplb ? ipl->iplb_index : dev_index;
|
||
|
+
|
||
|
+ ipl->rebuilt_iplb = s390_build_iplb(get_boot_device(index), iplb);
|
||
|
+ ipl->iplb_index = index;
|
||
|
+}
|
||
|
+
|
||
|
static bool s390_init_all_iplbs(S390IPLState *ipl)
|
||
|
{
|
||
|
int iplb_num = 0;
|
||
|
@@ -564,44 +570,6 @@ static bool s390_init_all_iplbs(S390IPLState *ipl)
|
||
|
return iplb_num;
|
||
|
}
|
||
|
|
||
|
-static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
|
||
|
- int virtio_id)
|
||
|
-{
|
||
|
- uint8_t cssid;
|
||
|
- uint8_t ssid;
|
||
|
- uint16_t devno;
|
||
|
- uint16_t schid;
|
||
|
- SubchDev *sch = NULL;
|
||
|
-
|
||
|
- if (iplb->pbt != S390_IPL_TYPE_CCW) {
|
||
|
- return false;
|
||
|
- }
|
||
|
-
|
||
|
- devno = be16_to_cpu(iplb->ccw.devno);
|
||
|
- ssid = iplb->ccw.ssid & 3;
|
||
|
-
|
||
|
- for (schid = 0; schid < MAX_SCHID; schid++) {
|
||
|
- for (cssid = 0; cssid < MAX_CSSID; cssid++) {
|
||
|
- sch = css_find_subch(1, cssid, ssid, schid);
|
||
|
-
|
||
|
- if (sch && sch->devno == devno) {
|
||
|
- return sch->id.cu_model == virtio_id;
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
- return false;
|
||
|
-}
|
||
|
-
|
||
|
-static bool is_virtio_net_device(IplParameterBlock *iplb)
|
||
|
-{
|
||
|
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
|
||
|
-}
|
||
|
-
|
||
|
-static bool is_virtio_scsi_device(IplParameterBlock *iplb)
|
||
|
-{
|
||
|
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
|
||
|
-}
|
||
|
-
|
||
|
static void update_machine_ipl_properties(IplParameterBlock *iplb)
|
||
|
{
|
||
|
Object *machine = qdev_get_machine();
|
||
|
@@ -641,7 +609,7 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
|
||
|
ipl->iplb = *iplb;
|
||
|
ipl->iplb_valid = true;
|
||
|
}
|
||
|
- ipl->netboot = is_virtio_net_device(iplb);
|
||
|
+
|
||
|
update_machine_ipl_properties(iplb);
|
||
|
}
|
||
|
|
||
|
@@ -668,32 +636,14 @@ IplParameterBlock *s390_ipl_get_iplb(void)
|
||
|
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
|
||
|
{
|
||
|
S390IPLState *ipl = get_ipl_device();
|
||
|
-
|
||
|
if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
|
||
|
/* use CPU 0 for full resets */
|
||
|
ipl->reset_cpu_index = 0;
|
||
|
} else {
|
||
|
ipl->reset_cpu_index = cs->cpu_index;
|
||
|
}
|
||
|
- ipl->reset_type = reset_type;
|
||
|
|
||
|
- if (reset_type == S390_RESET_REIPL &&
|
||
|
- ipl->iplb_valid &&
|
||
|
- !ipl->netboot &&
|
||
|
- ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
|
||
|
- is_virtio_scsi_device(&ipl->iplb)) {
|
||
|
- CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
|
||
|
-
|
||
|
- if (ccw_dev &&
|
||
|
- cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
|
||
|
- (ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
|
||
|
- /*
|
||
|
- * this is the original boot device's SCSI
|
||
|
- * so restore IPL parameter info from it
|
||
|
- */
|
||
|
- ipl->iplb_valid = s390_build_iplb(get_boot_device(0), &ipl->iplb);
|
||
|
- }
|
||
|
- }
|
||
|
+ ipl->reset_type = reset_type;
|
||
|
if (reset_type == S390_RESET_MODIFIED_CLEAR ||
|
||
|
reset_type == S390_RESET_LOAD_NORMAL ||
|
||
|
reset_type == S390_RESET_PV) {
|
||
|
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
|
||
|
index 54eb48fd6e..d7d0b7bfd2 100644
|
||
|
--- a/hw/s390x/ipl.h
|
||
|
+++ b/hw/s390x/ipl.h
|
||
|
@@ -24,6 +24,7 @@
|
||
|
|
||
|
void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
|
||
|
void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
|
||
|
+void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
|
||
|
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
||
|
int s390_ipl_prepare_pv_header(Error **errp);
|
||
|
int s390_ipl_pv_unpack(void);
|
||
|
@@ -65,7 +66,8 @@ struct S390IPLState {
|
||
|
bool enforce_bios;
|
||
|
bool iplb_valid;
|
||
|
bool iplb_valid_pv;
|
||
|
- bool netboot;
|
||
|
+ bool rebuilt_iplb;
|
||
|
+ uint16_t iplb_index;
|
||
|
/* reset related properties don't have to be migrated or reset */
|
||
|
enum s390_reset reset_type;
|
||
|
int reset_cpu_index;
|
||
|
@@ -172,11 +174,14 @@ static inline bool iplb_valid_pv(IplParameterBlock *iplb)
|
||
|
|
||
|
static inline bool iplb_valid(IplParameterBlock *iplb)
|
||
|
{
|
||
|
+ uint32_t len = be32_to_cpu(iplb->len);
|
||
|
+
|
||
|
switch (iplb->pbt) {
|
||
|
case S390_IPL_TYPE_FCP:
|
||
|
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN;
|
||
|
+ return len >= S390_IPLB_MIN_FCP_LEN;
|
||
|
case S390_IPL_TYPE_CCW:
|
||
|
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN;
|
||
|
+ return len >= S390_IPLB_MIN_CCW_LEN;
|
||
|
+ case S390_IPL_TYPE_QEMU_SCSI:
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
|
||
|
index 1da4f75aa8..6824391111 100644
|
||
|
--- a/include/hw/s390x/ipl/qipl.h
|
||
|
+++ b/include/hw/s390x/ipl/qipl.h
|
||
|
@@ -29,7 +29,8 @@
|
||
|
*/
|
||
|
struct QemuIplParameters {
|
||
|
uint8_t qipl_flags;
|
||
|
- uint8_t reserved1[3];
|
||
|
+ uint8_t index;
|
||
|
+ uint8_t reserved1[2];
|
||
|
uint64_t reserved2;
|
||
|
uint32_t boot_menu_timeout;
|
||
|
uint8_t reserved3[2];
|
||
|
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
|
||
|
index 8db1764ff3..99d18947d1 100644
|
||
|
--- a/pc-bios/s390-ccw/jump2ipl.c
|
||
|
+++ b/pc-bios/s390-ccw/jump2ipl.c
|
||
|
@@ -39,10 +39,15 @@ int jump_to_IPL_code(uint64_t address)
|
||
|
write_subsystem_identification();
|
||
|
write_iplb_location();
|
||
|
|
||
|
- /* prevent unknown IPL types in the guest */
|
||
|
+ /*
|
||
|
+ * The IPLB for QEMU SCSI type devices must be rebuilt during re-ipl. The
|
||
|
+ * iplb.devno is set to the boot position of the target SCSI device.
|
||
|
+ */
|
||
|
if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
|
||
|
- iplb.pbt = S390_IPL_TYPE_CCW;
|
||
|
- set_iplb(&iplb);
|
||
|
+ iplb.devno = qipl.index;
|
||
|
+ if (!set_iplb(&iplb)) {
|
||
|
+ panic("Failed to set IPLB");
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
|
||
|
index 27ffd48576..a1fd54ddac 100644
|
||
|
--- a/target/s390x/diag.c
|
||
|
+++ b/target/s390x/diag.c
|
||
|
@@ -133,7 +133,14 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
|
||
|
|
||
|
valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
|
||
|
if (!valid) {
|
||
|
- env->regs[r1 + 1] = DIAG_308_RC_INVALID;
|
||
|
+ if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_QEMU_SCSI) {
|
||
|
+ s390_rebuild_iplb(iplb->devno, iplb);
|
||
|
+ s390_ipl_update_diag308(iplb);
|
||
|
+ env->regs[r1 + 1] = DIAG_308_RC_OK;
|
||
|
+ } else {
|
||
|
+ env->regs[r1 + 1] = DIAG_308_RC_INVALID;
|
||
|
+ }
|
||
|
+
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.39.3
|
||
|
|