* [PATCH 1/6] s390x: Rename SCSI IPL type to indicate CCW bus
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
@ 2026-05-04 22:16 ` jrossi
2026-05-08 16:53 ` Eric Farman
2026-05-04 22:16 ` [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations jrossi
` (4 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
As IPL support is being added for some PCI devices it is necessary to specify
the bus type of the SCSI controller when booting from a SCSI device. Therefore
the IPL type S390_IPL_TYPE_QEMU_SCSI is changed to to S390_IPL_TYPE_CCW_SCSI.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
hw/s390x/ipl.c | 14 +++++++-------
hw/s390x/ipl.h | 2 +-
include/hw/s390x/ipl/qipl.h | 8 ++++----
pc-bios/s390-ccw/jump2ipl.c | 4 ++--
pc-bios/s390-ccw/main.c | 16 ++++++++--------
pc-bios/s390-ccw/virtio-blkdev.c | 2 +-
pc-bios/s390-ccw/virtio.c | 12 ++++++------
target/s390x/diag.c | 2 +-
8 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 1babcd2b7d..402f5dbd7e 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -315,7 +315,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
return;
}
break;
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
break;
default:
if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
@@ -477,12 +477,12 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
iplb->blk0_len =
cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
- iplb->pbt = S390_IPL_TYPE_QEMU_SCSI;
- iplb->scsi.lun = cpu_to_be32(sd->lun);
- iplb->scsi.target = cpu_to_be16(sd->id);
- iplb->scsi.channel = cpu_to_be16(sd->channel);
- iplb->scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
- iplb->scsi.ssid = ccw_dev->sch->ssid & 3;
+ iplb->pbt = S390_IPL_TYPE_CCW_SCSI;
+ iplb->ccw_scsi.lun = cpu_to_be32(sd->lun);
+ iplb->ccw_scsi.target = cpu_to_be16(sd->id);
+ iplb->ccw_scsi.channel = cpu_to_be16(sd->channel);
+ iplb->ccw_scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->ccw_scsi.ssid = ccw_dev->sch->ssid & 3;
break;
case CCW_DEVTYPE_VFIO:
iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index fac30763df..5d4c618ecf 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -182,7 +182,7 @@ static inline bool iplb_valid(IplParameterBlock *iplb)
return len >= S390_IPLB_MIN_CCW_LEN;
case S390_IPL_TYPE_PCI:
return len >= S390_IPLB_MIN_PCI_LEN;
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
default:
return false;
}
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 8d3c83a80b..67db54c964 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -25,7 +25,7 @@ enum S390IplType {
S390_IPL_TYPE_CCW = 0x02,
S390_IPL_TYPE_PCI = 0x04,
S390_IPL_TYPE_PV = 0x05,
- S390_IPL_TYPE_QEMU_SCSI = 0xff
+ S390_IPL_TYPE_CCW_SCSI = 0xff
};
typedef enum S390IplType S390IplType;
@@ -99,7 +99,7 @@ struct IplBlockFcp {
} QEMU_PACKED;
typedef struct IplBlockFcp IplBlockFcp;
-struct IplBlockQemuScsi {
+struct IplBlockCcwScsi {
uint32_t lun;
uint16_t target;
uint16_t channel;
@@ -107,7 +107,7 @@ struct IplBlockQemuScsi {
uint8_t ssid;
uint16_t devno;
} QEMU_PACKED;
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+typedef struct IplBlockCcwScsi IplBlockCcwScsi;
struct IplBlockPci {
uint32_t reserved0[76];
@@ -131,7 +131,7 @@ union IplParameterBlock {
IplBlockCcw ccw;
IplBlockFcp fcp;
IPLBlockPV pv;
- IplBlockQemuScsi scsi;
+ IplBlockCcwScsi ccw_scsi;
IplBlockPci pci;
};
} QEMU_PACKED;
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 86321d0f46..f8f6b21327 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -40,10 +40,10 @@ int jump_to_IPL_code(uint64_t address)
write_iplb_location();
/*
- * The IPLB for QEMU SCSI type devices must be rebuilt during re-ipl. The
+ * The IPLB for 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) {
+ if (iplb.pbt == S390_IPL_TYPE_CCW_SCSI) {
iplb.devno = qipl.index;
}
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 26287cfd81..1a9579beab 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -183,7 +183,7 @@ static void menu_setup(VDev *vdev)
switch (vdev->ipl_type) {
case S390_IPL_TYPE_CCW:
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
menu_set_parms(qipl.qipl_flags & BOOT_MENU_FLAG_MASK,
qipl.boot_menu_timeout);
/* fall through */
@@ -249,13 +249,13 @@ static bool find_boot_device(void)
debug_print_int("ssid ", blk_schid.ssid);
found = find_subch(iplb.ccw.devno);
break;
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
vdev->scsi_device_selected = true;
- vdev->selected_scsi_device.channel = iplb.scsi.channel;
- vdev->selected_scsi_device.target = iplb.scsi.target;
- vdev->selected_scsi_device.lun = iplb.scsi.lun;
- blk_schid.ssid = iplb.scsi.ssid & 0x3;
- found = find_subch(iplb.scsi.devno);
+ vdev->selected_scsi_device.channel = iplb.ccw_scsi.channel;
+ vdev->selected_scsi_device.target = iplb.ccw_scsi.target;
+ vdev->selected_scsi_device.lun = iplb.ccw_scsi.lun;
+ blk_schid.ssid = iplb.ccw_scsi.ssid & 0x3;
+ found = find_subch(iplb.ccw_scsi.devno);
break;
case S390_IPL_TYPE_PCI:
found = find_fid(iplb.pci.fid);
@@ -339,7 +339,7 @@ static void ipl_pci_device(void)
static void ipl_boot_device(void)
{
switch (virtio_get_device()->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
ipl_ccw_device();
break;
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index 98b6cec3a0..40631e0c0f 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -253,7 +253,7 @@ int virtio_blk_setup_device(VDev *vdev)
puts("Using virtio-blk.");
switch (vdev->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_ccw_setup(vdev);
case S390_IPL_TYPE_PCI:
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 390b55c7b9..30e6b2bc16 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -61,7 +61,7 @@ char *virtio_get_ring_area(int ring_num)
int drain_irqs(void)
{
switch (vdev.ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return drain_irqs_ccw(vdev.schid);
default:
@@ -72,7 +72,7 @@ int drain_irqs(void)
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
{
switch (vdev->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_ccw_run(vdev, vqid, cmd);
default:
@@ -109,7 +109,7 @@ void vring_init(VRing *vr, VqInfo *info)
bool vring_notify(VRing *vr)
{
switch (vdev.ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
break;
@@ -129,7 +129,7 @@ bool vring_notify(VRing *vr)
bool be_ipl(void)
{
switch (virtio_get_device()->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return true;
case S390_IPL_TYPE_PCI:
@@ -230,7 +230,7 @@ int vring_wait_reply(void)
int virtio_reset(VDev *vdev)
{
switch (vdev->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_ccw_reset(vdev);
case S390_IPL_TYPE_PCI:
@@ -243,7 +243,7 @@ int virtio_reset(VDev *vdev)
bool virtio_is_supported(VDev *vdev)
{
switch (vdev->ipl_type) {
- case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_ccw_is_supported(vdev);
default:
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index da44b0133e..06bdb2bbc8 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -133,7 +133,7 @@ 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) {
- if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_QEMU_SCSI) {
+ if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_CCW_SCSI) {
s390_rebuild_iplb(iplb->devno, iplb);
s390_ipl_update_diag308(iplb);
env->regs[r1 + 1] = DIAG_308_RC_OK;
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH 1/6] s390x: Rename SCSI IPL type to indicate CCW bus
2026-05-04 22:16 ` [PATCH 1/6] s390x: Rename SCSI IPL type to indicate CCW bus jrossi
@ 2026-05-08 16:53 ` Eric Farman
0 siblings, 0 replies; 15+ messages in thread
From: Eric Farman @ 2026-05-08 16:53 UTC (permalink / raw)
To: jrossi, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
>
> As IPL support is being added for some PCI devices it is necessary to specify
> the bus type of the SCSI controller when booting from a SCSI device. Therefore
> the IPL type S390_IPL_TYPE_QEMU_SCSI is changed to to S390_IPL_TYPE_CCW_SCSI.
>
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> ---
> hw/s390x/ipl.c | 14 +++++++-------
> hw/s390x/ipl.h | 2 +-
> include/hw/s390x/ipl/qipl.h | 8 ++++----
> pc-bios/s390-ccw/jump2ipl.c | 4 ++--
> pc-bios/s390-ccw/main.c | 16 ++++++++--------
> pc-bios/s390-ccw/virtio-blkdev.c | 2 +-
> pc-bios/s390-ccw/virtio.c | 12 ++++++------
> target/s390x/diag.c | 2 +-
> 8 files changed, 30 insertions(+), 30 deletions(-)
Reviewed-by: Eric Farman <farman@linux.ibm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
2026-05-04 22:16 ` [PATCH 1/6] s390x: Rename SCSI IPL type to indicate CCW bus jrossi
@ 2026-05-04 22:16 ` jrossi
2026-05-06 18:20 ` Zhuoying Cai
2026-05-08 17:23 ` Eric Farman
2026-05-04 22:16 ` [PATCH 3/6] pc-bios/s390-ccw: Rename Virtio CCW run function for generic use jrossi
` (3 subsequent siblings)
5 siblings, 2 replies; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
The initial support for virtio-blk-pci IPL devices used a single virt-queue, but
other device types require multiple queues, and for PCI device types this also
requires a per-queue notification offset.
Add a PCI notify field to the VRing struct so that each queue has a unique
notify offset. Also re-select the target queue before writing buffers to
ensure the proper queue is active.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
pc-bios/s390-ccw/virtio-pci.h | 3 ++-
pc-bios/s390-ccw/virtio.c | 4 +++-
pc-bios/s390-ccw/virtio.h | 1 +
4 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
index 53bdb52e76..736869f4f5 100644
--- a/pc-bios/s390-ccw/virtio-pci.c
+++ b/pc-bios/s390-ccw/virtio-pci.c
@@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
return 0;
}
-long virtio_pci_notify(int vq_id)
+long virtio_pci_notify(VRing *vr)
{
- uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
- return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
+ uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
+ return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
}
/*
@@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
return 0;
}
-static int vpci_set_selected_vq(uint16_t queue_num)
+int vpci_set_selected_vq(uint16_t queue_num)
{
return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
}
@@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
VRing *vr;
int rc;
uint8_t status;
- uint16_t vq_size;
int i = 0;
vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
@@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
return -EIO;
}
- if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
- puts("Failed to read virt-queue configuration");
- return -EIO;
- }
-
/* Configure virt-queues for pci */
for (i = 0; i < vdev->nr_vqs; i++) {
+ uint16_t vq_size;
+ uint16_t vq_notify;
VqInfo info = {
.queue = (unsigned long long) virtio_get_ring_area(i),
.align = KVM_S390_VIRTIO_RING_ALIGN,
.index = i,
- .num = vq_size,
+ .num = 0,
};
vr = &vdev->vrings[i];
- vring_init(vr, &info);
- if (vpci_set_selected_vq(vr->id)) {
+ if (vpci_set_selected_vq(i)) {
puts("Failed to set selected virt-queue");
return -EIO;
}
+ if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
+ puts("Failed to read virt-queue configuration");
+ return -EIO;
+ }
+
+ info.num = vq_size;
+
+ if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
+ puts("Failed to read virt-queue configuration");
+ return -EIO;
+ }
+
+ vr->pci_notify = vq_notify;
+ vring_init(vr, &info);
+
rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
index 90d07cb9a7..993fc285ac 100644
--- a/pc-bios/s390-ccw/virtio-pci.h
+++ b/pc-bios/s390-ccw/virtio-pci.h
@@ -62,9 +62,10 @@ struct VirtioPciCap {
};
typedef struct VirtioPciCap VirtioPciCap;
+int vpci_set_selected_vq(uint16_t queue_num);
void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
int virtio_pci_reset(VDev *vdev);
-long virtio_pci_notify(int vq_id);
+long virtio_pci_notify(VRing *vr);
int virtio_pci_setup(VDev *vdev);
int virtio_pci_setup_device(void);
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 30e6b2bc16..00850acc2f 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
break;
case S390_IPL_TYPE_PCI:
- vr->cookie = virtio_pci_notify(vr->id);
+ vr->cookie = virtio_pci_notify(vr);
+ break;
default:
return 1;
}
@@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
void vring_send_buf(VRing *vr, void *p, int len, int flags)
{
if (!be_ipl()) {
+ vpci_set_selected_vq(vr->id);
vr->avail->idx = bswap16(vr->avail->idx);
}
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index d32a4830ca..75ae5bdbc2 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -107,6 +107,7 @@ struct VRing {
VRingUsed *used;
long cookie;
int id;
+ uint16_t pci_notify;
};
typedef struct VRing VRing;
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations
2026-05-04 22:16 ` [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations jrossi
@ 2026-05-06 18:20 ` Zhuoying Cai
2026-05-07 13:26 ` Jared Rossi
2026-05-08 17:23 ` Eric Farman
1 sibling, 1 reply; 15+ messages in thread
From: Zhuoying Cai @ 2026-05-06 18:20 UTC (permalink / raw)
To: jrossi, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato
On 5/4/26 6:16 PM, jrossi@linux.ibm.com wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
>
> The initial support for virtio-blk-pci IPL devices used a single virt-queue, but
> other device types require multiple queues, and for PCI device types this also
> requires a per-queue notification offset.
>
> Add a PCI notify field to the VRing struct so that each queue has a unique
> notify offset. Also re-select the target queue before writing buffers to
> ensure the proper queue is active.
>
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> ---
> pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
> pc-bios/s390-ccw/virtio-pci.h | 3 ++-
> pc-bios/s390-ccw/virtio.c | 4 +++-
> pc-bios/s390-ccw/virtio.h | 1 +
> 4 files changed, 29 insertions(+), 15 deletions(-)
>
> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
> index 53bdb52e76..736869f4f5 100644
> --- a/pc-bios/s390-ccw/virtio-pci.c
> +++ b/pc-bios/s390-ccw/virtio-pci.c
> @@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
> return 0;
> }
>
> -long virtio_pci_notify(int vq_id)
> +long virtio_pci_notify(VRing *vr)
> {
> - uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
> - return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
> + uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
> + return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
> }
>
> /*
> @@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
> return 0;
> }
>
> -static int vpci_set_selected_vq(uint16_t queue_num)
> +int vpci_set_selected_vq(uint16_t queue_num)
> {
> return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
> }
> @@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
> VRing *vr;
> int rc;
> uint8_t status;
> - uint16_t vq_size;
> int i = 0;
>
> vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> @@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
> return -EIO;
> }
>
> - if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
> - puts("Failed to read virt-queue configuration");
> - return -EIO;
> - }
> -
> /* Configure virt-queues for pci */
> for (i = 0; i < vdev->nr_vqs; i++) {
> + uint16_t vq_size;
> + uint16_t vq_notify;
> VqInfo info = {
> .queue = (unsigned long long) virtio_get_ring_area(i),
> .align = KVM_S390_VIRTIO_RING_ALIGN,
> .index = i,
> - .num = vq_size,
> + .num = 0,
> };
>
> vr = &vdev->vrings[i];
> - vring_init(vr, &info);
>
> - if (vpci_set_selected_vq(vr->id)) {
> + if (vpci_set_selected_vq(i)) {
> puts("Failed to set selected virt-queue");
> return -EIO;
> }
>
> + if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
Small nit: c_cap.off + VPCI_C_OFFSET_Q_SIZE
> + puts("Failed to read virt-queue configuration");
> + return -EIO;
> + }
> +
> + info.num = vq_size;
> +
> + if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
> + puts("Failed to read virt-queue configuration");
> + return -EIO;
> + }
Since the notification offset is now read per queue, should we remove
the same read in virtio_pci_read_pci_cap_config() as well as the global
q_notify_offset variable?
if (rc || vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar,
&q_notify_offset))
> +
> + vr->pci_notify = vq_notify;
> + vring_init(vr, &info);
> +
> rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
> diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
> index 90d07cb9a7..993fc285ac 100644
> --- a/pc-bios/s390-ccw/virtio-pci.h
> +++ b/pc-bios/s390-ccw/virtio-pci.h
> @@ -62,9 +62,10 @@ struct VirtioPciCap {
> };
> typedef struct VirtioPciCap VirtioPciCap;
>
> +int vpci_set_selected_vq(uint16_t queue_num);
> void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
> int virtio_pci_reset(VDev *vdev);
> -long virtio_pci_notify(int vq_id);
> +long virtio_pci_notify(VRing *vr);
> int virtio_pci_setup(VDev *vdev);
> int virtio_pci_setup_device(void);
>
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> index 30e6b2bc16..00850acc2f 100644
> --- a/pc-bios/s390-ccw/virtio.c
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
> vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
> break;
> case S390_IPL_TYPE_PCI:
> - vr->cookie = virtio_pci_notify(vr->id);
> + vr->cookie = virtio_pci_notify(vr);
> + break;
> default:
> return 1;
> }
> @@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
> void vring_send_buf(VRing *vr, void *p, int len, int flags)
> {
> if (!be_ipl()) {
> + vpci_set_selected_vq(vr->id);
> vr->avail->idx = bswap16(vr->avail->idx);
> }
>
> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
> index d32a4830ca..75ae5bdbc2 100644
> --- a/pc-bios/s390-ccw/virtio.h
> +++ b/pc-bios/s390-ccw/virtio.h
> @@ -107,6 +107,7 @@ struct VRing {
> VRingUsed *used;
> long cookie;
> int id;
> + uint16_t pci_notify;
> };
> typedef struct VRing VRing;
>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations
2026-05-06 18:20 ` Zhuoying Cai
@ 2026-05-07 13:26 ` Jared Rossi
0 siblings, 0 replies; 15+ messages in thread
From: Jared Rossi @ 2026-05-07 13:26 UTC (permalink / raw)
To: Zhuoying Cai, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato
On 5/6/26 2:20 PM, Zhuoying Cai wrote:
> On 5/4/26 6:16 PM, jrossi@linux.ibm.com wrote:
>> From: Jared Rossi <jrossi@linux.ibm.com>
>>
>> The initial support for virtio-blk-pci IPL devices used a single virt-queue, but
>> other device types require multiple queues, and for PCI device types this also
>> requires a per-queue notification offset.
>>
>> Add a PCI notify field to the VRing struct so that each queue has a unique
>> notify offset. Also re-select the target queue before writing buffers to
>> ensure the proper queue is active.
>>
>> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
>> ---
>> pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
>> pc-bios/s390-ccw/virtio-pci.h | 3 ++-
>> pc-bios/s390-ccw/virtio.c | 4 +++-
>> pc-bios/s390-ccw/virtio.h | 1 +
>> 4 files changed, 29 insertions(+), 15 deletions(-)
>>
>> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
>> index 53bdb52e76..736869f4f5 100644
>> --- a/pc-bios/s390-ccw/virtio-pci.c
>> +++ b/pc-bios/s390-ccw/virtio-pci.c
>> @@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
>> return 0;
>> }
>>
>> -long virtio_pci_notify(int vq_id)
>> +long virtio_pci_notify(VRing *vr)
>> {
>> - uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
>> - return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
>> + uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
>> + return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
>> }
>>
>> /*
>> @@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
>> return 0;
>> }
>>
>> -static int vpci_set_selected_vq(uint16_t queue_num)
>> +int vpci_set_selected_vq(uint16_t queue_num)
>> {
>> return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
>> }
>> @@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
>> VRing *vr;
>> int rc;
>> uint8_t status;
>> - uint16_t vq_size;
>> int i = 0;
>>
>> vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
>> @@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
>> return -EIO;
>> }
>>
>> - if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
>> - puts("Failed to read virt-queue configuration");
>> - return -EIO;
>> - }
>> -
>> /* Configure virt-queues for pci */
>> for (i = 0; i < vdev->nr_vqs; i++) {
>> + uint16_t vq_size;
>> + uint16_t vq_notify;
>> VqInfo info = {
>> .queue = (unsigned long long) virtio_get_ring_area(i),
>> .align = KVM_S390_VIRTIO_RING_ALIGN,
>> .index = i,
>> - .num = vq_size,
>> + .num = 0,
>> };
>>
>> vr = &vdev->vrings[i];
>> - vring_init(vr, &info);
>>
>> - if (vpci_set_selected_vq(vr->id)) {
>> + if (vpci_set_selected_vq(i)) {
>> puts("Failed to set selected virt-queue");
>> return -EIO;
>> }
>>
>> + if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
> Small nit: c_cap.off + VPCI_C_OFFSET_Q_SIZE
Ah, this is actually not just a small nit! Although the common capabilities
offset is 0 in the current QEMU implementation there is nothing
preventing it
from being a different offset in the future. So it must be included,
otherwise
a non-zero value would break it. Good catch.
>
>> + puts("Failed to read virt-queue configuration");
>> + return -EIO;
>> + }
>> +
>> + info.num = vq_size;
>> +
>> + if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
>> + puts("Failed to read virt-queue configuration");
>> + return -EIO;
>> + }
> Since the notification offset is now read per queue, should we remove
> the same read in virtio_pci_read_pci_cap_config() as well as the global
> q_notify_offset variable?
>
> if (rc || vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar,
> &q_notify_offset))
Yes, that should be removed. I will take care of it for V2. Thanks.
>
>> +
>> + vr->pci_notify = vq_notify;
>> + vring_init(vr, &info);
>> +
>> rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
>> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
>> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
>> diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
>> index 90d07cb9a7..993fc285ac 100644
>> --- a/pc-bios/s390-ccw/virtio-pci.h
>> +++ b/pc-bios/s390-ccw/virtio-pci.h
>> @@ -62,9 +62,10 @@ struct VirtioPciCap {
>> };
>> typedef struct VirtioPciCap VirtioPciCap;
>>
>> +int vpci_set_selected_vq(uint16_t queue_num);
>> void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
>> int virtio_pci_reset(VDev *vdev);
>> -long virtio_pci_notify(int vq_id);
>> +long virtio_pci_notify(VRing *vr);
>> int virtio_pci_setup(VDev *vdev);
>> int virtio_pci_setup_device(void);
>>
>> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
>> index 30e6b2bc16..00850acc2f 100644
>> --- a/pc-bios/s390-ccw/virtio.c
>> +++ b/pc-bios/s390-ccw/virtio.c
>> @@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
>> vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
>> break;
>> case S390_IPL_TYPE_PCI:
>> - vr->cookie = virtio_pci_notify(vr->id);
>> + vr->cookie = virtio_pci_notify(vr);
>> + break;
>> default:
>> return 1;
>> }
>> @@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
>> void vring_send_buf(VRing *vr, void *p, int len, int flags)
>> {
>> if (!be_ipl()) {
>> + vpci_set_selected_vq(vr->id);
>> vr->avail->idx = bswap16(vr->avail->idx);
>> }
>>
>> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
>> index d32a4830ca..75ae5bdbc2 100644
>> --- a/pc-bios/s390-ccw/virtio.h
>> +++ b/pc-bios/s390-ccw/virtio.h
>> @@ -107,6 +107,7 @@ struct VRing {
>> VRingUsed *used;
>> long cookie;
>> int id;
>> + uint16_t pci_notify;
>> };
>> typedef struct VRing VRing;
>>
Regards,
Jared Rossi
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations
2026-05-04 22:16 ` [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations jrossi
2026-05-06 18:20 ` Zhuoying Cai
@ 2026-05-08 17:23 ` Eric Farman
2026-05-12 16:21 ` Jared Rossi
1 sibling, 1 reply; 15+ messages in thread
From: Eric Farman @ 2026-05-08 17:23 UTC (permalink / raw)
To: jrossi, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
>
> The initial support for virtio-blk-pci IPL devices used a single virt-queue, but
> other device types require multiple queues, and for PCI device types this also
> requires a per-queue notification offset.
>
> Add a PCI notify field to the VRing struct so that each queue has a unique
> notify offset. Also re-select the target queue before writing buffers to
> ensure the proper queue is active.
Why is this patch 2/5, when the series is n/6?
>
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> ---
> pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
> pc-bios/s390-ccw/virtio-pci.h | 3 ++-
> pc-bios/s390-ccw/virtio.c | 4 +++-
> pc-bios/s390-ccw/virtio.h | 1 +
> 4 files changed, 29 insertions(+), 15 deletions(-)
>
> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
> index 53bdb52e76..736869f4f5 100644
> --- a/pc-bios/s390-ccw/virtio-pci.c
> +++ b/pc-bios/s390-ccw/virtio-pci.c
> @@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
> return 0;
> }
>
> -long virtio_pci_notify(int vq_id)
> +long virtio_pci_notify(VRing *vr)
> {
> - uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
> - return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
> + uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
> + return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
You no longer need the q_notify_offset variable nor the read into it.
(Ah, Joy already pointed this out; nice!)
> }
>
> /*
> @@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
> return 0;
> }
>
> -static int vpci_set_selected_vq(uint16_t queue_num)
> +int vpci_set_selected_vq(uint16_t queue_num)
> {
> return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
> }
> @@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
> VRing *vr;
> int rc;
> uint8_t status;
> - uint16_t vq_size;
> int i = 0;
>
> vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
> @@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
> return -EIO;
> }
>
> - if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
> - puts("Failed to read virt-queue configuration");
> - return -EIO;
> - }
> -
> /* Configure virt-queues for pci */
> for (i = 0; i < vdev->nr_vqs; i++) {
> + uint16_t vq_size;
> + uint16_t vq_notify;
> VqInfo info = {
> .queue = (unsigned long long) virtio_get_ring_area(i),
> .align = KVM_S390_VIRTIO_RING_ALIGN,
> .index = i,
> - .num = vq_size,
> + .num = 0,
> };
>
> vr = &vdev->vrings[i];
> - vring_init(vr, &info);
>
> - if (vpci_set_selected_vq(vr->id)) {
> + if (vpci_set_selected_vq(i)) {
> puts("Failed to set selected virt-queue");
> return -EIO;
> }
>
> + if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
> + puts("Failed to read virt-queue configuration");
> + return -EIO;
> + }
> +
> + info.num = vq_size;
> +
> + if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
> + puts("Failed to read virt-queue configuration");
> + return -EIO;
> + }
For either of these error exits, do you need an identifier logged as to -which- virtqueue failed, as
you're in a loop?
> +
> + vr->pci_notify = vq_notify;
> + vring_init(vr, &info);
> +
> rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
> diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
> index 90d07cb9a7..993fc285ac 100644
> --- a/pc-bios/s390-ccw/virtio-pci.h
> +++ b/pc-bios/s390-ccw/virtio-pci.h
> @@ -62,9 +62,10 @@ struct VirtioPciCap {
> };
> typedef struct VirtioPciCap VirtioPciCap;
>
> +int vpci_set_selected_vq(uint16_t queue_num);
> void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
> int virtio_pci_reset(VDev *vdev);
> -long virtio_pci_notify(int vq_id);
> +long virtio_pci_notify(VRing *vr);
> int virtio_pci_setup(VDev *vdev);
> int virtio_pci_setup_device(void);
>
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> index 30e6b2bc16..00850acc2f 100644
> --- a/pc-bios/s390-ccw/virtio.c
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
> vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
> break;
> case S390_IPL_TYPE_PCI:
> - vr->cookie = virtio_pci_notify(vr->id);
> + vr->cookie = virtio_pci_notify(vr);
> + break;
> default:
> return 1;
> }
> @@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
> void vring_send_buf(VRing *vr, void *p, int len, int flags)
> {
> if (!be_ipl()) {
> + vpci_set_selected_vq(vr->id);
> vr->avail->idx = bswap16(vr->avail->idx);
> }
>
> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
> index d32a4830ca..75ae5bdbc2 100644
> --- a/pc-bios/s390-ccw/virtio.h
> +++ b/pc-bios/s390-ccw/virtio.h
> @@ -107,6 +107,7 @@ struct VRing {
> VRingUsed *used;
> long cookie;
> int id;
> + uint16_t pci_notify;
> };
> typedef struct VRing VRing;
>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations
2026-05-08 17:23 ` Eric Farman
@ 2026-05-12 16:21 ` Jared Rossi
0 siblings, 0 replies; 15+ messages in thread
From: Jared Rossi @ 2026-05-12 16:21 UTC (permalink / raw)
To: Eric Farman, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On 5/8/26 1:23 PM, Eric Farman wrote:
> On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
>> From: Jared Rossi <jrossi@linux.ibm.com>
>>
>> The initial support for virtio-blk-pci IPL devices used a single virt-queue, but
>> other device types require multiple queues, and for PCI device types this also
>> requires a per-queue notification offset.
>>
>> Add a PCI notify field to the VRing struct so that each queue has a unique
>> notify offset. Also re-select the target queue before writing buffers to
>> ensure the proper queue is active.
> Why is this patch 2/5, when the series is n/6?
The short answer is I goofed it up. The contents of the patch are as
intended.
It should be 2/6.
>
>> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
>> ---
>> pc-bios/s390-ccw/virtio-pci.c | 36 ++++++++++++++++++++++-------------
>> pc-bios/s390-ccw/virtio-pci.h | 3 ++-
>> pc-bios/s390-ccw/virtio.c | 4 +++-
>> pc-bios/s390-ccw/virtio.h | 1 +
>> 4 files changed, 29 insertions(+), 15 deletions(-)
>>
>> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
>> index 53bdb52e76..736869f4f5 100644
>> --- a/pc-bios/s390-ccw/virtio-pci.c
>> +++ b/pc-bios/s390-ccw/virtio-pci.c
>> @@ -74,10 +74,10 @@ int virtio_pci_reset(VDev *vdev)
>> return 0;
>> }
>>
>> -long virtio_pci_notify(int vq_id)
>> +long virtio_pci_notify(VRing *vr)
>> {
>> - uint32_t offset = n_cap.off + notify_mult * q_notify_offset;
>> - return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vq_id);
>> + uint32_t offset = n_cap.off + notify_mult * vr->pci_notify;
>> + return vpci_bswap16_write(offset, n_cap.bar, (uint16_t) vr->id);
> You no longer need the q_notify_offset variable nor the read into it.
> (Ah, Joy already pointed this out; nice!)
>
>> }
>>
>> /*
>> @@ -166,7 +166,7 @@ int vpci_read_flex(uint64_t offset, uint8_t pcias, void *buf, int len)
>> return 0;
>> }
>>
>> -static int vpci_set_selected_vq(uint16_t queue_num)
>> +int vpci_set_selected_vq(uint16_t queue_num)
>> {
>> return vpci_bswap16_write(c_cap.off + VPCI_C_OFFSET_Q_SELECT, c_cap.bar, queue_num);
>> }
>> @@ -332,7 +332,6 @@ int virtio_pci_setup(VDev *vdev)
>> VRing *vr;
>> int rc;
>> uint8_t status;
>> - uint16_t vq_size;
>> int i = 0;
>>
>> vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
>> @@ -380,28 +379,39 @@ int virtio_pci_setup(VDev *vdev)
>> return -EIO;
>> }
>>
>> - if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
>> - puts("Failed to read virt-queue configuration");
>> - return -EIO;
>> - }
>> -
>> /* Configure virt-queues for pci */
>> for (i = 0; i < vdev->nr_vqs; i++) {
>> + uint16_t vq_size;
>> + uint16_t vq_notify;
>> VqInfo info = {
>> .queue = (unsigned long long) virtio_get_ring_area(i),
>> .align = KVM_S390_VIRTIO_RING_ALIGN,
>> .index = i,
>> - .num = vq_size,
>> + .num = 0,
>> };
>>
>> vr = &vdev->vrings[i];
>> - vring_init(vr, &info);
>>
>> - if (vpci_set_selected_vq(vr->id)) {
>> + if (vpci_set_selected_vq(i)) {
>> puts("Failed to set selected virt-queue");
>> return -EIO;
>> }
>>
>> + if (vpci_read_bswap16(VPCI_C_OFFSET_Q_SIZE, c_cap.bar, &vq_size)) {
>> + puts("Failed to read virt-queue configuration");
>> + return -EIO;
>> + }
>> +
>> + info.num = vq_size;
>> +
>> + if (vpci_read_bswap16(c_cap.off + VPCI_C_OFFSET_Q_NOFF, c_cap.bar, &vq_notify)) {
>> + puts("Failed to read virt-queue configuration");
>> + return -EIO;
>> + }
> For either of these error exits, do you need an identifier logged as to -which- virtqueue failed, as
> you're in a loop?
Yes, that would certainly be useful information to have. I'll add it.
>
>> +
>> + vr->pci_notify = vq_notify;
>> + vring_init(vr, &info);
>> +
>> rc = set_pci_vq_addr(VPCI_C_OFFSET_Q_DESCLO, vr->desc);
>> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_AVAILLO, vr->avail);
>> rc |= set_pci_vq_addr(VPCI_C_OFFSET_Q_USEDLO, vr->used);
>> diff --git a/pc-bios/s390-ccw/virtio-pci.h b/pc-bios/s390-ccw/virtio-pci.h
>> index 90d07cb9a7..993fc285ac 100644
>> --- a/pc-bios/s390-ccw/virtio-pci.h
>> +++ b/pc-bios/s390-ccw/virtio-pci.h
>> @@ -62,9 +62,10 @@ struct VirtioPciCap {
>> };
>> typedef struct VirtioPciCap VirtioPciCap;
>>
>> +int vpci_set_selected_vq(uint16_t queue_num);
>> void virtio_pci_id2type(VDev *vdev, uint16_t device_id);
>> int virtio_pci_reset(VDev *vdev);
>> -long virtio_pci_notify(int vq_id);
>> +long virtio_pci_notify(VRing *vr);
>> int virtio_pci_setup(VDev *vdev);
>> int virtio_pci_setup_device(void);
>>
>> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
>> index 30e6b2bc16..00850acc2f 100644
>> --- a/pc-bios/s390-ccw/virtio.c
>> +++ b/pc-bios/s390-ccw/virtio.c
>> @@ -114,7 +114,8 @@ bool vring_notify(VRing *vr)
>> vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
>> break;
>> case S390_IPL_TYPE_PCI:
>> - vr->cookie = virtio_pci_notify(vr->id);
>> + vr->cookie = virtio_pci_notify(vr);
>> + break;
>> default:
>> return 1;
>> }
>> @@ -154,6 +155,7 @@ static void vr_bswap_descriptor(VRingDesc *desc)
>> void vring_send_buf(VRing *vr, void *p, int len, int flags)
>> {
>> if (!be_ipl()) {
>> + vpci_set_selected_vq(vr->id);
>> vr->avail->idx = bswap16(vr->avail->idx);
>> }
>>
>> diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
>> index d32a4830ca..75ae5bdbc2 100644
>> --- a/pc-bios/s390-ccw/virtio.h
>> +++ b/pc-bios/s390-ccw/virtio.h
>> @@ -107,6 +107,7 @@ struct VRing {
>> VRingUsed *used;
>> long cookie;
>> int id;
>> + uint16_t pci_notify;
>> };
>> typedef struct VRing VRing;
>>
Thank you for the review comments.
Regards,
Jared Rossi
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/6] pc-bios/s390-ccw: Rename Virtio CCW run function for generic use
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
2026-05-04 22:16 ` [PATCH 1/6] s390x: Rename SCSI IPL type to indicate CCW bus jrossi
2026-05-04 22:16 ` [PATCH 2/5] pc-bios/s390-ccw: Add per-queue notification offset for multi-queue virtio configurations jrossi
@ 2026-05-04 22:16 ` jrossi
2026-05-08 17:26 ` Eric Farman
2026-05-04 22:16 ` [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type jrossi
` (2 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
The same function can be used for issuing both CCW and PCI virtio commands, so
remove CCW from the existing name. Additionally, move the function out of the
CCW specific file and make it static.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
pc-bios/s390-ccw/virtio-ccw.c | 17 -----------------
pc-bios/s390-ccw/virtio-ccw.h | 1 -
pc-bios/s390-ccw/virtio.c | 19 ++++++++++++++++++-
3 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/pc-bios/s390-ccw/virtio-ccw.c b/pc-bios/s390-ccw/virtio-ccw.c
index 5cb2158ed2..ea5dbc2857 100644
--- a/pc-bios/s390-ccw/virtio-ccw.c
+++ b/pc-bios/s390-ccw/virtio-ccw.c
@@ -107,23 +107,6 @@ long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie)
vq_idx, cookie);
}
-int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd)
-{
- VRing *vr = &vdev->vrings[vqid];
- int i = 0;
-
- do {
- vring_send_buf(vr, cmd[i].data, cmd[i].size,
- cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
- } while (cmd[i++].flags & VRING_DESC_F_NEXT);
-
- vring_wait_reply();
- if (drain_irqs()) {
- return -1;
- }
- return 0;
-}
-
int virtio_ccw_reset(VDev *vdev)
{
return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
diff --git a/pc-bios/s390-ccw/virtio-ccw.h b/pc-bios/s390-ccw/virtio-ccw.h
index a506767eaa..43d21906e5 100644
--- a/pc-bios/s390-ccw/virtio-ccw.h
+++ b/pc-bios/s390-ccw/virtio-ccw.h
@@ -16,7 +16,6 @@ extern SubChannelId blk_schid;
/* virtio-ccw.c */
int drain_irqs_ccw(SubChannelId schid);
bool virtio_ccw_is_supported(VDev *vdev);
-int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd);
long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie);
int virtio_ccw_setup(VDev *vdev);
int virtio_ccw_reset(VDev *vdev);
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 00850acc2f..79dccdcbfc 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -69,12 +69,29 @@ int drain_irqs(void)
}
}
+static int virtio_do_run(VDev *vdev, int vqid, VirtioCmd *cmd)
+{
+ VRing *vr = &vdev->vrings[vqid];
+ int i = 0;
+
+ do {
+ vring_send_buf(vr, cmd[i].data, cmd[i].size,
+ cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
+ } while (cmd[i++].flags & VRING_DESC_F_NEXT);
+
+ vring_wait_reply();
+ if (drain_irqs()) {
+ return -1;
+ }
+ return 0;
+}
+
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
{
switch (vdev->ipl_type) {
case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
- return virtio_ccw_run(vdev, vqid, cmd);
+ return virtio_do_run(vdev, vqid, cmd);
default:
return -1;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH 3/6] pc-bios/s390-ccw: Rename Virtio CCW run function for generic use
2026-05-04 22:16 ` [PATCH 3/6] pc-bios/s390-ccw: Rename Virtio CCW run function for generic use jrossi
@ 2026-05-08 17:26 ` Eric Farman
0 siblings, 0 replies; 15+ messages in thread
From: Eric Farman @ 2026-05-08 17:26 UTC (permalink / raw)
To: jrossi, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
>
> The same function can be used for issuing both CCW and PCI virtio commands, so
> remove CCW from the existing name. Additionally, move the function out of the
> CCW specific file and make it static.
>
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> ---
> pc-bios/s390-ccw/virtio-ccw.c | 17 -----------------
> pc-bios/s390-ccw/virtio-ccw.h | 1 -
> pc-bios/s390-ccw/virtio.c | 19 ++++++++++++++++++-
> 3 files changed, 18 insertions(+), 19 deletions(-)
Reviewed-by: Eric Farman <farman@linux.ibm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
` (2 preceding siblings ...)
2026-05-04 22:16 ` [PATCH 3/6] pc-bios/s390-ccw: Rename Virtio CCW run function for generic use jrossi
@ 2026-05-04 22:16 ` jrossi
2026-05-09 1:16 ` Eric Farman
2026-05-04 22:16 ` [PATCH 5/6] s390x: Enable IPL from Virtio PCI SCSI devices jrossi
2026-05-04 22:16 ` [PATCH 6/6] tests/qtest: Add s390x PCI SCSI fallback test to cdrom-test.c jrossi
5 siblings, 1 reply; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
Define a new IPLB format for SCSI PCI devices and add cases to handle it.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
include/hw/s390x/ipl/qipl.h | 15 +++++++++++++++
pc-bios/s390-ccw/main.c | 11 ++++++++++-
pc-bios/s390-ccw/virtio-pci.c | 29 +++++++++++++++++++++++++++++
pc-bios/s390-ccw/virtio-scsi.c | 14 +++++++++++++-
pc-bios/s390-ccw/virtio.c | 5 +++++
5 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 67db54c964..951c5e2d8e 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -25,6 +25,7 @@ enum S390IplType {
S390_IPL_TYPE_CCW = 0x02,
S390_IPL_TYPE_PCI = 0x04,
S390_IPL_TYPE_PV = 0x05,
+ S390_IPL_TYPE_PCI_SCSI = 0xfe,
S390_IPL_TYPE_CCW_SCSI = 0xff
};
typedef enum S390IplType S390IplType;
@@ -117,6 +118,19 @@ struct IplBlockPci {
} QEMU_PACKED;
typedef struct IplBlockPci IplBlockPci;
+struct IplBlockPciScsi {
+ uint32_t lun;
+ uint16_t target;
+ uint16_t channel;
+ uint8_t reserved0[74];
+ uint8_t opt;
+ uint8_t reserved1[3];
+ uint32_t fid;
+ uint8_t ssid;
+ uint16_t devno;
+} QEMU_PACKED;
+typedef struct IplBlockPciScsi IplBlockPciScsi;
+
union IplParameterBlock {
struct {
uint32_t len;
@@ -133,6 +147,7 @@ union IplParameterBlock {
IPLBlockPV pv;
IplBlockCcwScsi ccw_scsi;
IplBlockPci pci;
+ IplBlockPciScsi pci_scsi;
};
} QEMU_PACKED;
struct {
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 1a9579beab..b2bc35962a 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -257,7 +257,15 @@ static bool find_boot_device(void)
blk_schid.ssid = iplb.ccw_scsi.ssid & 0x3;
found = find_subch(iplb.ccw_scsi.devno);
break;
+ case S390_IPL_TYPE_PCI_SCSI:
+ vdev->scsi_device_selected = true;
+ vdev->selected_scsi_device.channel = iplb.pci_scsi.channel;
+ vdev->selected_scsi_device.target = iplb.pci_scsi.target;
+ vdev->selected_scsi_device.lun = iplb.pci_scsi.lun;
+ found = find_fid(iplb.pci_scsi.fid);
+ break;
case S390_IPL_TYPE_PCI:
+ vdev->scsi_device_selected = false;
found = find_fid(iplb.pci.fid);
break;
default:
@@ -318,13 +326,13 @@ static void ipl_pci_device(void)
{
VDev *vdev = virtio_get_device();
vdev->is_cdrom = false;
- vdev->scsi_device_selected = false;
if (virtio_pci_setup_device()) {
return;
}
switch (vdev->dev_type) {
+ case VIRTIO_ID_SCSI:
case VIRTIO_ID_BLOCK:
if (virtio_setup() == 0) {
zipl_load(); /* only return on error */
@@ -343,6 +351,7 @@ static void ipl_boot_device(void)
case S390_IPL_TYPE_CCW:
ipl_ccw_device();
break;
+ case S390_IPL_TYPE_PCI_SCSI:
case S390_IPL_TYPE_PCI:
ipl_pci_device();
break;
diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
index 736869f4f5..01a1401ef2 100644
--- a/pc-bios/s390-ccw/virtio-pci.c
+++ b/pc-bios/s390-ccw/virtio-pci.c
@@ -53,6 +53,10 @@ void virtio_pci_id2type(VDev *vdev, uint16_t device_id)
case 0x1001:
vdev->dev_type = VIRTIO_ID_BLOCK;
break;
+ case 0x1048:
+ case 0x1004:
+ vdev->dev_type = VIRTIO_ID_SCSI;
+ break;
default:
vdev->dev_type = 0;
}
@@ -200,6 +204,26 @@ static int virtio_pci_get_blk_config(void)
return rc;
}
+static int virtio_pci_get_scsi_config(void)
+{
+ VirtioScsiConfig *cfg = &virtio_get_device()->config.scsi;
+ int rc = vpci_read_flex(d_cap.off, d_cap.bar, cfg, sizeof(VirtioScsiConfig));
+
+ /* all fields of scsi config must be byte swapped */
+ cfg->num_queues = bswap32(cfg->num_queues);
+ cfg->seg_max = bswap32(cfg->seg_max);
+ cfg->max_sectors = bswap32(cfg->max_sectors);
+ cfg->cmd_per_lun = bswap32(cfg->cmd_per_lun);
+ cfg->event_info_size = bswap32(cfg->event_info_size);
+ cfg->sense_size = bswap32(cfg->sense_size);
+ cfg->cdb_size = bswap32(cfg->cdb_size);
+ cfg->max_channel = bswap16(cfg->max_channel);
+ cfg->max_target = bswap16(cfg->max_target);
+ cfg->max_lun = bswap32(cfg->max_lun);
+
+ return rc;
+}
+
static int virtio_pci_negotiate(void)
{
int i, rc;
@@ -367,6 +391,11 @@ int virtio_pci_setup(VDev *vdev)
vdev->cmd_vr_idx = 0;
virtio_pci_get_blk_config();
break;
+ case VIRTIO_ID_SCSI:
+ vdev->nr_vqs = 3;
+ vdev->cmd_vr_idx = 2;
+ virtio_pci_get_scsi_config();
+ break;
default:
puts("Unsupported virtio device");
return -ENODEV;
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index 9ea00c6fe6..09d2caa879 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -16,6 +16,7 @@
#include "scsi.h"
#include "virtio-scsi.h"
#include "virtio-ccw.h"
+#include "virtio-pci.h"
#include "s390-time.h"
#include "helper.h"
@@ -479,7 +480,18 @@ static int virtio_scsi_setup(VDev *vdev)
int virtio_scsi_setup_device(VDev *vdev)
{
- virtio_ccw_setup(vdev);
+ switch (vdev->ipl_type) {
+ case S390_IPL_TYPE_CCW_SCSI:
+ case S390_IPL_TYPE_CCW:
+ virtio_ccw_setup(vdev);
+ break;
+ case S390_IPL_TYPE_PCI_SCSI:
+ case S390_IPL_TYPE_PCI:
+ virtio_pci_setup(vdev);
+ break;
+ default:
+ return 1;
+ }
if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
puts("Config: sense size mismatch");
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 79dccdcbfc..598768d12b 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -89,6 +89,8 @@ static int virtio_do_run(VDev *vdev, int vqid, VirtioCmd *cmd)
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
{
switch (vdev->ipl_type) {
+ case S390_IPL_TYPE_PCI_SCSI:
+ case S390_IPL_TYPE_PCI:
case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_do_run(vdev, vqid, cmd);
@@ -130,6 +132,7 @@ bool vring_notify(VRing *vr)
case S390_IPL_TYPE_CCW:
vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
break;
+ case S390_IPL_TYPE_PCI_SCSI:
case S390_IPL_TYPE_PCI:
vr->cookie = virtio_pci_notify(vr);
break;
@@ -150,6 +153,7 @@ bool be_ipl(void)
case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return true;
+ case S390_IPL_TYPE_PCI_SCSI:
case S390_IPL_TYPE_PCI:
return false;
default:
@@ -252,6 +256,7 @@ int virtio_reset(VDev *vdev)
case S390_IPL_TYPE_CCW_SCSI:
case S390_IPL_TYPE_CCW:
return virtio_ccw_reset(vdev);
+ case S390_IPL_TYPE_PCI_SCSI:
case S390_IPL_TYPE_PCI:
return virtio_pci_reset(vdev);
default:
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type
2026-05-04 22:16 ` [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type jrossi
@ 2026-05-09 1:16 ` Eric Farman
2026-05-12 16:13 ` Jared Rossi
0 siblings, 1 reply; 15+ messages in thread
From: Eric Farman @ 2026-05-09 1:16 UTC (permalink / raw)
To: jrossi, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
>
> Define a new IPLB format for SCSI PCI devices and add cases to handle it.
>
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> ---
> include/hw/s390x/ipl/qipl.h | 15 +++++++++++++++
> pc-bios/s390-ccw/main.c | 11 ++++++++++-
> pc-bios/s390-ccw/virtio-pci.c | 29 +++++++++++++++++++++++++++++
> pc-bios/s390-ccw/virtio-scsi.c | 14 +++++++++++++-
> pc-bios/s390-ccw/virtio.c | 5 +++++
> 5 files changed, 72 insertions(+), 2 deletions(-)
>
> diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
> index 67db54c964..951c5e2d8e 100644
> --- a/include/hw/s390x/ipl/qipl.h
> +++ b/include/hw/s390x/ipl/qipl.h
> @@ -25,6 +25,7 @@ enum S390IplType {
> S390_IPL_TYPE_CCW = 0x02,
> S390_IPL_TYPE_PCI = 0x04,
> S390_IPL_TYPE_PV = 0x05,
> + S390_IPL_TYPE_PCI_SCSI = 0xfe,
> S390_IPL_TYPE_CCW_SCSI = 0xff
> };
> typedef enum S390IplType S390IplType;
> @@ -117,6 +118,19 @@ struct IplBlockPci {
> } QEMU_PACKED;
> typedef struct IplBlockPci IplBlockPci;
>
> +struct IplBlockPciScsi {
> + uint32_t lun;
> + uint16_t target;
> + uint16_t channel;
> + uint8_t reserved0[74];
> + uint8_t opt;
> + uint8_t reserved1[3];
> + uint32_t fid;
> + uint8_t ssid;
> + uint16_t devno;
> +} QEMU_PACKED;
> +typedef struct IplBlockPciScsi IplBlockPciScsi;
Now that I get to the point where I see why you renamed the ...QemuScsi struct in patch one, I'm
struggling.
This combines the PCI stuff in IplBlockPci, with the CCW (!) and SCSI stuff in IplBlockCcwScsi (nee
IplBlockQemuScsi). Some of the stuff (ssid, devno) isn't needed for PCI, and I find myself wondering
what the "right" struct should look like...
Can we add the PCI stuff to a (generalized) struct that's just "IplBlockScsi" and have fields that
are specific to -ccw or -pci? That's basically what IplBlockPciScsi is, even though it's not used
that way. Or is it better that there's overlap between Ccw/CcwScsi (e.g., offsetof(Ccw.ssid) ==
offsetof(CcwScsi.ssid)) and Pci/PciScsi? If the latter, there's quite a bit of difference in their
layouts, e.g., the location of the opt and fid fields. That worries me...
> +
> union IplParameterBlock {
> struct {
> uint32_t len;
> @@ -133,6 +147,7 @@ union IplParameterBlock {
> IPLBlockPV pv;
> IplBlockCcwScsi ccw_scsi;
> IplBlockPci pci;
> + IplBlockPciScsi pci_scsi;
> };
> } QEMU_PACKED;
> struct {
> diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
> index 1a9579beab..b2bc35962a 100644
> --- a/pc-bios/s390-ccw/main.c
> +++ b/pc-bios/s390-ccw/main.c
> @@ -257,7 +257,15 @@ static bool find_boot_device(void)
> blk_schid.ssid = iplb.ccw_scsi.ssid & 0x3;
> found = find_subch(iplb.ccw_scsi.devno);
> break;
> + case S390_IPL_TYPE_PCI_SCSI:
> + vdev->scsi_device_selected = true;
> + vdev->selected_scsi_device.channel = iplb.pci_scsi.channel;
> + vdev->selected_scsi_device.target = iplb.pci_scsi.target;
> + vdev->selected_scsi_device.lun = iplb.pci_scsi.lun;
> + found = find_fid(iplb.pci_scsi.fid);
...because of this. I don't see iplb.pci_scsi.fid set anywhere. Patch 5 sets ipl.pci.fid, but that's
at a different offset within the respective structs in that union.
> + break;
> case S390_IPL_TYPE_PCI:
> + vdev->scsi_device_selected = false;
> found = find_fid(iplb.pci.fid);
> break;
> default:
> @@ -318,13 +326,13 @@ static void ipl_pci_device(void)
> {
> VDev *vdev = virtio_get_device();
> vdev->is_cdrom = false;
> - vdev->scsi_device_selected = false;
>
> if (virtio_pci_setup_device()) {
> return;
> }
>
> switch (vdev->dev_type) {
> + case VIRTIO_ID_SCSI:
> case VIRTIO_ID_BLOCK:
> if (virtio_setup() == 0) {
> zipl_load(); /* only return on error */
> @@ -343,6 +351,7 @@ static void ipl_boot_device(void)
> case S390_IPL_TYPE_CCW:
> ipl_ccw_device();
> break;
> + case S390_IPL_TYPE_PCI_SCSI:
> case S390_IPL_TYPE_PCI:
> ipl_pci_device();
> break;
> diff --git a/pc-bios/s390-ccw/virtio-pci.c b/pc-bios/s390-ccw/virtio-pci.c
> index 736869f4f5..01a1401ef2 100644
> --- a/pc-bios/s390-ccw/virtio-pci.c
> +++ b/pc-bios/s390-ccw/virtio-pci.c
> @@ -53,6 +53,10 @@ void virtio_pci_id2type(VDev *vdev, uint16_t device_id)
> case 0x1001:
> vdev->dev_type = VIRTIO_ID_BLOCK;
> break;
> + case 0x1048:
> + case 0x1004:
> + vdev->dev_type = VIRTIO_ID_SCSI;
> + break;
> default:
> vdev->dev_type = 0;
> }
> @@ -200,6 +204,26 @@ static int virtio_pci_get_blk_config(void)
> return rc;
> }
>
> +static int virtio_pci_get_scsi_config(void)
> +{
> + VirtioScsiConfig *cfg = &virtio_get_device()->config.scsi;
> + int rc = vpci_read_flex(d_cap.off, d_cap.bar, cfg, sizeof(VirtioScsiConfig));
> +
> + /* all fields of scsi config must be byte swapped */
> + cfg->num_queues = bswap32(cfg->num_queues);
> + cfg->seg_max = bswap32(cfg->seg_max);
> + cfg->max_sectors = bswap32(cfg->max_sectors);
> + cfg->cmd_per_lun = bswap32(cfg->cmd_per_lun);
> + cfg->event_info_size = bswap32(cfg->event_info_size);
> + cfg->sense_size = bswap32(cfg->sense_size);
> + cfg->cdb_size = bswap32(cfg->cdb_size);
> + cfg->max_channel = bswap16(cfg->max_channel);
> + cfg->max_target = bswap16(cfg->max_target);
> + cfg->max_lun = bswap32(cfg->max_lun);
> +
> + return rc;
> +}
> +
> static int virtio_pci_negotiate(void)
> {
> int i, rc;
> @@ -367,6 +391,11 @@ int virtio_pci_setup(VDev *vdev)
> vdev->cmd_vr_idx = 0;
> virtio_pci_get_blk_config();
> break;
> + case VIRTIO_ID_SCSI:
> + vdev->nr_vqs = 3;
> + vdev->cmd_vr_idx = 2;
> + virtio_pci_get_scsi_config();
> + break;
> default:
> puts("Unsupported virtio device");
> return -ENODEV;
> diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
> index 9ea00c6fe6..09d2caa879 100644
> --- a/pc-bios/s390-ccw/virtio-scsi.c
> +++ b/pc-bios/s390-ccw/virtio-scsi.c
> @@ -16,6 +16,7 @@
> #include "scsi.h"
> #include "virtio-scsi.h"
> #include "virtio-ccw.h"
> +#include "virtio-pci.h"
> #include "s390-time.h"
> #include "helper.h"
>
> @@ -479,7 +480,18 @@ static int virtio_scsi_setup(VDev *vdev)
>
> int virtio_scsi_setup_device(VDev *vdev)
> {
> - virtio_ccw_setup(vdev);
> + switch (vdev->ipl_type) {
> + case S390_IPL_TYPE_CCW_SCSI:
> + case S390_IPL_TYPE_CCW:
> + virtio_ccw_setup(vdev);
> + break;
> + case S390_IPL_TYPE_PCI_SCSI:
> + case S390_IPL_TYPE_PCI:
> + virtio_pci_setup(vdev);
> + break;
> + default:
> + return 1;
> + }
>
> if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
> puts("Config: sense size mismatch");
> diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
> index 79dccdcbfc..598768d12b 100644
> --- a/pc-bios/s390-ccw/virtio.c
> +++ b/pc-bios/s390-ccw/virtio.c
> @@ -89,6 +89,8 @@ static int virtio_do_run(VDev *vdev, int vqid, VirtioCmd *cmd)
> int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
> {
> switch (vdev->ipl_type) {
> + case S390_IPL_TYPE_PCI_SCSI:
> + case S390_IPL_TYPE_PCI:
> case S390_IPL_TYPE_CCW_SCSI:
> case S390_IPL_TYPE_CCW:
> return virtio_do_run(vdev, vqid, cmd);
> @@ -130,6 +132,7 @@ bool vring_notify(VRing *vr)
> case S390_IPL_TYPE_CCW:
> vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
> break;
> + case S390_IPL_TYPE_PCI_SCSI:
> case S390_IPL_TYPE_PCI:
> vr->cookie = virtio_pci_notify(vr);
> break;
> @@ -150,6 +153,7 @@ bool be_ipl(void)
> case S390_IPL_TYPE_CCW_SCSI:
> case S390_IPL_TYPE_CCW:
> return true;
> + case S390_IPL_TYPE_PCI_SCSI:
> case S390_IPL_TYPE_PCI:
> return false;
> default:
> @@ -252,6 +256,7 @@ int virtio_reset(VDev *vdev)
> case S390_IPL_TYPE_CCW_SCSI:
> case S390_IPL_TYPE_CCW:
> return virtio_ccw_reset(vdev);
> + case S390_IPL_TYPE_PCI_SCSI:
> case S390_IPL_TYPE_PCI:
> return virtio_pci_reset(vdev);
> default:
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type
2026-05-09 1:16 ` Eric Farman
@ 2026-05-12 16:13 ` Jared Rossi
0 siblings, 0 replies; 15+ messages in thread
From: Jared Rossi @ 2026-05-12 16:13 UTC (permalink / raw)
To: Eric Farman, qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, mjrosato, zycai
On 5/8/26 9:16 PM, Eric Farman wrote:
> On Mon, 2026-05-04 at 18:16 -0400, jrossi@linux.ibm.com wrote:
>> From: Jared Rossi <jrossi@linux.ibm.com>
>>
>> Define a new IPLB format for SCSI PCI devices and add cases to handle it.
>>
>> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
>> ---
>> include/hw/s390x/ipl/qipl.h | 15 +++++++++++++++
>> pc-bios/s390-ccw/main.c | 11 ++++++++++-
>> pc-bios/s390-ccw/virtio-pci.c | 29 +++++++++++++++++++++++++++++
>> pc-bios/s390-ccw/virtio-scsi.c | 14 +++++++++++++-
>> pc-bios/s390-ccw/virtio.c | 5 +++++
>> 5 files changed, 72 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
>> index 67db54c964..951c5e2d8e 100644
>> --- a/include/hw/s390x/ipl/qipl.h
>> +++ b/include/hw/s390x/ipl/qipl.h
>> @@ -25,6 +25,7 @@ enum S390IplType {
>> S390_IPL_TYPE_CCW = 0x02,
>> S390_IPL_TYPE_PCI = 0x04,
>> S390_IPL_TYPE_PV = 0x05,
>> + S390_IPL_TYPE_PCI_SCSI = 0xfe,
>> S390_IPL_TYPE_CCW_SCSI = 0xff
>> };
>> typedef enum S390IplType S390IplType;
>> @@ -117,6 +118,19 @@ struct IplBlockPci {
>> } QEMU_PACKED;
>> typedef struct IplBlockPci IplBlockPci;
>>
>> +struct IplBlockPciScsi {
>> + uint32_t lun;
>> + uint16_t target;
>> + uint16_t channel;
>> + uint8_t reserved0[74];
>> + uint8_t opt;
>> + uint8_t reserved1[3];
>> + uint32_t fid;
>> + uint8_t ssid;
>> + uint16_t devno;
>> +} QEMU_PACKED;
>> +typedef struct IplBlockPciScsi IplBlockPciScsi;
> Now that I get to the point where I see why you renamed the ...QemuScsi struct in patch one, I'm
> struggling.
>
> This combines the PCI stuff in IplBlockPci, with the CCW (!) and SCSI stuff in IplBlockCcwScsi (nee
> IplBlockQemuScsi). Some of the stuff (ssid, devno) isn't needed for PCI, and I find myself wondering
> what the "right" struct should look like...
The ssid and devno should be removed from the PCI version, it was just an
oversight to leave them there.
> Can we add the PCI stuff to a (generalized) struct that's just "IplBlockScsi" and have fields that
> are specific to -ccw or -pci? That's basically what IplBlockPciScsi is, even though it's not used
> that way.
Yes, it is possible. At first I did not think it was the proper
approach, but
thinking about it again now I can see the benefit. I will reconsider it.
> Or is it better that there's overlap between Ccw/CcwScsi (e.g., offsetof(Ccw.ssid) ==
> offsetof(CcwScsi.ssid)) and Pci/PciScsi? If the latter, there's quite a bit of difference in their
> layouts, e.g., the location of the opt and fid fields. That worries me...
You are correct that the offsets are wrong. At minimum I will fix the
offsets to
match, otherwise I will rework it into a combined IPLB as described above.
Thanks for catching this error.
Regards,
Jared Rossi
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 5/6] s390x: Enable IPL from Virtio PCI SCSI devices
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
` (3 preceding siblings ...)
2026-05-04 22:16 ` [PATCH 4/6] s390x: Introduce PCI SCSI IPLB and boot type jrossi
@ 2026-05-04 22:16 ` jrossi
2026-05-04 22:16 ` [PATCH 6/6] tests/qtest: Add s390x PCI SCSI fallback test to cdrom-test.c jrossi
5 siblings, 0 replies; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
Detect PCI SCSI boot devices and build an IPLB for them.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
hw/s390x/ipl.c | 36 ++++++++++++++++++++++++++++++++++++
target/s390x/diag.c | 3 ++-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 402f5dbd7e..1ed1afe4c4 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -400,6 +400,7 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
}
#define PCI_DEVTYPE_VIRTIO 0x05
+#define PCI_DEVTYPE_SCSI 0x06
static S390PCIBusDevice *s390_get_pci_device(DeviceState *dev_st, int *devtype)
{
@@ -415,6 +416,26 @@ static S390PCIBusDevice *s390_get_pci_device(DeviceState *dev_st, int *devtype)
if (pbdev) {
tmp_dt = PCI_DEVTYPE_VIRTIO;
}
+ } else {
+ SCSIDevice *sd = (SCSIDevice *)
+ object_dynamic_cast(OBJECT(dev_st), TYPE_SCSI_DEVICE);
+ if (sd) {
+ SCSIBus *sbus = scsi_bus_from_device(sd);
+ VirtIODevice *vdev = (VirtIODevice *)
+ object_dynamic_cast(OBJECT(sbus->qbus.parent),
+ TYPE_VIRTIO_DEVICE);
+ if (vdev) {
+ pci_dev = (PCIDevice *)
+ object_dynamic_cast(OBJECT(qdev_get_parent_bus(DEVICE(vdev))->parent),
+ TYPE_PCI_DEVICE);
+ if (pci_dev) {
+ pbdev = s390_pci_find_dev_by_pci(s390_get_phb(), pci_dev);
+ if (pbdev) {
+ tmp_dt = PCI_DEVTYPE_SCSI;
+ }
+ }
+ }
+ }
}
}
if (devtype) {
@@ -523,6 +544,21 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
}
switch (devtype) {
+ case PCI_DEVTYPE_SCSI:
+ sd = SCSI_DEVICE(dev_st);
+ scsi_lp = object_property_get_str(OBJECT(sd), "loadparm", NULL);
+ if (scsi_lp && strlen(scsi_lp) > 0) {
+ lp = scsi_lp;
+ }
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
+ iplb->blk0_len =
+ cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
+ iplb->pbt = S390_IPL_TYPE_PCI_SCSI;
+ iplb->pci_scsi.lun = cpu_to_be32(sd->lun);
+ iplb->pci_scsi.target = cpu_to_be16(sd->id);
+ iplb->len = S390_IPLB_MIN_PCI_LEN;
+ iplb->pci.fid = cpu_to_be32(pbdev->fid);
+ break;
case PCI_DEVTYPE_VIRTIO:
iplb->len = cpu_to_be32(S390_IPLB_MIN_PCI_LEN);
iplb->pbt = S390_IPL_TYPE_PCI;
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 06bdb2bbc8..319a2c9f4c 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -133,7 +133,8 @@ 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) {
- if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_CCW_SCSI) {
+ if (subcode == DIAG308_SET && (iplb->pbt == S390_IPL_TYPE_CCW_SCSI ||
+ iplb->pbt == S390_IPL_TYPE_PCI_SCSI)) {
s390_rebuild_iplb(iplb->devno, iplb);
s390_ipl_update_diag308(iplb);
env->regs[r1 + 1] = DIAG_308_RC_OK;
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH 6/6] tests/qtest: Add s390x PCI SCSI fallback test to cdrom-test.c
2026-05-04 22:16 [PATCH 0/6] s390x: Add support for virtio-scsi-pci boot device jrossi
` (4 preceding siblings ...)
2026-05-04 22:16 ` [PATCH 5/6] s390x: Enable IPL from Virtio PCI SCSI devices jrossi
@ 2026-05-04 22:16 ` jrossi
5 siblings, 0 replies; 15+ messages in thread
From: jrossi @ 2026-05-04 22:16 UTC (permalink / raw)
To: qemu-devel, qemu-s390x, cohuck; +Cc: jjherne, farman, mjrosato, jrossi, zycai
From: Jared Rossi <jrossi@linux.ibm.com>
Add a test to verify that a guest can use a PCI controlled CD as a fallback boot
device after a failed CCW IPL.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
tests/qtest/cdrom-test.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index a65854d2bc..50706b6f84 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -253,6 +253,14 @@ static void add_s390x_tests(void)
"-drive if=none,id=d1,media=cdrom,file=",
test_cdboot);
}
+ if (qtest_has_device("virtio-scsi-pci")) {
+ qtest_add_data_func("cdrom/boot/pci-scsi-fallback-from-blk-ccw",
+ "-device virtio-scsi-pci -device virtio-serial "
+ "-device virtio-blk-ccw,drive=d1,bootindex=1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device scsi-cd,drive=d2,bootindex=2 "
+ "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+ }
}
int main(int argc, char **argv)
--
2.52.0
^ permalink raw reply related [flat|nested] 15+ messages in thread