From: jrossi@linux.ibm.com
To: qemu-devel@nongnu.org, qemu-s390x@nongnu.org, thuth@redhat.com,
mst@redhat.com
Cc: jjherne@linux.ibm.com, alifm@linux.ibm.com, farman@linux.ibm.com,
mjrosato@linux.ibm.com, jrossi@linux.ibm.com,
zycai@linux.ibm.com
Subject: [PATCH 03/10] pc-bios/s390-ccw: Split virtio-ccw and generic virtio
Date: Wed, 10 Dec 2025 15:54:42 -0500 [thread overview]
Message-ID: <20251210205449.2783111-4-jrossi@linux.ibm.com> (raw)
In-Reply-To: <20251210205449.2783111-1-jrossi@linux.ibm.com>
From: Jared Rossi <jrossi@linux.ibm.com>
Separate the CCW specific virtio routines and create generic wrappers for easier
reuse of existing virtio functions with non-CCW devices.
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
---
pc-bios/s390-ccw/s390-ccw.h | 3 -
pc-bios/s390-ccw/virtio-ccw.h | 24 +++
pc-bios/s390-ccw/virtio-scsi.h | 2 +-
pc-bios/s390-ccw/virtio.h | 7 +-
pc-bios/s390-ccw/main.c | 10 +-
pc-bios/s390-ccw/netmain.c | 2 +-
pc-bios/s390-ccw/virtio-blkdev.c | 15 +-
pc-bios/s390-ccw/virtio-ccw.c | 242 +++++++++++++++++++++++++++++++
pc-bios/s390-ccw/virtio-net.c | 5 +-
pc-bios/s390-ccw/virtio-scsi.c | 6 +-
pc-bios/s390-ccw/virtio.c | 237 +++++-------------------------
pc-bios/s390-ccw/Makefile | 3 +-
12 files changed, 334 insertions(+), 222 deletions(-)
create mode 100644 pc-bios/s390-ccw/virtio-ccw.h
create mode 100644 pc-bios/s390-ccw/virtio-ccw.c
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 47ea66bd4d..ccd68ff0a4 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -66,9 +66,6 @@ void sclp_setup(void);
void sclp_get_loadparm_ascii(char *loadparm);
int sclp_read(char *str, size_t count);
-/* virtio.c */
-bool virtio_is_supported(SubChannelId schid);
-
/* bootmap.c */
void zipl_load(void);
diff --git a/pc-bios/s390-ccw/virtio-ccw.h b/pc-bios/s390-ccw/virtio-ccw.h
new file mode 100644
index 0000000000..cdf6a55dc8
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-ccw.h
@@ -0,0 +1,24 @@
+/*
+ * Virtio definitions for CCW devices
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef VIRTIO_CCW_H
+#define VIRTIO_CCW_H
+
+/* main.c */
+extern SubChannelId blk_schid;
+
+/* virtio-ccw.c */
+int drain_irqs_ccw(SubChannelId schid);
+bool virtio_ccw_is_supported(SubChannelId schid);
+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);
+
+#endif
diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h
index c5612e16a2..7a37f8b45a 100644
--- a/pc-bios/s390-ccw/virtio-scsi.h
+++ b/pc-bios/s390-ccw/virtio-scsi.h
@@ -69,6 +69,6 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
int virtio_scsi_read_many(VDev *vdev,
unsigned long sector, void *load_addr, int sec_num);
-int virtio_scsi_setup_device(SubChannelId schid);
+int virtio_scsi_setup_device(void);
#endif /* VIRTIO_SCSI_H */
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index d557a4a90e..e747891a2c 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -109,6 +109,7 @@ struct VRing {
};
typedef struct VRing VRing;
+char *virtio_get_ring_area(void);
/***********************************************
* Virtio block *
@@ -270,8 +271,10 @@ struct VirtioCmd {
};
typedef struct VirtioCmd VirtioCmd;
+void vring_init(VRing *vr, VqInfo *info);
+bool virtio_is_supported(VDev *vdev);
bool vring_notify(VRing *vr);
-int drain_irqs(SubChannelId schid);
+int drain_irqs(VRing *vr);
void vring_send_buf(VRing *vr, void *p, int len, int flags);
int vr_poll(VRing *vr);
int vring_wait_reply(void);
@@ -284,7 +287,7 @@ int virtio_net_init(void *mac_addr);
void virtio_net_deinit(void);
/* virtio-blkdev.c */
-int virtio_blk_setup_device(SubChannelId schid);
+int virtio_blk_setup_device(void);
int virtio_read(unsigned long sector, void *load_addr);
unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long rec_list2,
void *load_addr);
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index fef192c934..e82d60bbb7 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -72,6 +72,7 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
Schib schib;
int r;
+ VDev *vdev = virtio_get_device();
blk_schid.sch_no = sch_no;
r = stsch_err(blk_schid, &schib);
if (r == 3 || r == -EIO) {
@@ -91,7 +92,8 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
* Note: we always have to run virtio_is_supported() here to make
* sure that the vdev.senseid data gets pre-initialized correctly
*/
- is_virtio = virtio_is_supported(blk_schid);
+ vdev->schid = blk_schid;
+ is_virtio = virtio_is_supported(vdev);
/* No specific devno given, just return whether the device is possibly bootable */
if (dev_no < 0) {
@@ -254,10 +256,12 @@ static int virtio_setup(void)
puts("Network boot device detected");
return 0;
case VIRTIO_ID_BLOCK:
- ret = virtio_blk_setup_device(blk_schid);
+ vdev->schid = blk_schid;
+ ret = virtio_blk_setup_device();
break;
case VIRTIO_ID_SCSI:
- ret = virtio_scsi_setup_device(blk_schid);
+ vdev->schid = blk_schid;
+ ret = virtio_scsi_setup_device();
break;
default:
puts("\n! No IPL device available !\n");
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index a9521dff41..651cedf6ef 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -500,7 +500,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
continue;
}
enable_subchannel(net_schid);
- if (!virtio_is_supported(net_schid)) {
+ if (!virtio_is_supported(virtio_get_device())) {
continue;
}
if (virtio_get_device_type() != VIRTIO_ID_NET) {
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index f40a9407c2..87ab9a9513 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -12,6 +12,7 @@
#include "s390-ccw.h"
#include "virtio.h"
#include "virtio-scsi.h"
+#include "virtio-ccw.h"
#define VIRTIO_BLK_F_GEOMETRY (1 << 4)
#define VIRTIO_BLK_F_BLK_SIZE (1 << 6)
@@ -42,7 +43,7 @@ static int virtio_blk_read_many(VDev *vdev, unsigned long sector, void *load_add
/* Now we can tell the host to read */
vring_wait_reply();
- if (drain_irqs(vr->schid)) {
+ if (drain_irqs(vr)) {
/* Well, whatever status is supposed to contain... */
status = 1;
}
@@ -229,15 +230,19 @@ uint64_t virtio_get_blocks(void)
}
}
-int virtio_blk_setup_device(SubChannelId schid)
+int virtio_blk_setup_device(void)
{
VDev *vdev = virtio_get_device();
vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
- vdev->schid = schid;
- virtio_setup_ccw(vdev);
puts("Using virtio-blk.");
- return 0;
+ switch (virtio_get_device()->ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ return virtio_ccw_setup(vdev);
+ }
+
+ return 1;
}
diff --git a/pc-bios/s390-ccw/virtio-ccw.c b/pc-bios/s390-ccw/virtio-ccw.c
new file mode 100644
index 0000000000..e121826625
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-ccw.c
@@ -0,0 +1,242 @@
+/*
+ * Virtio functionality for CCW devices
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ * Copyright 2025 IBM Corp. Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include <string.h>
+#include "s390-ccw.h"
+#include "cio.h"
+#include "virtio.h"
+#include "virtio-ccw.h"
+#include "virtio-scsi.h"
+#include "bswap.h"
+#include "helper.h"
+#include "s390-time.h"
+
+/* virtio spec v1.0 para 4.3.3.2 */
+static long kvm_hypercall(unsigned long nr, unsigned long param1,
+ unsigned long param2, unsigned long param3)
+{
+ register unsigned long r_nr asm("1") = nr;
+ register unsigned long r_param1 asm("2") = param1;
+ register unsigned long r_param2 asm("3") = param2;
+ register unsigned long r_param3 asm("4") = param3;
+ register long retval asm("2");
+
+ asm volatile ("diag %%r2,%%r4,0x500"
+ : "=d" (retval)
+ : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
+ : "memory", "cc");
+
+ return retval;
+}
+
+static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
+{
+ Ccw1 ccw = {};
+
+ ccw.cmd_code = cmd;
+ ccw.cda = (long)ptr;
+ ccw.count = len;
+
+ if (sli) {
+ ccw.flags |= CCW_FLAG_SLI;
+ }
+
+ return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
+}
+
+bool virtio_ccw_is_supported(SubChannelId schid)
+{
+ VDev *vdev = virtio_get_device();
+ vdev->schid = schid;
+ memset(&vdev->senseid, 0, sizeof(vdev->senseid));
+
+ /*
+ * Run sense id command.
+ * The size of the senseid data differs between devices (notably,
+ * between virtio devices and dasds), so specify the largest possible
+ * size and suppress the incorrect length indication for smaller sizes.
+ */
+ if (run_ccw(vdev, CCW_CMD_SENSE_ID, &vdev->senseid, sizeof(vdev->senseid),
+ true)) {
+ return false;
+ }
+
+ vdev->dev_type = vdev->senseid.cu_model;
+
+ if (vdev->senseid.cu_type == 0x3832) {
+ switch (vdev->dev_type) {
+ case VIRTIO_ID_BLOCK:
+ case VIRTIO_ID_SCSI:
+ case VIRTIO_ID_NET:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+int drain_irqs_ccw(SubChannelId schid)
+{
+ Irb irb = {};
+ int r = 0;
+
+ while (1) {
+ /* FIXME: make use of TPI, for that enable subchannel and isc */
+ if (tsch(schid, &irb)) {
+ /* Might want to differentiate error codes later on. */
+ if (irb.scsw.cstat) {
+ r = -EIO;
+ } else if (irb.scsw.dstat != 0xc) {
+ r = -EIO;
+ }
+ return r;
+ }
+ }
+}
+
+long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie)
+{
+ return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
+ 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(vr)) {
+ return -1;
+ }
+ return 0;
+}
+
+int virtio_ccw_reset(VDev *vdev)
+{
+ return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
+}
+
+int virtio_ccw_setup(VDev *vdev)
+{
+ int i, cfg_size = 0;
+ uint8_t status;
+ struct VirtioFeatureDesc {
+ uint32_t features;
+ uint8_t index;
+ } __attribute__((packed)) feats;
+
+ if (!virtio_ccw_is_supported(vdev->schid)) {
+ puts("Virtio unsupported for this device ID");
+ return -ENODEV;
+ }
+ /* device ID has been established now */
+
+ vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
+ vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
+
+ virtio_reset(vdev);
+
+ status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write ACKNOWLEDGE status to host");
+ return -EIO;
+ }
+
+ switch (vdev->dev_type) {
+ case VIRTIO_ID_NET:
+ vdev->nr_vqs = 2;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.net);
+ break;
+ case VIRTIO_ID_BLOCK:
+ vdev->nr_vqs = 1;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.blk);
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev->nr_vqs = 3;
+ vdev->cmd_vr_idx = VR_REQUEST;
+ cfg_size = sizeof(vdev->config.scsi);
+ break;
+ default:
+ puts("Unsupported virtio device");
+ return -ENODEV;
+ }
+
+ status |= VIRTIO_CONFIG_S_DRIVER;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER status to host");
+ return -EIO;
+ }
+
+ /* Feature negotiation */
+ for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
+ feats.features = 0;
+ feats.index = i;
+ if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not get features bits");
+ return -EIO;
+ }
+
+ vdev->guest_features[i] &= bswap32(feats.features);
+ feats.features = bswap32(vdev->guest_features[i]);
+ if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not set features bits");
+ return -EIO;
+ }
+ }
+
+ if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
+ puts("Could not get virtio device configuration");
+ return -EIO;
+ }
+
+ for (i = 0; i < vdev->nr_vqs; i++) {
+ VqInfo info = {
+ .queue = (unsigned long long) virtio_get_ring_area() + (i * VIRTIO_RING_SIZE),
+ .align = KVM_S390_VIRTIO_RING_ALIGN,
+ .index = i,
+ .num = 0,
+ };
+ VqConfig config = {
+ .index = i,
+ .num = 0,
+ };
+
+ if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
+ false)) {
+ puts("Could not get virtio device VQ config");
+ return -EIO;
+ }
+ info.num = config.num;
+ vring_init(&vdev->vrings[i], &info);
+ vdev->vrings[i].schid = vdev->schid;
+ if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
+ puts("Cannot set VQ info");
+ return -EIO;
+ }
+ }
+
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER_OK status to host");
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
index 301445bf97..604f1cf003 100644
--- a/pc-bios/s390-ccw/virtio-net.c
+++ b/pc-bios/s390-ccw/virtio-net.c
@@ -19,6 +19,7 @@
#include <ethernet.h>
#include "s390-ccw.h"
#include "virtio.h"
+#include "virtio-ccw.h"
#include "s390-time.h"
#include "helper.h"
@@ -54,7 +55,7 @@ int virtio_net_init(void *mac_addr)
rx_last_idx = 0;
vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
- virtio_setup_ccw(vdev);
+ virtio_ccw_setup(vdev);
if (!(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT)) {
puts("virtio-net device does not support the MAC address feature");
@@ -88,7 +89,7 @@ int send(int fd, const void *buf, int len, int flags)
while (!vr_poll(txvq)) {
yield();
}
- if (drain_irqs(txvq->schid)) {
+ if (drain_irqs(txvq)) {
puts("send: drain irqs failed");
return -1;
}
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index 71db75ce7b..6ab0f755f2 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -15,6 +15,7 @@
#include "virtio.h"
#include "scsi.h"
#include "virtio-scsi.h"
+#include "virtio-ccw.h"
#include "s390-time.h"
#include "helper.h"
@@ -476,12 +477,11 @@ static int virtio_scsi_setup(VDev *vdev)
return 0;
}
-int virtio_scsi_setup_device(SubChannelId schid)
+int virtio_scsi_setup_device(void)
{
VDev *vdev = virtio_get_device();
- vdev->schid = schid;
- virtio_setup_ccw(vdev);
+ virtio_ccw_setup(vdev);
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 0f4f201038..0488b3a07e 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -2,6 +2,7 @@
* Virtio driver bits
*
* Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ * Copyright 2025 IBM Corp. Author(s): Jared Rossi <jrossi@linux.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
@@ -13,6 +14,7 @@
#include "cio.h"
#include "virtio.h"
#include "virtio-scsi.h"
+#include "virtio-ccw.h"
#include "bswap.h"
#include "helper.h"
#include "s390-time.h"
@@ -44,69 +46,38 @@ VirtioDevType virtio_get_device_type(void)
return vdev.dev_type;
}
-/* virtio spec v1.0 para 4.3.3.2 */
-static long kvm_hypercall(unsigned long nr, unsigned long param1,
- unsigned long param2, unsigned long param3)
+char *virtio_get_ring_area(void)
{
- register unsigned long r_nr asm("1") = nr;
- register unsigned long r_param1 asm("2") = param1;
- register unsigned long r_param2 asm("3") = param2;
- register unsigned long r_param3 asm("4") = param3;
- register long retval asm("2");
-
- asm volatile ("diag %%r2,%%r4,0x500"
- : "=d" (retval)
- : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
- : "memory", "cc");
-
- return retval;
-}
-
-static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
-{
- return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
- vq_idx, cookie);
+ return ring_area;
}
/***********************************************
* Virtio functions *
***********************************************/
-int drain_irqs(SubChannelId schid)
+int drain_irqs(VRing *vr)
{
- Irb irb = {};
- int r = 0;
-
- while (1) {
- /* FIXME: make use of TPI, for that enable subchannel and isc */
- if (tsch(schid, &irb)) {
- /* Might want to differentiate error codes later on. */
- if (irb.scsw.cstat) {
- r = -EIO;
- } else if (irb.scsw.dstat != 0xc) {
- r = -EIO;
- }
- return r;
- }
+ switch (vdev.ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ return drain_irqs_ccw(vr->schid);
+ default:
+ return 0;
}
}
-static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
+int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
{
- Ccw1 ccw = {};
-
- ccw.cmd_code = cmd;
- ccw.cda = (long)ptr;
- ccw.count = len;
-
- if (sli) {
- ccw.flags |= CCW_FLAG_SLI;
+ switch (vdev->ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ return virtio_ccw_run(vdev, vqid, cmd);
+ default:
+ return -1;
}
-
- return do_cio(vdev->schid, vdev->dev_type, ptr2u32(&ccw), CCW_FMT1);
}
-static void vring_init(VRing *vr, VqInfo *info)
+void vring_init(VRing *vr, VqInfo *info)
{
void *p = (void *) info->queue;
@@ -134,7 +105,12 @@ static void vring_init(VRing *vr, VqInfo *info)
bool vring_notify(VRing *vr)
{
- vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
+ switch (vdev.ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ vr->cookie = virtio_ccw_notify(vr->schid, vr->id, vr->cookie);
+ }
+
return vr->cookie >= 0;
}
@@ -200,165 +176,24 @@ int vring_wait_reply(void)
return 1;
}
-int virtio_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(vr->schid)) {
- return -1;
- }
- return 0;
-}
-
int virtio_reset(VDev *vdev)
{
- return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
-}
-
-int virtio_setup_ccw(VDev *vdev)
-{
- int i, cfg_size = 0;
- uint8_t status;
- struct VirtioFeatureDesc {
- uint32_t features;
- uint8_t index;
- } __attribute__((packed)) feats;
-
- if (!virtio_is_supported(vdev->schid)) {
- puts("Virtio unsupported for this device ID");
- return -ENODEV;
- }
- /* device ID has been established now */
-
- vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
- vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
-
- virtio_reset(vdev);
-
- status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
- if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
- puts("Could not write ACKNOWLEDGE status to host");
- return -EIO;
- }
-
- switch (vdev->dev_type) {
- case VIRTIO_ID_NET:
- vdev->nr_vqs = 2;
- vdev->cmd_vr_idx = 0;
- cfg_size = sizeof(vdev->config.net);
- break;
- case VIRTIO_ID_BLOCK:
- vdev->nr_vqs = 1;
- vdev->cmd_vr_idx = 0;
- cfg_size = sizeof(vdev->config.blk);
- break;
- case VIRTIO_ID_SCSI:
- vdev->nr_vqs = 3;
- vdev->cmd_vr_idx = VR_REQUEST;
- cfg_size = sizeof(vdev->config.scsi);
- break;
+ switch (vdev->ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ return virtio_ccw_reset(vdev);
default:
- puts("Unsupported virtio device");
- return -ENODEV;
- }
-
- status |= VIRTIO_CONFIG_S_DRIVER;
- if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
- puts("Could not write DRIVER status to host");
- return -EIO;
- }
-
- /* Feature negotiation */
- for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
- feats.features = 0;
- feats.index = i;
- if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
- puts("Could not get features bits");
- return -EIO;
- }
-
- vdev->guest_features[i] &= bswap32(feats.features);
- feats.features = bswap32(vdev->guest_features[i]);
- if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
- puts("Could not set features bits");
- return -EIO;
- }
- }
-
- if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
- puts("Could not get virtio device configuration");
- return -EIO;
- }
-
- for (i = 0; i < vdev->nr_vqs; i++) {
- VqInfo info = {
- .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
- .align = KVM_S390_VIRTIO_RING_ALIGN,
- .index = i,
- .num = 0,
- };
- VqConfig config = {
- .index = i,
- .num = 0,
- };
-
- if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
- false)) {
- puts("Could not get virtio device VQ config");
- return -EIO;
- }
- info.num = config.num;
- vring_init(&vdev->vrings[i], &info);
- vdev->vrings[i].schid = vdev->schid;
- if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
- puts("Cannot set VQ info");
- return -EIO;
- }
- }
-
- status |= VIRTIO_CONFIG_S_DRIVER_OK;
- if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
- puts("Could not write DRIVER_OK status to host");
- return -EIO;
+ return -1;
}
-
- return 0;
}
-bool virtio_is_supported(SubChannelId schid)
+bool virtio_is_supported(VDev *vdev)
{
- vdev.schid = schid;
- memset(&vdev.senseid, 0, sizeof(vdev.senseid));
-
- /*
- * Run sense id command.
- * The size of the senseid data differs between devices (notably,
- * between virtio devices and dasds), so specify the largest possible
- * size and suppress the incorrect length indication for smaller sizes.
- */
- if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid),
- true)) {
+ switch (vdev->ipl_type) {
+ case S390_IPL_TYPE_QEMU_SCSI:
+ case S390_IPL_TYPE_CCW:
+ return virtio_ccw_is_supported(vdev->schid);
+ default:
return false;
}
-
- vdev.dev_type = vdev.senseid.cu_model;
-
- if (vdev.senseid.cu_type == 0x3832) {
- switch (vdev.dev_type) {
- case VIRTIO_ID_BLOCK:
- case VIRTIO_ID_SCSI:
- case VIRTIO_ID_NET:
- return true;
- default:
- return false;
- }
- }
- return false;
}
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index a0f24c94a8..259cff09db 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -34,7 +34,8 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
.PHONY : all clean build-all distclean
OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
- virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
+ virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
+ virtio-ccw.o
SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
--
2.49.0
next prev parent reply other threads:[~2025-12-10 20:56 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-10 20:54 [PATCH V2 0/10] s390x: Add support for virtio-blk-pci IPL device jrossi
2025-12-10 20:54 ` [PATCH 01/10] pc-bios/s390-ccw: Fix misattributed function prototypes jrossi
2025-12-10 20:54 ` [PATCH 02/10] pc-bios/s390-ccw: Store boot device type and bus separately jrossi
2025-12-10 20:54 ` jrossi [this message]
2025-12-10 20:54 ` [PATCH 04/10] include/hw/s390x: Move CLP definitions for easier BIOS access jrossi
2025-12-10 20:54 ` [PATCH 05/10] pc-bios/s390-ccw: Introduce CLP Architecture jrossi
2025-12-10 20:54 ` [PATCH 06/10] pc-bios/s390-ccw: Introduce PCI device jrossi
2025-12-10 20:54 ` [PATCH 07/10] pc-bios/s390-ccw: Add support for virtio-blk-pci IPL jrossi
2025-12-10 20:54 ` [PATCH 08/10] s390x: Build IPLB for virtio-pci devices jrossi
2025-12-10 20:54 ` [PATCH 09/10] hw: Add "loadparm" property to PCI devices for booting on s390x jrossi
2025-12-10 20:54 ` [PATCH 10/10] tests/qtest: Add s390x PCI boot test to cdrom-test.c jrossi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251210205449.2783111-4-jrossi@linux.ibm.com \
--to=jrossi@linux.ibm.com \
--cc=alifm@linux.ibm.com \
--cc=farman@linux.ibm.com \
--cc=jjherne@linux.ibm.com \
--cc=mjrosato@linux.ibm.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=thuth@redhat.com \
--cc=zycai@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).