blob: 87683314cfc4ed9a24de663bebcf91d6082f8472 [file] [log] [blame]
Alexander Graf1e17c2c2013-04-22 21:01:00 +02001/*
2 * Virtio driver bits
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
7 * your option) any later version. See the COPYING file in the top-level
8 * directory.
9 */
10
Thomas Huth90806fe2017-07-12 14:49:43 +020011#include "libc.h"
Alexander Graf1e17c2c2013-04-22 21:01:00 +020012#include "s390-ccw.h"
13#include "virtio.h"
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +010014#include "virtio-scsi.h"
Alexander Graf1e17c2c2013-04-22 21:01:00 +020015
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +010016#define VRING_WAIT_REPLY_TIMEOUT 3
17
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010018static VRing block[VIRTIO_MAX_VQS];
19static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
20 __attribute__((__aligned__(PAGE_SIZE)));
Alexander Graf1e17c2c2013-04-22 21:01:00 +020021
Dominik Dingelc8cda872013-06-17 14:29:42 +020022static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
23
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +010024static VDev vdev = {
25 .nr_vqs = 1,
26 .vrings = block,
27 .cmd_vr_idx = 0,
28 .ring_area = ring_area,
29 .wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +010030 .schid = { .one = 1 },
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +010031 .scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE,
32 .blk_factor = 1,
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +010033};
34
35VDev *virtio_get_device(void)
36{
37 return &vdev;
38}
39
40VirtioDevType virtio_get_device_type(void)
41{
42 return vdev.senseid.cu_model;
43}
44
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010045/* virtio spec v1.0 para 4.3.3.2 */
Alexander Graf1e17c2c2013-04-22 21:01:00 +020046static long kvm_hypercall(unsigned long nr, unsigned long param1,
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010047 unsigned long param2, unsigned long param3)
Alexander Graf1e17c2c2013-04-22 21:01:00 +020048{
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +020049 register ulong r_nr asm("1") = nr;
50 register ulong r_param1 asm("2") = param1;
51 register ulong r_param2 asm("3") = param2;
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010052 register ulong r_param3 asm("4") = param3;
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +020053 register long retval asm("2");
Alexander Graf1e17c2c2013-04-22 21:01:00 +020054
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +020055 asm volatile ("diag 2,4,0x500"
56 : "=d" (retval)
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010057 : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +020058 : "memory", "cc");
Alexander Graf1e17c2c2013-04-22 21:01:00 +020059
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +020060 return retval;
Alexander Graf1e17c2c2013-04-22 21:01:00 +020061}
62
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010063static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
Alexander Graf1e17c2c2013-04-22 21:01:00 +020064{
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +010065 return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
66 vq_idx, cookie);
Alexander Graf1e17c2c2013-04-22 21:01:00 +020067}
68
69/***********************************************
70 * Virtio functions *
71 ***********************************************/
72
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010073static int drain_irqs(SubChannelId schid)
Alexander Graf1e17c2c2013-04-22 21:01:00 +020074{
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010075 Irb irb = {};
Cornelia Huck776e7f02013-04-26 02:12:53 +000076 int r = 0;
77
Alexander Graf1e17c2c2013-04-22 21:01:00 +020078 while (1) {
Cornelia Huck776e7f02013-04-26 02:12:53 +000079 /* FIXME: make use of TPI, for that enable subchannel and isc */
Alexander Graf1e17c2c2013-04-22 21:01:00 +020080 if (tsch(schid, &irb)) {
Cornelia Huck776e7f02013-04-26 02:12:53 +000081 /* Might want to differentiate error codes later on. */
82 if (irb.scsw.cstat) {
83 r = -EIO;
84 } else if (irb.scsw.dstat != 0xc) {
85 r = -EIO;
86 }
87 return r;
Alexander Graf1e17c2c2013-04-22 21:01:00 +020088 }
89 }
90}
91
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +010092static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
Alexander Graf1e17c2c2013-04-22 21:01:00 +020093{
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +010094 Ccw1 ccw = {};
95 CmdOrb orb = {};
96 Schib schib;
Alexander Graf1e17c2c2013-04-22 21:01:00 +020097 int r;
98
99 /* start command processing */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100100 stsch_err(vdev->schid, &schib);
Dong Jia Shi9c9f5f32016-09-22 10:36:39 +0200101 /* enable the subchannel for IPL device */
102 schib.pmcw.ena = 1;
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100103 msch(vdev->schid, &schib);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200104
105 /* start subchannel command */
106 orb.fmt = 1;
107 orb.cpa = (u32)(long)&ccw;
108 orb.lpm = 0x80;
109
110 ccw.cmd_code = cmd;
111 ccw.cda = (long)ptr;
112 ccw.count = len;
113
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100114 r = ssch(vdev->schid, &orb);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200115 /*
116 * XXX Wait until device is done processing the CCW. For now we can
117 * assume that a simple tsch will have finished the CCW processing,
118 * but the architecture allows for asynchronous operation
119 */
Cornelia Huck0f3f1f32013-04-26 02:12:54 +0000120 if (!r) {
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100121 r = drain_irqs(vdev->schid);
Cornelia Huck0f3f1f32013-04-26 02:12:54 +0000122 }
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200123 return r;
124}
125
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100126static void vring_init(VRing *vr, VqInfo *info)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200127{
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100128 void *p = (void *) info->queue;
129
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200130 debug_print_addr("init p", p);
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100131 vr->id = info->index;
132 vr->num = info->num;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200133 vr->desc = p;
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100134 vr->avail = p + info->num * sizeof(VRingDesc);
135 vr->used = (void *)(((unsigned long)&vr->avail->ring[info->num]
136 + info->align - 1) & ~(info->align - 1));
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200137
Christian Borntraeger39c93c62013-05-23 13:51:41 +0200138 /* Zero out all relevant field */
139 vr->avail->flags = 0;
140 vr->avail->idx = 0;
141
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200142 /* We're running with interrupts off anyways, so don't bother */
143 vr->used->flags = VRING_USED_F_NO_NOTIFY;
Christian Borntraeger39c93c62013-05-23 13:51:41 +0200144 vr->used->idx = 0;
Cornelia Huck441ea692013-08-29 17:52:43 +0200145 vr->used_idx = 0;
Christian Borntraegerd1028f12014-02-12 16:17:35 +0100146 vr->next_idx = 0;
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100147 vr->cookie = 0;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200148
149 debug_print_addr("init vr", vr);
150}
151
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100152static bool vring_notify(VRing *vr)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200153{
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100154 vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
155 return vr->cookie >= 0;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200156}
157
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +0100158static void vring_send_buf(VRing *vr, void *p, int len, int flags)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200159{
160 /* For follow-up chains we need to keep the first entry point */
161 if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
162 vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx;
163 }
164
165 vr->desc[vr->next_idx].addr = (ulong)p;
166 vr->desc[vr->next_idx].len = len;
167 vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN;
Christian Borntraegerdc036402013-04-23 01:23:04 +0000168 vr->desc[vr->next_idx].next = vr->next_idx;
169 vr->desc[vr->next_idx].next++;
170 vr->next_idx++;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200171
172 /* Chains only have a single ID */
173 if (!(flags & VRING_DESC_F_NEXT)) {
174 vr->avail->idx++;
175 }
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200176}
177
178static u64 get_clock(void)
179{
180 u64 r;
181
182 asm volatile("stck %0" : "=Q" (r) : : "cc");
183 return r;
184}
185
Eugene (jno) Dvurechenskidc25e842015-10-27 09:49:27 +0100186ulong get_second(void)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200187{
188 return (get_clock() >> 12) / 1000000;
189}
190
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100191static int vr_poll(VRing *vr)
192{
193 if (vr->used->idx == vr->used_idx) {
194 vring_notify(vr);
195 yield();
196 return 0;
197 }
198
199 vr->used_idx = vr->used->idx;
200 vr->next_idx = 0;
201 vr->desc[0].len = 0;
202 vr->desc[0].flags = 0;
203 return 1; /* vr has been updated */
204}
205
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200206/*
207 * Wait for the host to reply.
208 *
209 * timeout is in seconds if > 0.
210 *
211 * Returns 0 on success, 1 on timeout.
212 */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100213static int vring_wait_reply(void)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200214{
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100215 ulong target_second = get_second() + vdev.wait_reply_timeout;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200216
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100217 /* Wait for any queue to be updated by the host */
218 do {
219 int i, r = 0;
220
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100221 for (i = 0; i < vdev.nr_vqs; i++) {
222 r += vr_poll(&vdev.vrings[i]);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200223 }
224 yield();
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100225 if (r) {
226 return 0;
227 }
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100228 } while (!vdev.wait_reply_timeout || (get_second() < target_second));
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200229
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100230 return 1;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200231}
232
Eugene (jno) Dvurechenski8944edc2015-10-28 11:12:13 +0100233int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
234{
235 VRing *vr = &vdev->vrings[vqid];
236 int i = 0;
237
238 do {
239 vring_send_buf(vr, cmd[i].data, cmd[i].size,
240 cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
241 } while (cmd[i++].flags & VRING_DESC_F_NEXT);
242
243 vring_wait_reply();
244 if (drain_irqs(vr->schid)) {
245 return -1;
246 }
247 return 0;
248}
249
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200250/***********************************************
251 * Virtio block *
252 ***********************************************/
253
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100254static int virtio_blk_read_many(VDev *vdev,
255 ulong sector, void *load_addr, int sec_num)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200256{
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +0100257 VirtioBlkOuthdr out_hdr;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200258 u8 status;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100259 VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200260
261 /* Tell the host we want to read */
262 out_hdr.type = VIRTIO_BLK_T_IN;
263 out_hdr.ioprio = 99;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200264 out_hdr.sector = virtio_sector_adjust(sector);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200265
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100266 vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200267
268 /* This is where we want to receive data */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100269 vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200270 VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
271 VRING_DESC_F_NEXT);
272
273 /* status field */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100274 vring_send_buf(vr, &status, sizeof(u8),
275 VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200276
277 /* Now we can tell the host to read */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100278 vring_wait_reply();
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200279
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100280 if (drain_irqs(vr->schid)) {
Cornelia Huck0f3f1f32013-04-26 02:12:54 +0000281 /* Well, whatever status is supposed to contain... */
282 status = 1;
283 }
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200284 return status;
285}
286
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100287int virtio_read_many(ulong sector, void *load_addr, int sec_num)
288{
289 switch (vdev.senseid.cu_model) {
290 case VIRTIO_ID_BLOCK:
291 return virtio_blk_read_many(&vdev, sector, load_addr, sec_num);
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100292 case VIRTIO_ID_SCSI:
293 return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num);
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100294 }
295 panic("\n! No readable IPL device !\n");
296 return -1;
297}
298
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200299unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +0200300 ulong subchan_id, void *load_addr)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200301{
302 u8 status;
303 int sec = rec_list1;
David Hildenbrand554f8082014-06-18 14:16:44 +0200304 int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200305 int sec_len = rec_list2 >> 48;
306 ulong addr = (ulong)load_addr;
307
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200308 if (sec_len != virtio_get_block_size()) {
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200309 return -1;
310 }
311
312 sclp_print(".");
Eugene (jno) Dvurechenskiabd696e2014-05-19 20:05:40 +0200313 status = virtio_read_many(sec, (void *)addr, sec_num);
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200314 if (status) {
Eugene (jno) Dvurechenskic9262e82015-09-17 12:47:27 +0200315 panic("I/O Error");
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200316 }
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200317 addr += sec_num * virtio_get_block_size();
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200318
319 return addr;
320}
321
322int virtio_read(ulong sector, void *load_addr)
323{
324 return virtio_read_many(sector, load_addr, 1);
325}
326
Eugene (jno) Dvurechenski00a47e72014-08-29 11:01:37 +0200327/*
328 * Other supported value pairs, if any, would need to be added here.
329 * Note: head count is always 15.
330 */
331static inline u8 virtio_eckd_sectors_for_block_size(int size)
332{
333 switch (size) {
334 case 512:
335 return 49;
336 case 1024:
337 return 33;
338 case 2048:
339 return 21;
340 case 4096:
341 return 12;
342 }
343 return 0;
344}
345
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100346VirtioGDN virtio_guessed_disk_nature(void)
347{
348 return vdev.guessed_disk_nature;
349}
350
351void virtio_assume_scsi(void)
352{
353 switch (vdev.senseid.cu_model) {
354 case VIRTIO_ID_BLOCK:
355 vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
356 vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
357 vdev.config.blk.physical_block_exp = 0;
358 vdev.blk_factor = 1;
359 break;
360 case VIRTIO_ID_SCSI:
361 vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
362 break;
363 }
364}
365
366void virtio_assume_iso9660(void)
367{
368 switch (vdev.senseid.cu_model) {
369 case VIRTIO_ID_BLOCK:
370 vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
371 vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
372 vdev.config.blk.physical_block_exp = 0;
373 vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
374 break;
375 case VIRTIO_ID_SCSI:
376 vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
377 break;
378 }
379}
380
381void virtio_assume_eckd(void)
382{
383 vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
384 vdev.blk_factor = 1;
385 vdev.config.blk.physical_block_exp = 0;
386 switch (vdev.senseid.cu_model) {
387 case VIRTIO_ID_BLOCK:
388 vdev.config.blk.blk_size = 4096;
389 break;
390 case VIRTIO_ID_SCSI:
391 vdev.config.blk.blk_size = vdev.scsi_block_size;
392 break;
393 }
394 vdev.config.blk.geometry.heads = 15;
395 vdev.config.blk.geometry.sectors =
396 virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size);
397}
398
399bool virtio_disk_is_scsi(void)
400{
401 if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
402 return true;
403 }
404 switch (vdev.senseid.cu_model) {
405 case VIRTIO_ID_BLOCK:
406 return (vdev.config.blk.geometry.heads == 255)
407 && (vdev.config.blk.geometry.sectors == 63)
408 && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
409 case VIRTIO_ID_SCSI:
410 return true;
411 }
412 return false;
413}
414
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200415bool virtio_disk_is_eckd(void)
416{
Eugene (jno) Dvurechenski00a47e72014-08-29 11:01:37 +0200417 const int block_size = virtio_get_block_size();
418
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100419 if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
420 return true;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200421 }
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100422 switch (vdev.senseid.cu_model) {
423 case VIRTIO_ID_BLOCK:
424 return (vdev.config.blk.geometry.heads == 15)
425 && (vdev.config.blk.geometry.sectors ==
426 virtio_eckd_sectors_for_block_size(block_size));
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100427 case VIRTIO_ID_SCSI:
428 return false;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100429 }
430 return false;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200431}
432
433bool virtio_ipl_disk_is_valid(void)
434{
Eugene (jno) Dvurechenski92cb0552014-08-29 11:01:36 +0200435 return virtio_disk_is_scsi() || virtio_disk_is_eckd();
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200436}
437
438int virtio_get_block_size(void)
439{
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100440 switch (vdev.senseid.cu_model) {
441 case VIRTIO_ID_BLOCK:
442 return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100443 case VIRTIO_ID_SCSI:
444 return vdev.scsi_block_size;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100445 }
446 return 0;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200447}
448
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200449uint8_t virtio_get_heads(void)
450{
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100451 switch (vdev.senseid.cu_model) {
452 case VIRTIO_ID_BLOCK:
453 return vdev.config.blk.geometry.heads;
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100454 case VIRTIO_ID_SCSI:
455 return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
456 ? vdev.config.blk.geometry.heads : 255;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100457 }
458 return 0;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200459}
460
461uint8_t virtio_get_sectors(void)
462{
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100463 switch (vdev.senseid.cu_model) {
464 case VIRTIO_ID_BLOCK:
465 return vdev.config.blk.geometry.sectors;
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100466 case VIRTIO_ID_SCSI:
467 return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
468 ? vdev.config.blk.geometry.sectors : 63;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100469 }
470 return 0;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200471}
472
Eugene (jno) Dvurechenskif04db282014-08-29 11:01:39 +0200473uint64_t virtio_get_blocks(void)
474{
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100475 const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100476 switch (vdev.senseid.cu_model) {
477 case VIRTIO_ID_BLOCK:
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100478 return vdev.config.blk.capacity / factor;
479 case VIRTIO_ID_SCSI:
480 return vdev.scsi_last_block / factor;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100481 }
482 return 0;
Eugene (jno) Dvurechenskif04db282014-08-29 11:01:39 +0200483}
484
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100485static void virtio_setup_ccw(VDev *vdev)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200486{
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100487 int i, cfg_size = 0;
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100488 unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200489
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100490 IPL_assert(virtio_is_supported(vdev->schid), "PE");
491 /* device ID has been established now */
492
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100493 vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100494 vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200495
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100496 run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
497
498 switch (vdev->senseid.cu_model) {
499 case VIRTIO_ID_BLOCK:
500 vdev->nr_vqs = 1;
501 vdev->cmd_vr_idx = 0;
502 cfg_size = sizeof(vdev->config.blk);
503 break;
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100504 case VIRTIO_ID_SCSI:
505 vdev->nr_vqs = 3;
506 vdev->cmd_vr_idx = VR_REQUEST;
507 cfg_size = sizeof(vdev->config.scsi);
508 break;
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100509 default:
510 panic("Unsupported virtio device\n");
511 }
512 IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100513 "Could not get block device configuration");
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200514
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200515 /*
516 * Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and
517 * we'll just stop dead anyway if anything does not work like we
518 * expect it.
519 */
520
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100521 for (i = 0; i < vdev->nr_vqs; i++) {
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100522 VqInfo info = {
523 .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
524 .align = KVM_S390_VIRTIO_RING_ALIGN,
525 .index = i,
526 .num = 0,
527 };
528 VqConfig config = {
529 .index = i,
530 .num = 0,
531 };
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200532
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100533 IPL_assert(
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100534 run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100535 "Could not get block device VQ configuration");
536 info.num = config.num;
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100537 vring_init(&vdev->vrings[i], &info);
538 vdev->vrings[i].schid = vdev->schid;
539 IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100540 "Cannot set VQ info");
Cornelia Huck0f3f1f32013-04-26 02:12:54 +0000541 }
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100542 IPL_assert(
543 run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0,
544 "Could not write status to host");
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100545}
546
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100547void virtio_setup_device(SubChannelId schid)
Eugene (jno) Dvurechenski85129892015-11-10 15:13:36 +0100548{
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100549 vdev.schid = schid;
550 virtio_setup_ccw(&vdev);
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200551
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100552 switch (vdev.senseid.cu_model) {
553 case VIRTIO_ID_BLOCK:
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100554 sclp_print("Using virtio-blk.\n");
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100555 if (!virtio_ipl_disk_is_valid()) {
556 /* make sure all getters but blocksize return 0 for
557 * invalid IPL disk
558 */
559 memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
560 virtio_assume_scsi();
561 }
562 break;
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100563 case VIRTIO_ID_SCSI:
564 IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
565 "Config: sense size mismatch");
566 IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
567 "Config: CDB size mismatch");
568
569 sclp_print("Using virtio-scsi.\n");
570 virtio_scsi_setup(&vdev);
571 break;
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100572 default:
573 panic("\n! No IPL device available !\n");
Eugene (jno) Dvurechenski91a03f92014-05-19 20:10:27 +0200574 }
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200575}
576
Eugene (jno) Dvurechenskia1102ce2015-10-26 16:55:16 +0100577bool virtio_is_supported(SubChannelId schid)
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200578{
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100579 vdev.schid = schid;
580 memset(&vdev.senseid, 0, sizeof(vdev.senseid));
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200581 /* run sense id command */
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100582 if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) {
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200583 return false;
584 }
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100585 if (vdev.senseid.cu_type == 0x3832) {
586 switch (vdev.senseid.cu_model) {
587 case VIRTIO_ID_BLOCK:
Eugene (jno) Dvurechenski80ba3e22015-11-10 15:37:22 +0100588 case VIRTIO_ID_SCSI:
Farhan Ali99b72e02016-11-01 17:34:00 -0400589 case VIRTIO_ID_NET:
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100590 return true;
591 }
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200592 }
Eugene (jno) Dvurechenski69429682015-10-26 15:47:24 +0100593 return false;
Alexander Graf1e17c2c2013-04-22 21:01:00 +0200594}
595
Dominik Dingelc8cda872013-06-17 14:29:42 +0200596int enable_mss_facility(void)
597{
598 int ret;
Eugene (jno) Dvurechenskib88d7fa2015-11-10 14:10:20 +0100599 ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
Dominik Dingelc8cda872013-06-17 14:29:42 +0200600
601 memset(sda_area, 0, PAGE_SIZE);
602 sda_area->request.length = 0x0400;
603 sda_area->request.code = 0x0031;
604 sda_area->operation_code = 0x2;
605
606 ret = chsc(sda_area);
607 if ((ret == 0) && (sda_area->response.code == 0x0001)) {
608 return 0;
609 }
610 return -EIO;
611}