@samitouri / QOSamiQemu / commits / 4ff1499ada

pc-bios/s390-ccw: Split virtio-ccw and generic virtio

Separate the CCW specific virtio routines and create generic wrappers for easier reuse of existing virtio functions with non-CCW devices. Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com> Message-ID: <20260309003601.242634-7-jrossi@linux.ibm.com> [thuth: Use SPDX license identifier in virtio-ccw.c] Signed-off-by: Thomas Huth <thuth@redhat.com>

Jared Rossi committed Mar 8, 2026 at 20:35 UTC 4ff1499adab8f266adf5fc837ae5d72666b26551
12 files changed +330 -221
pc-bios/s390-ccw/Makefile
+2 -1
@@ -34,7 +34,8 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
34 .PHONY : all clean build-all distclean
35
36 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
37 - virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
37 + virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
38 + virtio-ccw.o
39
40 SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
41
pc-bios/s390-ccw/main.c
+5 -3
@@ -71,6 +71,7 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
71 bool is_virtio;
72 Schib schib;
73 int r;
74 + VDev *vdev = virtio_get_device();
75
76 blk_schid.sch_no = sch_no;
77 r = stsch_err(blk_schid, &schib);
@@ -91,7 +92,8 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
92 * Note: we always have to run virtio_is_supported() here to make
93 * sure that the vdev.senseid data gets pre-initialized correctly
94 */
94 - is_virtio = virtio_is_supported(blk_schid);
95 + vdev->schid = blk_schid;
96 + is_virtio = virtio_is_supported(vdev);
97
98 /* No specific devno given, just return whether the device is possibly bootable */
99 if (dev_no < 0) {
@@ -256,10 +258,10 @@ static int virtio_setup(void)
258 puts("Network boot device detected");
259 return 0;
260 case VIRTIO_ID_BLOCK:
259 - ret = virtio_blk_setup_device(blk_schid);
261 + ret = virtio_blk_setup_device(vdev);
262 break;
263 case VIRTIO_ID_SCSI:
262 - ret = virtio_scsi_setup_device(blk_schid);
264 + ret = virtio_scsi_setup_device(vdev);
265 break;
266 default:
267 puts("\n! No IPL device available !\n");
pc-bios/s390-ccw/netmain.c
+1 -1
@@ -500,7 +500,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
500 continue;
501 }
502 enable_subchannel(net_schid);
503 - if (!virtio_is_supported(net_schid)) {
503 + if (!virtio_is_supported(virtio_get_device())) {
504 continue;
505 }
506 if (virtio_get_device_type() != VIRTIO_ID_NET) {
pc-bios/s390-ccw/s390-ccw.h
-3
@@ -66,9 +66,6 @@ void sclp_setup(void);
66 void sclp_get_loadparm_ascii(char *loadparm);
67 int sclp_read(char *str, size_t count);
68
69 -/* virtio.c */
70 -bool virtio_is_supported(SubChannelId schid);
71 -
69 /* bootmap.c */
70 void zipl_load(void);
71
pc-bios/s390-ccw/virtio-blkdev.c
+9 -6
@@ -12,6 +12,7 @@
12 #include "s390-ccw.h"
13 #include "virtio.h"
14 #include "virtio-scsi.h"
15 +#include "virtio-ccw.h"
16
17 #define VIRTIO_BLK_F_GEOMETRY (1 << 4)
18 #define VIRTIO_BLK_F_BLK_SIZE (1 << 6)
@@ -229,15 +230,17 @@ uint64_t virtio_get_blocks(void)
230 }
231 }
232
232 -int virtio_blk_setup_device(SubChannelId schid)
233 +int virtio_blk_setup_device(VDev *vdev)
234 {
234 - VDev *vdev = virtio_get_device();
235 -
235 vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
237 - vdev->schid = schid;
238 - virtio_setup_ccw(vdev);
236
237 puts("Using virtio-blk.");
238
242 - return 0;
239 + switch (vdev->ipl_type) {
240 + case S390_IPL_TYPE_QEMU_SCSI:
241 + case S390_IPL_TYPE_CCW:
242 + return virtio_ccw_setup(vdev);
243 + default:
244 + return 1;
245 + }
246 }
pc-bios/s390-ccw/virtio-ccw.c new
+239
@@ -0,0 +1,239 @@
1 +/*
2 + * Virtio functionality for CCW devices
3 + *
4 + * SPDX-License-Identifier: GPL-2.0-or-later
5 + *
6 + * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
7 + * Copyright 2025 IBM Corp.
8 + *
9 + * Author(s): Jared Rossi <jrossi@linux.ibm.com>
10 + */
11 +
12 +#include <string.h>
13 +#include "s390-ccw.h"
14 +#include "cio.h"
15 +#include "virtio.h"
16 +#include "virtio-ccw.h"
17 +#include "virtio-scsi.h"
18 +#include "bswap.h"
19 +#include "helper.h"
20 +#include "s390-time.h"
21 +
22 +/* virtio spec v1.0 para 4.3.3.2 */
23 +static long kvm_hypercall(unsigned long nr, unsigned long param1,
24 + unsigned long param2, unsigned long param3)
25 +{
26 + register unsigned long r_nr asm("1") = nr;
27 + register unsigned long r_param1 asm("2") = param1;
28 + register unsigned long r_param2 asm("3") = param2;
29 + register unsigned long r_param3 asm("4") = param3;
30 + register long retval asm("2");
31 +
32 + asm volatile ("diag %%r2,%%r4,0x500"
33 + : "=d" (retval)
34 + : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
35 + : "memory", "cc");
36 +
37 + return retval;
38 +}
39 +
40 +static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
41 +{
42 + Ccw1 ccw = {};
43 +
44 + ccw.cmd_code = cmd;
45 + ccw.cda = (long)ptr;
46 + ccw.count = len;
47 +
48 + if (sli) {
49 + ccw.flags |= CCW_FLAG_SLI;
50 + }
51 +
52 + return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
53 +}
54 +
55 +bool virtio_ccw_is_supported(VDev *vdev)
56 +{
57 + memset(&vdev->senseid, 0, sizeof(vdev->senseid));
58 +
59 + /*
60 + * Run sense id command.
61 + * The size of the senseid data differs between devices (notably,
62 + * between virtio devices and dasds), so specify the largest possible
63 + * size and suppress the incorrect length indication for smaller sizes.
64 + */
65 + if (run_ccw(vdev, CCW_CMD_SENSE_ID, &vdev->senseid, sizeof(vdev->senseid),
66 + true)) {
67 + return false;
68 + }
69 +
70 + vdev->dev_type = vdev->senseid.cu_model;
71 +
72 + if (vdev->senseid.cu_type == 0x3832) {
73 + switch (vdev->dev_type) {
74 + case VIRTIO_ID_BLOCK:
75 + case VIRTIO_ID_SCSI:
76 + case VIRTIO_ID_NET:
77 + return true;
78 + default:
79 + return false;
80 + }
81 + }
82 + return false;
83 +}
84 +
85 +int drain_irqs_ccw(SubChannelId schid)
86 +{
87 + Irb irb = {};
88 + int r = 0;
89 +
90 + while (1) {
91 + /* FIXME: make use of TPI, for that enable subchannel and isc */
92 + if (tsch(schid, &irb)) {
93 + /* Might want to differentiate error codes later on. */
94 + if (irb.scsw.cstat) {
95 + r = -EIO;
96 + } else if (irb.scsw.dstat != 0xc) {
97 + r = -EIO;
98 + }
99 + return r;
100 + }
101 + }
102 +}
103 +
104 +long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie)
105 +{
106 + return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
107 + vq_idx, cookie);
108 +}
109 +
110 +int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd)
111 +{
112 + VRing *vr = &vdev->vrings[vqid];
113 + int i = 0;
114 +
115 + do {
116 + vring_send_buf(vr, cmd[i].data, cmd[i].size,
117 + cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
118 + } while (cmd[i++].flags & VRING_DESC_F_NEXT);
119 +
120 + vring_wait_reply();
121 + if (drain_irqs()) {
122 + return -1;
123 + }
124 + return 0;
125 +}
126 +
127 +int virtio_ccw_reset(VDev *vdev)
128 +{
129 + return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
130 +}
131 +
132 +int virtio_ccw_setup(VDev *vdev)
133 +{
134 + int i, cfg_size = 0;
135 + uint8_t status;
136 + struct VirtioFeatureDesc {
137 + uint32_t features;
138 + uint8_t index;
139 + } __attribute__((packed)) feats;
140 +
141 + if (!virtio_ccw_is_supported(vdev)) {
142 + puts("Virtio unsupported for this device ID");
143 + return -ENODEV;
144 + }
145 + /* device ID has been established now */
146 +
147 + vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
148 + vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
149 +
150 + virtio_reset(vdev);
151 +
152 + status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
153 + if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
154 + puts("Could not write ACKNOWLEDGE status to host");
155 + return -EIO;
156 + }
157 +
158 + switch (vdev->dev_type) {
159 + case VIRTIO_ID_NET:
160 + vdev->nr_vqs = 2;
161 + vdev->cmd_vr_idx = 0;
162 + cfg_size = sizeof(vdev->config.net);
163 + break;
164 + case VIRTIO_ID_BLOCK:
165 + vdev->nr_vqs = 1;
166 + vdev->cmd_vr_idx = 0;
167 + cfg_size = sizeof(vdev->config.blk);
168 + break;
169 + case VIRTIO_ID_SCSI:
170 + vdev->nr_vqs = 3;
171 + vdev->cmd_vr_idx = VR_REQUEST;
172 + cfg_size = sizeof(vdev->config.scsi);
173 + break;
174 + default:
175 + puts("Unsupported virtio device");
176 + return -ENODEV;
177 + }
178 +
179 + status |= VIRTIO_CONFIG_S_DRIVER;
180 + if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
181 + puts("Could not write DRIVER status to host");
182 + return -EIO;
183 + }
184 +
185 + /* Feature negotiation */
186 + for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
187 + feats.features = 0;
188 + feats.index = i;
189 + if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
190 + puts("Could not get features bits");
191 + return -EIO;
192 + }
193 +
194 + vdev->guest_features[i] &= bswap32(feats.features);
195 + feats.features = bswap32(vdev->guest_features[i]);
196 + if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
197 + puts("Could not set features bits");
198 + return -EIO;
199 + }
200 + }
201 +
202 + if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
203 + puts("Could not get virtio device configuration");
204 + return -EIO;
205 + }
206 +
207 + for (i = 0; i < vdev->nr_vqs; i++) {
208 + VqInfo info = {
209 + .queue = (unsigned long long) virtio_get_ring_area(i),
210 + .align = KVM_S390_VIRTIO_RING_ALIGN,
211 + .index = i,
212 + .num = 0,
213 + };
214 + VqConfig config = {
215 + .index = i,
216 + .num = 0,
217 + };
218 +
219 + if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
220 + false)) {
221 + puts("Could not get virtio device VQ config");
222 + return -EIO;
223 + }
224 + info.num = config.num;
225 + vring_init(&vdev->vrings[i], &info);
226 + if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
227 + puts("Cannot set VQ info");
228 + return -EIO;
229 + }
230 + }
231 +
232 + status |= VIRTIO_CONFIG_S_DRIVER_OK;
233 + if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
234 + puts("Could not write DRIVER_OK status to host");
235 + return -EIO;
236 + }
237 +
238 + return 0;
239 +}
pc-bios/s390-ccw/virtio-ccw.h new
+24
@@ -0,0 +1,24 @@
1 +/*
2 + * Virtio definitions for CCW devices
3 + *
4 + * Copyright 2025 IBM Corp.
5 + * Author(s): Jared Rossi <jrossi@linux.ibm.com>
6 + *
7 + * SPDX-License-Identifier: GPL-2.0-or-later
8 + */
9 +
10 +#ifndef VIRTIO_CCW_H
11 +#define VIRTIO_CCW_H
12 +
13 +/* main.c */
14 +extern SubChannelId blk_schid;
15 +
16 +/* virtio-ccw.c */
17 +int drain_irqs_ccw(SubChannelId schid);
18 +bool virtio_ccw_is_supported(VDev *vdev);
19 +int virtio_ccw_run(VDev *vdev, int vqid, VirtioCmd *cmd);
20 +long virtio_ccw_notify(SubChannelId schid, int vq_idx, long cookie);
21 +int virtio_ccw_setup(VDev *vdev);
22 +int virtio_ccw_reset(VDev *vdev);
23 +
24 +#endif
pc-bios/s390-ccw/virtio-net.c
+2 -1
@@ -19,6 +19,7 @@
19 #include <ethernet.h>
20 #include "s390-ccw.h"
21 #include "virtio.h"
22 +#include "virtio-ccw.h"
23 #include "s390-time.h"
24 #include "helper.h"
25
@@ -54,7 +55,7 @@ int virtio_net_init(void *mac_addr)
55 rx_last_idx = 0;
56
57 vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
57 - virtio_setup_ccw(vdev);
58 + virtio_ccw_setup(vdev);
59
60 if (!(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT)) {
61 puts("virtio-net device does not support the MAC address feature");
pc-bios/s390-ccw/virtio-scsi.c
+3 -5
@@ -15,6 +15,7 @@
15 #include "virtio.h"
16 #include "scsi.h"
17 #include "virtio-scsi.h"
18 +#include "virtio-ccw.h"
19 #include "s390-time.h"
20 #include "helper.h"
21
@@ -476,12 +477,9 @@ static int virtio_scsi_setup(VDev *vdev)
477 return 0;
478 }
479
479 -int virtio_scsi_setup_device(SubChannelId schid)
480 +int virtio_scsi_setup_device(VDev *vdev)
481 {
481 - VDev *vdev = virtio_get_device();
482 -
483 - vdev->schid = schid;
484 - virtio_setup_ccw(vdev);
482 + virtio_ccw_setup(vdev);
483
484 if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
485 puts("Config: sense size mismatch");
pc-bios/s390-ccw/virtio-scsi.h
+1 -1
@@ -69,6 +69,6 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
69
70 int virtio_scsi_read_many(VDev *vdev,
71 unsigned long sector, void *load_addr, int sec_num);
72 -int virtio_scsi_setup_device(SubChannelId schid);
72 +int virtio_scsi_setup_device(VDev *vdev);
73
74 #endif /* VIRTIO_SCSI_H */
pc-bios/s390-ccw/virtio.c
+40 -199
@@ -2,6 +2,9 @@
2 * Virtio driver bits
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 + * Copyright 2025 IBM Corp.
6 + *
7 + * Author(s): Jared Rossi <jrossi@linux.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or (at
10 * your option) any later version. See the COPYING file in the top-level
@@ -13,6 +16,7 @@
16 #include "cio.h"
17 #include "virtio.h"
18 #include "virtio-scsi.h"
19 +#include "virtio-ccw.h"
20 #include "bswap.h"
21 #include "helper.h"
22 #include "s390-time.h"
@@ -44,28 +48,9 @@ VirtioDevType virtio_get_device_type(void)
48 return vdev.dev_type;
49 }
50
47 -/* virtio spec v1.0 para 4.3.3.2 */
48 -static long kvm_hypercall(unsigned long nr, unsigned long param1,
49 - unsigned long param2, unsigned long param3)
51 +char *virtio_get_ring_area(int ring_num)
52 {
51 - register unsigned long r_nr asm("1") = nr;
52 - register unsigned long r_param1 asm("2") = param1;
53 - register unsigned long r_param2 asm("3") = param2;
54 - register unsigned long r_param3 asm("4") = param3;
55 - register long retval asm("2");
56 -
57 - asm volatile ("diag %%r2,%%r4,0x500"
58 - : "=d" (retval)
59 - : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
60 - : "memory", "cc");
61 -
62 - return retval;
63 -}
64 -
65 -static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
66 -{
67 - return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
68 - vq_idx, cookie);
53 + return ring_area + ring_num * VIRTIO_RING_SIZE;
54 }
55
56 /***********************************************
@@ -74,39 +59,27 @@ static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
59
60 int drain_irqs(void)
61 {
77 - Irb irb = {};
78 - int r = 0;
79 -
80 - while (1) {
81 - /* FIXME: make use of TPI, for that enable subchannel and isc */
82 - if (tsch(vdev.schid, &irb)) {
83 - /* Might want to differentiate error codes later on. */
84 - if (irb.scsw.cstat) {
85 - r = -EIO;
86 - } else if (irb.scsw.dstat != 0xc) {
87 - r = -EIO;
88 - }
89 - return r;
90 - }
62 + switch (vdev.ipl_type) {
63 + case S390_IPL_TYPE_QEMU_SCSI:
64 + case S390_IPL_TYPE_CCW:
65 + return drain_irqs_ccw(vdev.schid);
66 + default:
67 + return 0;
68 }
69 }
70
94 -static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
71 +int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
72 {
96 - Ccw1 ccw = {};
97 -
98 - ccw.cmd_code = cmd;
99 - ccw.cda = (long)ptr;
100 - ccw.count = len;
101 -
102 - if (sli) {
103 - ccw.flags |= CCW_FLAG_SLI;
73 + switch (vdev->ipl_type) {
74 + case S390_IPL_TYPE_QEMU_SCSI:
75 + case S390_IPL_TYPE_CCW:
76 + return virtio_ccw_run(vdev, vqid, cmd);
77 + default:
78 + return -1;
79 }
105 -
106 - return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
80 }
81
109 -static void vring_init(VRing *vr, VqInfo *info)
82 +void vring_init(VRing *vr, VqInfo *info)
83 {
84 void *p = (void *) info->queue;
85
@@ -134,7 +107,15 @@ static void vring_init(VRing *vr, VqInfo *info)
107
108 bool vring_notify(VRing *vr)
109 {
137 - vr->cookie = virtio_notify(vdev.schid, vr->id, vr->cookie);
110 + switch (vdev.ipl_type) {
111 + case S390_IPL_TYPE_QEMU_SCSI:
112 + case S390_IPL_TYPE_CCW:
113 + vr->cookie = virtio_ccw_notify(vdev.schid, vr->id, vr->cookie);
114 + break;
115 + default:
116 + return 1;
117 + }
118 +
119 return vr->cookie >= 0;
120 }
121
@@ -200,164 +181,24 @@ int vring_wait_reply(void)
181 return 1;
182 }
183
203 -int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
204 -{
205 - VRing *vr = &vdev->vrings[vqid];
206 - int i = 0;
207 -
208 - do {
209 - vring_send_buf(vr, cmd[i].data, cmd[i].size,
210 - cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
211 - } while (cmd[i++].flags & VRING_DESC_F_NEXT);
212 -
213 - vring_wait_reply();
214 - if (drain_irqs()) {
215 - return -1;
216 - }
217 - return 0;
218 -}
219 -
184 int virtio_reset(VDev *vdev)
185 {
222 - return run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
223 -}
224 -
225 -int virtio_setup_ccw(VDev *vdev)
226 -{
227 - int i, cfg_size = 0;
228 - uint8_t status;
229 - struct VirtioFeatureDesc {
230 - uint32_t features;
231 - uint8_t index;
232 - } __attribute__((packed)) feats;
233 -
234 - if (!virtio_is_supported(vdev->schid)) {
235 - puts("Virtio unsupported for this device ID");
236 - return -ENODEV;
237 - }
238 - /* device ID has been established now */
239 -
240 - vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
241 - vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
242 -
243 - virtio_reset(vdev);
244 -
245 - status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
246 - if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
247 - puts("Could not write ACKNOWLEDGE status to host");
248 - return -EIO;
249 - }
250 -
251 - switch (vdev->dev_type) {
252 - case VIRTIO_ID_NET:
253 - vdev->nr_vqs = 2;
254 - vdev->cmd_vr_idx = 0;
255 - cfg_size = sizeof(vdev->config.net);
256 - break;
257 - case VIRTIO_ID_BLOCK:
258 - vdev->nr_vqs = 1;
259 - vdev->cmd_vr_idx = 0;
260 - cfg_size = sizeof(vdev->config.blk);
261 - break;
262 - case VIRTIO_ID_SCSI:
263 - vdev->nr_vqs = 3;
264 - vdev->cmd_vr_idx = VR_REQUEST;
265 - cfg_size = sizeof(vdev->config.scsi);
266 - break;
186 + switch (vdev->ipl_type) {
187 + case S390_IPL_TYPE_QEMU_SCSI:
188 + case S390_IPL_TYPE_CCW:
189 + return virtio_ccw_reset(vdev);
190 default:
268 - puts("Unsupported virtio device");
269 - return -ENODEV;
270 - }
271 -
272 - status |= VIRTIO_CONFIG_S_DRIVER;
273 - if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
274 - puts("Could not write DRIVER status to host");
275 - return -EIO;
276 - }
277 -
278 - /* Feature negotiation */
279 - for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
280 - feats.features = 0;
281 - feats.index = i;
282 - if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
283 - puts("Could not get features bits");
284 - return -EIO;
285 - }
286 -
287 - vdev->guest_features[i] &= bswap32(feats.features);
288 - feats.features = bswap32(vdev->guest_features[i]);
289 - if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
290 - puts("Could not set features bits");
291 - return -EIO;
292 - }
293 - }
294 -
295 - if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
296 - puts("Could not get virtio device configuration");
297 - return -EIO;
298 - }
299 -
300 - for (i = 0; i < vdev->nr_vqs; i++) {
301 - VqInfo info = {
302 - .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
303 - .align = KVM_S390_VIRTIO_RING_ALIGN,
304 - .index = i,
305 - .num = 0,
306 - };
307 - VqConfig config = {
308 - .index = i,
309 - .num = 0,
310 - };
311 -
312 - if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
313 - false)) {
314 - puts("Could not get virtio device VQ config");
315 - return -EIO;
316 - }
317 - info.num = config.num;
318 - vring_init(&vdev->vrings[i], &info);
319 - if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
320 - puts("Cannot set VQ info");
321 - return -EIO;
322 - }
323 - }
324 -
325 - status |= VIRTIO_CONFIG_S_DRIVER_OK;
326 - if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
327 - puts("Could not write DRIVER_OK status to host");
328 - return -EIO;
191 + return -1;
192 }
330 -
331 - return 0;
193 }
194
334 -bool virtio_is_supported(SubChannelId schid)
195 +bool virtio_is_supported(VDev *vdev)
196 {
336 - vdev.schid = schid;
337 - memset(&vdev.senseid, 0, sizeof(vdev.senseid));
338 -
339 - /*
340 - * Run sense id command.
341 - * The size of the senseid data differs between devices (notably,
342 - * between virtio devices and dasds), so specify the largest possible
343 - * size and suppress the incorrect length indication for smaller sizes.
344 - */
345 - if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid),
346 - true)) {
197 + switch (vdev->ipl_type) {
198 + case S390_IPL_TYPE_QEMU_SCSI:
199 + case S390_IPL_TYPE_CCW:
200 + return virtio_ccw_is_supported(vdev);
201 + default:
202 return false;
203 }
349 -
350 - vdev.dev_type = vdev.senseid.cu_model;
351 -
352 - if (vdev.senseid.cu_type == 0x3832) {
353 - switch (vdev.dev_type) {
354 - case VIRTIO_ID_BLOCK:
355 - case VIRTIO_ID_SCSI:
356 - case VIRTIO_ID_NET:
357 - return true;
358 - default:
359 - return false;
360 - }
361 - }
362 - return false;
204 }
pc-bios/s390-ccw/virtio.h
+4 -1
@@ -108,6 +108,7 @@ struct VRing {
108 };
109 typedef struct VRing VRing;
110
111 +char *virtio_get_ring_area(int ring_num);
112
113 /***********************************************
114 * Virtio block *
@@ -269,6 +270,8 @@ struct VirtioCmd {
270 };
271 typedef struct VirtioCmd VirtioCmd;
272
273 +void vring_init(VRing *vr, VqInfo *info);
274 +bool virtio_is_supported(VDev *vdev);
275 bool vring_notify(VRing *vr);
276 int drain_irqs(void);
277 void vring_send_buf(VRing *vr, void *p, int len, int flags);
@@ -283,7 +286,7 @@ int virtio_net_init(void *mac_addr);
286 void virtio_net_deinit(void);
287
288 /* virtio-blkdev.c */
286 -int virtio_blk_setup_device(SubChannelId schid);
289 +int virtio_blk_setup_device(VDev *vdev);
290 int virtio_read(unsigned long sector, void *load_addr);
291 unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long rec_list2,
292 void *load_addr);