4 * Copyright IBM, Corp. 2007
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 #include "virtio-blk.h"
15 #include "block_int.h"
17 typedef struct VirtIOBlock
24 static VirtIOBlock
*to_virtio_blk(VirtIODevice
*vdev
)
26 return (VirtIOBlock
*)vdev
;
29 typedef struct VirtIOBlockReq
32 VirtQueueElement elem
;
33 struct virtio_blk_inhdr
*in
;
34 struct virtio_blk_outhdr
*out
;
39 static void virtio_blk_rw_complete(void *opaque
, int ret
)
41 VirtIOBlockReq
*req
= opaque
;
42 VirtIOBlock
*s
= req
->dev
;
44 /* Copy read data to the guest */
45 if (!ret
&& !(req
->out
->type
& VIRTIO_BLK_T_OUT
)) {
49 for (i
= 0; i
< req
->elem
.in_num
- 1; i
++) {
52 /* Be pretty defensive wrt malicious guests */
53 len
= MIN(req
->elem
.in_sg
[i
].iov_len
,
56 memcpy(req
->elem
.in_sg
[i
].iov_base
,
63 req
->in
->status
= ret
? VIRTIO_BLK_S_IOERR
: VIRTIO_BLK_S_OK
;
64 virtqueue_push(s
->vq
, &req
->elem
, req
->size
+ sizeof(*req
->in
));
65 virtio_notify(&s
->vdev
, s
->vq
);
67 qemu_free(req
->buffer
);
71 static VirtIOBlockReq
*virtio_blk_get_request(VirtIOBlock
*s
)
75 req
= qemu_mallocz(sizeof(*req
));
80 if (!virtqueue_pop(s
->vq
, &req
->elem
)) {
88 static void virtio_blk_handle_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
90 VirtIOBlock
*s
= to_virtio_blk(vdev
);
93 while ((req
= virtio_blk_get_request(s
))) {
96 if (req
->elem
.out_num
< 1 || req
->elem
.in_num
< 1) {
97 fprintf(stderr
, "virtio-blk missing headers\n");
101 if (req
->elem
.out_sg
[0].iov_len
< sizeof(*req
->out
) ||
102 req
->elem
.in_sg
[req
->elem
.in_num
- 1].iov_len
< sizeof(*req
->in
)) {
103 fprintf(stderr
, "virtio-blk header not in correct element\n");
107 req
->out
= (void *)req
->elem
.out_sg
[0].iov_base
;
108 req
->in
= (void *)req
->elem
.in_sg
[req
->elem
.in_num
- 1].iov_base
;
110 if (req
->out
->type
& VIRTIO_BLK_T_SCSI_CMD
) {
111 unsigned int len
= sizeof(*req
->in
);
113 req
->in
->status
= VIRTIO_BLK_S_UNSUPP
;
114 virtqueue_push(vq
, &req
->elem
, len
);
115 virtio_notify(vdev
, vq
);
117 } else if (req
->out
->type
& VIRTIO_BLK_T_OUT
) {
120 for (i
= 1; i
< req
->elem
.out_num
; i
++)
121 req
->size
+= req
->elem
.out_sg
[i
].iov_len
;
123 req
->buffer
= qemu_memalign(512, req
->size
);
124 if (req
->buffer
== NULL
) {
129 /* We copy the data from the SG list to avoid splitting up the request. This helps
130 performance a lot until we can pass full sg lists as AIO operations */
132 for (i
= 1; i
< req
->elem
.out_num
; i
++) {
135 len
= MIN(req
->elem
.out_sg
[i
].iov_len
,
137 memcpy(req
->buffer
+ offset
,
138 req
->elem
.out_sg
[i
].iov_base
,
143 bdrv_aio_write(s
->bs
, req
->out
->sector
,
146 virtio_blk_rw_complete
,
149 for (i
= 0; i
< req
->elem
.in_num
- 1; i
++)
150 req
->size
+= req
->elem
.in_sg
[i
].iov_len
;
152 req
->buffer
= qemu_memalign(512, req
->size
);
153 if (req
->buffer
== NULL
) {
158 bdrv_aio_read(s
->bs
, req
->out
->sector
,
161 virtio_blk_rw_complete
,
166 * FIXME: Want to check for completions before returning to guest mode,
167 * so cached reads and writes are reported as quickly as possible. But
168 * that should be done in the generic block layer.
172 static void virtio_blk_reset(VirtIODevice
*vdev
)
175 * This should cancel pending requests, but can't do nicely until there
176 * are per-device request lists.
181 static void virtio_blk_update_config(VirtIODevice
*vdev
, uint8_t *config
)
183 VirtIOBlock
*s
= to_virtio_blk(vdev
);
184 struct virtio_blk_config blkcfg
;
186 int cylinders
, heads
, secs
;
188 bdrv_get_geometry(s
->bs
, &capacity
);
189 bdrv_get_geometry_hint(s
->bs
, &cylinders
, &heads
, &secs
);
190 stq_raw(&blkcfg
.capacity
, capacity
);
191 stl_raw(&blkcfg
.seg_max
, 128 - 2);
192 stw_raw(&blkcfg
.cylinders
, cylinders
);
193 blkcfg
.heads
= heads
;
194 blkcfg
.sectors
= secs
;
195 memcpy(config
, &blkcfg
, sizeof(blkcfg
));
198 static uint32_t virtio_blk_get_features(VirtIODevice
*vdev
)
200 return (1 << VIRTIO_BLK_F_SEG_MAX
| 1 << VIRTIO_BLK_F_GEOMETRY
);
203 static void virtio_blk_save(QEMUFile
*f
, void *opaque
)
205 VirtIOBlock
*s
= opaque
;
206 virtio_save(&s
->vdev
, f
);
209 static int virtio_blk_load(QEMUFile
*f
, void *opaque
, int version_id
)
211 VirtIOBlock
*s
= opaque
;
216 virtio_load(&s
->vdev
, f
);
221 void *virtio_blk_init(PCIBus
*bus
, BlockDriverState
*bs
)
224 int cylinders
, heads
, secs
;
225 static int virtio_blk_id
;
227 s
= (VirtIOBlock
*)virtio_init_pci(bus
, "virtio-blk",
228 PCI_VENDOR_ID_REDHAT_QUMRANET
,
229 PCI_DEVICE_ID_VIRTIO_BLOCK
,
232 sizeof(struct virtio_blk_config
), sizeof(VirtIOBlock
));
236 s
->vdev
.get_config
= virtio_blk_update_config
;
237 s
->vdev
.get_features
= virtio_blk_get_features
;
238 s
->vdev
.reset
= virtio_blk_reset
;
240 bdrv_guess_geometry(s
->bs
, &cylinders
, &heads
, &secs
);
241 bdrv_set_geometry_hint(s
->bs
, cylinders
, heads
, secs
);
243 s
->vq
= virtio_add_queue(&s
->vdev
, 128, virtio_blk_handle_output
);
245 register_savevm("virtio-blk", virtio_blk_id
++, 1,
246 virtio_blk_save
, virtio_blk_load
, s
);