]> Git Repo - qemu.git/blob - pc-bios/s390-ccw/virtio-blkdev.c
works with less than base ISA qemu-system-riscv32 -M virt -bios none -kernel output...
[qemu.git] / pc-bios / s390-ccw / virtio-blkdev.c
1 /*
2  * Virtio driver bits
3  *
4  * Copyright (c) 2013 Alexander Graf <[email protected]>
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
11 #include "libc.h"
12 #include "s390-ccw.h"
13 #include "virtio.h"
14 #include "virtio-scsi.h"
15
16 #define VIRTIO_BLK_F_GEOMETRY   (1 << 4)
17 #define VIRTIO_BLK_F_BLK_SIZE   (1 << 6)
18
19 static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
20                                 int sec_num)
21 {
22     VirtioBlkOuthdr out_hdr;
23     u8 status;
24     VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
25
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);
30
31     vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
32
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);
37
38     /* status field */
39     vring_send_buf(vr, &status, sizeof(u8),
40                    VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
41
42     /* Now we can tell the host to read */
43     vring_wait_reply();
44
45     if (drain_irqs(vr->schid)) {
46         /* Well, whatever status is supposed to contain... */
47         status = 1;
48     }
49     return status;
50 }
51
52 int virtio_read_many(ulong sector, void *load_addr, int sec_num)
53 {
54     VDev *vdev = virtio_get_device();
55
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);
61     }
62     panic("\n! No readable IPL device !\n");
63     return -1;
64 }
65
66 unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
67                                  ulong subchan_id, void *load_addr)
68 {
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;
74
75     if (sec_len != virtio_get_block_size()) {
76         return -1;
77     }
78
79     sclp_print(".");
80     status = virtio_read_many(sec, (void *)addr, sec_num);
81     if (status) {
82         panic("I/O Error");
83     }
84     addr += sec_num * virtio_get_block_size();
85
86     return addr;
87 }
88
89 int virtio_read(ulong sector, void *load_addr)
90 {
91     return virtio_read_many(sector, load_addr, 1);
92 }
93
94 /*
95  * Other supported value pairs, if any, would need to be added here.
96  * Note: head count is always 15.
97  */
98 static inline u8 virtio_eckd_sectors_for_block_size(int size)
99 {
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;
109     }
110     return 0;
111 }
112
113 VirtioGDN virtio_guessed_disk_nature(void)
114 {
115     return virtio_get_device()->guessed_disk_nature;
116 }
117
118 void virtio_assume_iso9660(void)
119 {
120     VDev *vdev = virtio_get_device();
121
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;
132     }
133 }
134
135 void virtio_assume_eckd(void)
136 {
137     VDev *vdev = virtio_get_device();
138
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;
149     }
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);
153 }
154
155 bool virtio_ipl_disk_is_valid(void)
156 {
157     int blksize = virtio_get_block_size();
158     VDev *vdev = virtio_get_device();
159
160     if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI ||
161         vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
162         return true;
163     }
164
165     return (vdev->senseid.cu_model == VIRTIO_ID_BLOCK ||
166             vdev->senseid.cu_model == VIRTIO_ID_SCSI) &&
167            blksize >= 512 && blksize <= 4096;
168 }
169
170 int virtio_get_block_size(void)
171 {
172     VDev *vdev = virtio_get_device();
173
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;
179     }
180     return 0;
181 }
182
183 uint8_t virtio_get_heads(void)
184 {
185     VDev *vdev = virtio_get_device();
186
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;
193     }
194     return 0;
195 }
196
197 uint8_t virtio_get_sectors(void)
198 {
199     VDev *vdev = virtio_get_device();
200
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;
207     }
208     return 0;
209 }
210
211 uint64_t virtio_get_blocks(void)
212 {
213     VDev *vdev = virtio_get_device();
214     const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
215
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;
221     }
222     return 0;
223 }
224
225 int virtio_blk_setup_device(SubChannelId schid)
226 {
227     VDev *vdev = virtio_get_device();
228
229     vdev->guest_features[0] = VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_BLK_SIZE;
230     vdev->schid = schid;
231     virtio_setup_ccw(vdev);
232
233     sclp_print("Using virtio-blk.\n");
234
235     return 0;
236 }
This page took 0.035201 seconds and 4 git commands to generate.