tests/avocado: add RISC-V OpenSBI boot test
[qemu.git] / pc-bios / s390-ccw / virtio-blkdev.c
blob794f99b42c22910dab00984170171c16303c4ea8
1 /*
2 * Virtio driver bits
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
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 */
11 #include "libc.h"
12 #include "s390-ccw.h"
13 #include "virtio.h"
14 #include "virtio-scsi.h"
16 #define VIRTIO_BLK_F_GEOMETRY (1 << 4)
17 #define VIRTIO_BLK_F_BLK_SIZE (1 << 6)
19 static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
20 int sec_num)
22 VirtioBlkOuthdr out_hdr;
23 u8 status;
24 VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
26 /* Tell the host we want to read */
27 out_hdr.type = VIRTIO_BLK_T_IN;
28 out_hdr.ioprio = 99;
29 out_hdr.sector = virtio_sector_adjust(sector);
31 vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
33 /* This is where we want to receive data */
34 vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
35 VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
36 VRING_DESC_F_NEXT);
38 /* status field */
39 vring_send_buf(vr, &status, sizeof(u8),
40 VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
42 /* Now we can tell the host to read */
43 vring_wait_reply();
45 if (drain_irqs(vr->schid)) {
46 /* Well, whatever status is supposed to contain... */
47 status = 1;
49 return status;
52 int virtio_read_many(ulong sector, void *load_addr, int sec_num)
54 VDev *vdev = virtio_get_device();
56 switch (vdev->senseid.cu_model) {
57 case VIRTIO_ID_BLOCK:
58 return virtio_blk_read_many(vdev, sector, load_addr, sec_num);
59 case VIRTIO_ID_SCSI:
60 return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
62 panic("\n! No readable IPL device !\n");
63 return -1;
66 unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
67 ulong subchan_id, void *load_addr)
69 u8 status;
70 int sec = rec_list1;
71 int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
72 int sec_len = rec_list2 >> 48;
73 ulong addr = (ulong)load_addr;
75 if (sec_len != virtio_get_block_size()) {
76 return -1;
79 sclp_print(".");
80 status = virtio_read_many(sec, (void *)addr, sec_num);
81 if (status) {
82 panic("I/O Error");
84 addr += sec_num * virtio_get_block_size();
86 return addr;
89 int virtio_read(ulong sector, void *load_addr)
91 return virtio_read_many(sector, load_addr, 1);
95 * Other supported value pairs, if any, would need to be added here.
96 * Note: head count is always 15.
98 static inline u8 virtio_eckd_sectors_for_block_size(int size)
100 switch (size) {
101 case 512:
102 return 49;
103 case 1024:
104 return 33;
105 case 2048:
106 return 21;
107 case 4096:
108 return 12;
110 return 0;
113 VirtioGDN virtio_guessed_disk_nature(void)
115 return virtio_get_device()->guessed_disk_nature;
118 void virtio_assume_iso9660(void)
120 VDev *vdev = virtio_get_device();
122 switch (vdev->senseid.cu_model) {
123 case VIRTIO_ID_BLOCK:
124 vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
125 vdev->config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
126 vdev->config.blk.physical_block_exp = 0;
127 vdev->blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
128 break;
129 case VIRTIO_ID_SCSI:
130 vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
131 break;
135 void virtio_assume_eckd(void)
137 VDev *vdev = virtio_get_device();
139 vdev->guessed_disk_nature = VIRTIO_GDN_DASD;
140 vdev->blk_factor = 1;
141 vdev->config.blk.physical_block_exp = 0;
142 switch (vdev->senseid.cu_model) {
143 case VIRTIO_ID_BLOCK:
144 vdev->config.blk.blk_size = VIRTIO_DASD_DEFAULT_BLOCK_SIZE;
145 break;
146 case VIRTIO_ID_SCSI:
147 vdev->config.blk.blk_size = vdev->scsi_block_size;
148 break;
150 vdev->config.blk.geometry.heads = 15;
151 vdev->config.blk.geometry.sectors =
152 virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
155 bool virtio_ipl_disk_is_valid(void)
157 int blksize = virtio_get_block_size();
158 VDev *vdev = virtio_get_device();
160 if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI ||
161 vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
162 return true;
165 return (vdev->senseid.cu_model == VIRTIO_ID_BLOCK ||
166 vdev->senseid.cu_model == VIRTIO_ID_SCSI) &&
167 blksize >= 512 && blksize <= 4096;
170 int virtio_get_block_size(void)
172 VDev *vdev = virtio_get_device();
174 switch (vdev->senseid.cu_model) {
175 case VIRTIO_ID_BLOCK:
176 return vdev->config.blk.blk_size;
177 case VIRTIO_ID_SCSI:
178 return vdev->scsi_block_size;
180 return 0;
183 uint8_t virtio_get_heads(void)
185 VDev *vdev = virtio_get_device();
187 switch (vdev->senseid.cu_model) {
188 case VIRTIO_ID_BLOCK:
189 return vdev->config.blk.geometry.heads;
190 case VIRTIO_ID_SCSI:
191 return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
192 ? vdev->config.blk.geometry.heads : 255;
194 return 0;
197 uint8_t virtio_get_sectors(void)
199 VDev *vdev = virtio_get_device();
201 switch (vdev->senseid.cu_model) {
202 case VIRTIO_ID_BLOCK:
203 return vdev->config.blk.geometry.sectors;
204 case VIRTIO_ID_SCSI:
205 return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
206 ? vdev->config.blk.geometry.sectors : 63;
208 return 0;
211 uint64_t virtio_get_blocks(void)
213 VDev *vdev = virtio_get_device();
214 const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
216 switch (vdev->senseid.cu_model) {
217 case VIRTIO_ID_BLOCK:
218 return vdev->config.blk.capacity / factor;
219 case VIRTIO_ID_SCSI:
220 return vdev->scsi_last_block / factor;
222 return 0;
225 int virtio_blk_setup_device(SubChannelId schid)
227 VDev *vdev = virtio_get_device();
229 vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
230 vdev->schid = schid;
231 virtio_setup_ccw(vdev);
233 sclp_print("Using virtio-blk.\n");
235 return 0;