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);