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