Asynchronous reads added
[qemu/ovp.git] / qemu-vio-blk.c
blob709bd6e6c78206f3c54a4a16b179fa1a28aa1c11
1 #include <stdio.h>
2 #include <stdint.h>
5 #include <qemu-common.h>
6 #include <sysemu.h>
7 #include "qemu-vio-blk.h"
8 #include "block_int.h"
9 #ifdef __linux__
10 # include <scsi/sg.h>
11 #endif
13 char *progname;
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__)
22 #define trace() ;
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;
33 } else {
34 bytes_read+=req->qiov.size;
37 VirtIOBlock *s = req->dev;
38 trace();
39 req->in->status = status;
40 virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
42 if (req)
43 free(req);
46 static void qemu_vio_blk_flush_complete(void *opaque, int ret)
48 VirtIOBlockReq *req = opaque;
49 trace();
50 qemu_vio_blk_req_complete(req, ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK);
53 #ifdef __linux__
54 static void qemu_vio_blk_handle_scsi(VirtIOBlockReq *req)
56 struct sg_io_hdr hdr;
57 int ret, size = 0;
58 int status;
59 int i;
60 trace();
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);
70 return;
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);
78 return;
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;
92 hdr.dxfer_len = 0;
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
110 * read data.
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;
119 } else {
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);
131 if (ret) {
132 status = VIRTIO_BLK_S_UNSUPP;
133 hdr.status = ret;
134 hdr.resid = hdr.dxfer_len;
135 } else if (hdr.status) {
136 status = VIRTIO_BLK_S_IOERR;
137 } else {
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);
148 #else
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)
158 trace();
160 DriveInfo *dinfo;
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)
174 trace();
178 static int qemu_vio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
179 int is_read)
181 trace();
182 BlockErrorAction action =
183 drive_get_on_error(req->dev->bs, is_read);
184 VirtIOBlock *s = req->dev;
187 if (action == BLOCK_ERR_IGNORE)
188 return 0;
190 if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
191 || action == BLOCK_ERR_STOP_ANY) {
192 req->next = s->rq;
193 s->rq = req;
194 q_vm_stop(0);
195 } else {
197 qemu_vio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
202 return 1;
205 static void qemu_vio_blk_rw_complete(void *opaque, int ret)
207 VirtIOBlockReq *req = opaque;
208 trace();
211 if (ret) {
213 int is_read = !(req->out->type & VIRTIO_BLK_T_OUT);
215 if (qemu_vio_blk_handle_rw_error(req, -ret, is_read))
216 return;
219 qemu_vio_blk_req_complete(req, VIRTIO_BLK_S_OK);
222 void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
223 int num_writes)
225 int i, ret;
226 trace();
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);
234 return;
236 //FIX: How to use bdrv_aio_multiwrite inside qemu-vio?
237 ret = bdrv_aio_multiwrite(bs, blkreq, num_writes);
239 trace();
240 if (ret != 0) {
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)
252 trace();
253 if (req->dev->bs != *old_bs || *num_writes == 32) {
254 if (*old_bs != NULL) {
255 do_multiwrite(*old_bs, blkreq, *num_writes);
257 *num_writes = 0;
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;
269 (*num_writes)++;
272 static void qemu_vio_blk_handle_read(VirtIOBlockReq *req)
274 BlockDriverAIOCB *acb;
276 trace();
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);
282 trace();
283 if (!acb) {
284 qemu_vio_blk_rw_complete(req, -EIO);
287 trace();
288 while (req->in->status == WAITING_ASYNC_RET)
289 qemu_aio_wait();
291 trace();
292 return;
295 static void qemu_vio_blk_handle_flush(BlockRequest *blkreq, int *num_writes,
296 VirtIOBlockReq *req, BlockDriverState **old_bs)
298 BlockDriverAIOCB *acb;
299 trace();
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);
307 *num_writes = 0;
308 *old_bs = req->dev->bs;
310 acb = bdrv_aio_flush(req->dev->bs, qemu_vio_blk_flush_complete, req);
311 if (!acb) {
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));
321 trace();
323 bzero(req,sizeof(VirtIOBlockReq));
325 req->dev = s;
326 req->dev->bs = s->bs;
328 if (req != NULL) {
329 if (!virtqueue_pop(s->vq, &req->elem)) {
330 free(req);
331 return NULL;
335 return req;
339 void virtio_blk_handle_request(VirtIOBlockReq *req,
340 MultiReqBuffer *mrb)
343 trace();
344 if (req->elem.out_num < 1 || req->elem.in_num < 1) {
345 fprintf(stderr, "qemu-vio-blk: missing headers\n");
346 exit(1);
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");
352 exit(1);
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) {
359 num_flushs++;
360 qemu_vio_blk_handle_flush(mrb->blkreq, &mrb->num_writes,
361 req, &mrb->old_bs);
362 } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
363 num_scsi_cmds++;
364 qemu_vio_blk_handle_scsi(req);
365 } else if (req->out->type & VIRTIO_BLK_T_OUT) {
366 num_writes++;
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,
370 req, &mrb->old_bs);
371 } else {
372 num_reads++;
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;