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
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,
22 VirtioBlkOuthdr out_hdr;
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;
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 |
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 */
45 if (drain_irqs(vr->schid)) {
46 /* Well, whatever status is supposed to contain... */
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) {
58 return virtio_blk_read_many(vdev, sector, load_addr, sec_num);
60 return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
62 panic("\n! No readable IPL device !\n");
66 unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
67 ulong subchan_id, void *load_addr)
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()) {
80 status = virtio_read_many(sec, (void *)addr, sec_num);
84 addr += sec_num * virtio_get_block_size();
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)
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;
130 vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
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;
147 vdev->config.blk.blk_size = vdev->scsi_block_size;
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) {
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;
178 return vdev->scsi_block_size;
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;
191 return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
192 ? vdev->config.blk.geometry.heads : 255;
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;
205 return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
206 ? vdev->config.blk.geometry.sectors : 63;
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;
220 return vdev->scsi_last_block / factor;
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;
231 virtio_setup_ccw(vdev);
233 sclp_print("Using virtio-blk.\n");