5 #include <qemu-common.h>
7 #include "qemu-vio-blk.h"
14 extern unsigned long int num_reads
;
15 extern unsigned long int num_writes
;
16 extern unsigned long int num_scsi_cmds
;
17 extern unsigned long int num_flushs
;
18 extern unsigned long int bytes_wrote
;
19 extern unsigned long int bytes_read
;
21 //#define trace() printf("qemu-vio-blk: %s-%s: %s(%d)\n",__TIME__, __FILE__,__func__, __LINE__)
24 static void qemu_vio_blk_req_complete(VirtIOBlockReq
*req
, int status
)
27 if (req
->out
->type
& VIRTIO_BLK_T_FLUSH
) {
28 bytes_wrote
+=req
->qiov
.size
;
29 } else if (req
->out
->type
& VIRTIO_BLK_T_SCSI_CMD
) {
30 bytes_wrote
+=req
->qiov
.size
;
31 } else if (req
->out
->type
& VIRTIO_BLK_T_OUT
) {
32 bytes_wrote
+=req
->qiov
.size
;
34 bytes_read
+=req
->qiov
.size
;
37 VirtIOBlock
*s
= req
->dev
;
39 req
->in
->status
= status
;
40 virtqueue_push(s
->vq
, &req
->elem
, req
->qiov
.size
+ sizeof(*req
->in
));
46 static void qemu_vio_blk_flush_complete(void *opaque
, int ret
)
48 VirtIOBlockReq
*req
= opaque
;
50 qemu_vio_blk_req_complete(req
, ret
? VIRTIO_BLK_S_IOERR
: VIRTIO_BLK_S_OK
);
54 static void qemu_vio_blk_handle_scsi(VirtIOBlockReq
*req
)
62 * We require at least one output segment each for the virtio_blk_outhdr
63 * and the SCSI command block.
65 * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
66 * and the sense buffer pointer in the input segments.
68 if (req
->elem
.out_num
< 2 || req
->elem
.in_num
< 3) {
69 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_IOERR
);
74 * No support for bidirection commands yet.
76 if (req
->elem
.out_num
> 2 && req
->elem
.in_num
> 3) {
77 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_UNSUPP
);
82 * The scsi inhdr is placed in the second-to-last input segment, just
83 * before the regular inhdr.
85 req
->scsi
= (void *)req
->elem
.in_sg
[req
->elem
.in_num
- 2].iov_base
;
86 size
= sizeof(*req
->in
) + sizeof(*req
->scsi
);
88 memset(&hdr
, 0, sizeof(struct sg_io_hdr
));
89 hdr
.interface_id
= 'S';
90 hdr
.cmd_len
= req
->elem
.out_sg
[1].iov_len
;
91 hdr
.cmdp
= req
->elem
.out_sg
[1].iov_base
;
94 if (req
->elem
.out_num
> 2) {
96 * If there are more than the minimally required 2 output segments
97 * there is write payload starting from the third iovec.
99 hdr
.dxfer_direction
= SG_DXFER_TO_DEV
;
100 hdr
.iovec_count
= req
->elem
.out_num
- 2;
102 for (i
= 0; i
< hdr
.iovec_count
; i
++)
103 hdr
.dxfer_len
+= req
->elem
.out_sg
[i
+ 2].iov_len
;
105 hdr
.dxferp
= req
->elem
.out_sg
+ 2;
107 } else if (req
->elem
.in_num
> 3) {
109 * If we have more than 3 input segments the guest wants to actually
112 hdr
.dxfer_direction
= SG_DXFER_FROM_DEV
;
113 hdr
.iovec_count
= req
->elem
.in_num
- 3;
114 for (i
= 0; i
< hdr
.iovec_count
; i
++)
115 hdr
.dxfer_len
+= req
->elem
.in_sg
[i
].iov_len
;
117 hdr
.dxferp
= req
->elem
.in_sg
;
118 size
+= hdr
.dxfer_len
;
121 * Some SCSI commands don't actually transfer any data.
123 hdr
.dxfer_direction
= SG_DXFER_NONE
;
126 hdr
.sbp
= req
->elem
.in_sg
[req
->elem
.in_num
- 3].iov_base
;
127 hdr
.mx_sb_len
= req
->elem
.in_sg
[req
->elem
.in_num
- 3].iov_len
;
128 size
+= hdr
.mx_sb_len
;
130 ret
= bdrv_ioctl(req
->dev
->bs
, SG_IO
, &hdr
);
132 status
= VIRTIO_BLK_S_UNSUPP
;
134 hdr
.resid
= hdr
.dxfer_len
;
135 } else if (hdr
.status
) {
136 status
= VIRTIO_BLK_S_IOERR
;
138 status
= VIRTIO_BLK_S_OK
;
141 req
->scsi
->errors
= hdr
.status
;
142 req
->scsi
->residual
= hdr
.resid
;
143 req
->scsi
->sense_len
= hdr
.sb_len_wr
;
144 req
->scsi
->data_len
= hdr
.dxfer_len
;
146 qemu_vio_blk_req_complete(req
, status
);
149 static void qemu_vio_blk_handle_scsi(VirtIOBlockReq
*req
)
151 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_UNSUPP
);
153 #endif /* __linux__ */
155 BlockErrorAction
drive_get_on_error(
156 BlockDriverState
*bdrv
, int is_read
)
162 QTAILQ_FOREACH(dinfo, &drives, next) {
163 if (dinfo->bdrv == bdrv)
164 return is_read ? dinfo->on_read_error : dinfo->on_write_error;
167 return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC;
169 return BLOCK_ERR_REPORT
;
172 static void q_vm_stop(int reason
)
178 static int qemu_vio_blk_handle_rw_error(VirtIOBlockReq
*req
, int error
,
182 BlockErrorAction action
=
183 drive_get_on_error(req
->dev
->bs
, is_read
);
184 VirtIOBlock
*s
= req
->dev
;
187 if (action
== BLOCK_ERR_IGNORE
)
190 if ((error
== ENOSPC
&& action
== BLOCK_ERR_STOP_ENOSPC
)
191 || action
== BLOCK_ERR_STOP_ANY
) {
197 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_IOERR
);
205 static void qemu_vio_blk_rw_complete(void *opaque
, int ret
)
207 VirtIOBlockReq
*req
= opaque
;
213 int is_read
= !(req
->out
->type
& VIRTIO_BLK_T_OUT
);
215 if (qemu_vio_blk_handle_rw_error(req
, -ret
, is_read
))
219 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_OK
);
222 void do_multiwrite(BlockDriverState
*bs
, BlockRequest
*blkreq
,
228 for (i
= 0; i
< num_writes
; i
++) {
230 ret
= bdrv_write(bs
,blkreq
[i
].sector
,blkreq
[i
].qiov
->iov
->iov_base
,blkreq
[i
].nb_sectors
);
231 blkreq
[i
].cb(blkreq
[i
].opaque
,ret
);
236 //FIX: How to use bdrv_aio_multiwrite inside qemu-vio?
237 ret
= bdrv_aio_multiwrite(bs
, blkreq
, num_writes
);
241 for (i
= 0; i
< num_writes
; i
++) {
242 if (blkreq
[i
].error
) {
243 qemu_vio_blk_rw_complete(blkreq
[i
].opaque
, -EIO
);
249 static void qemu_vio_blk_handle_write(BlockRequest
*blkreq
, int *num_writes
,
250 VirtIOBlockReq
*req
, BlockDriverState
**old_bs
)
253 if (req
->dev
->bs
!= *old_bs
|| *num_writes
== 32) {
254 if (*old_bs
!= NULL
) {
255 do_multiwrite(*old_bs
, blkreq
, *num_writes
);
258 *old_bs
= req
->dev
->bs
;
262 blkreq
[*num_writes
].sector
= req
->out
->sector
;
263 blkreq
[*num_writes
].nb_sectors
= req
->qiov
.size
/ 512;
264 blkreq
[*num_writes
].qiov
= &req
->qiov
;
265 blkreq
[*num_writes
].cb
= qemu_vio_blk_rw_complete
;
266 blkreq
[*num_writes
].opaque
= req
;
267 blkreq
[*num_writes
].error
= 0;
272 static void qemu_vio_blk_handle_read(VirtIOBlockReq
*req
)
274 BlockDriverAIOCB
*acb
;
277 req
->in
->status
= WAITING_ASYNC_RET
;
279 acb
= bdrv_aio_readv(req
->dev
->bs
, req
->out
->sector
, &req
->qiov
,
280 req
->qiov
.size
/ 512, qemu_vio_blk_rw_complete
, req
);
284 qemu_vio_blk_rw_complete(req
, -EIO
);
288 while (req
->in
->status
== WAITING_ASYNC_RET
)
295 static void qemu_vio_blk_handle_flush(BlockRequest
*blkreq
, int *num_writes
,
296 VirtIOBlockReq
*req
, BlockDriverState
**old_bs
)
298 BlockDriverAIOCB
*acb
;
301 * Make sure all outstanding writes are posted to the backing device.
303 if (*old_bs
!= NULL
) {
305 do_multiwrite(*old_bs
, blkreq
, *num_writes
);
308 *old_bs
= req
->dev
->bs
;
310 acb
= bdrv_aio_flush(req
->dev
->bs
, qemu_vio_blk_flush_complete
, req
);
312 qemu_vio_blk_req_complete(req
, VIRTIO_BLK_S_IOERR
);
316 VirtIOBlockReq
*virtio_blk_get_request(VirtIOBlock
*s
)
319 VirtIOBlockReq
*req
= malloc(sizeof(VirtIOBlockReq
));
323 bzero(req
,sizeof(VirtIOBlockReq
));
326 req
->dev
->bs
= s
->bs
;
329 if (!virtqueue_pop(s
->vq
, &req
->elem
)) {
339 void virtio_blk_handle_request(VirtIOBlockReq
*req
,
344 if (req
->elem
.out_num
< 1 || req
->elem
.in_num
< 1) {
345 fprintf(stderr
, "qemu-vio-blk: missing headers\n");
349 if (req
->elem
.out_sg
[0].iov_len
< sizeof(*req
->out
) ||
350 req
->elem
.in_sg
[req
->elem
.in_num
- 1].iov_len
< sizeof(*req
->in
)) {
351 fprintf(stderr
, "qemu-vio-blk: header not in correct element\n");
355 req
->out
= (void *)req
->elem
.out_sg
[0].iov_base
;
356 req
->in
= (void *)req
->elem
.in_sg
[req
->elem
.in_num
- 1].iov_base
;
358 if (req
->out
->type
& VIRTIO_BLK_T_FLUSH
) {
360 qemu_vio_blk_handle_flush(mrb
->blkreq
, &mrb
->num_writes
,
362 } else if (req
->out
->type
& VIRTIO_BLK_T_SCSI_CMD
) {
364 qemu_vio_blk_handle_scsi(req
);
365 } else if (req
->out
->type
& VIRTIO_BLK_T_OUT
) {
367 qemu_iovec_init_external(&req
->qiov
, &req
->elem
.out_sg
[1],
368 req
->elem
.out_num
- 1);
369 qemu_vio_blk_handle_write(mrb
->blkreq
, &mrb
->num_writes
,
373 qemu_iovec_init_external(&req
->qiov
, &req
->elem
.in_sg
[0],
374 req
->elem
.in_num
- 1);
375 qemu_vio_blk_handle_read(req
);
379 void qemu_vio_guess_geometry(BlockDriverState
*bs
, int *pcyls
, int *pheads
, int *psecs
)
381 bdrv_guess_geometry(bs
, pcyls
, pheads
, psecs
);
384 int64_t qemu_vio_getlength(BlockDriverState
*bs
)
386 return bdrv_getlength(bs
) / 512;