Statistics
| Branch: | Revision:

root / hw / virtio-blk.c @ d9f75a4e

History | View | Annotate | Download (7.3 kB)

1 6e02c38d aliguori
/*
2 6e02c38d aliguori
 * Virtio Block Device
3 6e02c38d aliguori
 *
4 6e02c38d aliguori
 * Copyright IBM, Corp. 2007
5 6e02c38d aliguori
 *
6 6e02c38d aliguori
 * Authors:
7 6e02c38d aliguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 6e02c38d aliguori
 *
9 6e02c38d aliguori
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 6e02c38d aliguori
 * the COPYING file in the top-level directory.
11 6e02c38d aliguori
 *
12 6e02c38d aliguori
 */
13 6e02c38d aliguori
14 869a5c6d aliguori
#include <qemu-common.h>
15 869a5c6d aliguori
#include <sysemu.h>
16 6e02c38d aliguori
#include "virtio-blk.h"
17 6e02c38d aliguori
#include "block_int.h"
18 6e02c38d aliguori
19 6e02c38d aliguori
typedef struct VirtIOBlock
20 6e02c38d aliguori
{
21 6e02c38d aliguori
    VirtIODevice vdev;
22 6e02c38d aliguori
    BlockDriverState *bs;
23 6e02c38d aliguori
    VirtQueue *vq;
24 869a5c6d aliguori
    void *rq;
25 6e02c38d aliguori
} VirtIOBlock;
26 6e02c38d aliguori
27 6e02c38d aliguori
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
28 6e02c38d aliguori
{
29 6e02c38d aliguori
    return (VirtIOBlock *)vdev;
30 6e02c38d aliguori
}
31 6e02c38d aliguori
32 6e02c38d aliguori
typedef struct VirtIOBlockReq
33 6e02c38d aliguori
{
34 6e02c38d aliguori
    VirtIOBlock *dev;
35 6e02c38d aliguori
    VirtQueueElement elem;
36 6e02c38d aliguori
    struct virtio_blk_inhdr *in;
37 6e02c38d aliguori
    struct virtio_blk_outhdr *out;
38 d28a1b6e aliguori
    QEMUIOVector qiov;
39 869a5c6d aliguori
    struct VirtIOBlockReq *next;
40 6e02c38d aliguori
} VirtIOBlockReq;
41 6e02c38d aliguori
42 869a5c6d aliguori
static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
43 869a5c6d aliguori
{
44 869a5c6d aliguori
    VirtIOBlock *s = req->dev;
45 869a5c6d aliguori
46 869a5c6d aliguori
    req->in->status = status;
47 d28a1b6e aliguori
    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
48 869a5c6d aliguori
    virtio_notify(&s->vdev, s->vq);
49 869a5c6d aliguori
50 869a5c6d aliguori
    qemu_free(req);
51 869a5c6d aliguori
}
52 869a5c6d aliguori
53 869a5c6d aliguori
static int virtio_blk_handle_write_error(VirtIOBlockReq *req, int error)
54 869a5c6d aliguori
{
55 869a5c6d aliguori
    BlockInterfaceErrorAction action = drive_get_onerror(req->dev->bs);
56 869a5c6d aliguori
    VirtIOBlock *s = req->dev;
57 869a5c6d aliguori
58 869a5c6d aliguori
    if (action == BLOCK_ERR_IGNORE)
59 869a5c6d aliguori
        return 0;
60 869a5c6d aliguori
61 869a5c6d aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
62 869a5c6d aliguori
            || action == BLOCK_ERR_STOP_ANY) {
63 869a5c6d aliguori
        req->next = s->rq;
64 869a5c6d aliguori
        s->rq = req;
65 869a5c6d aliguori
        vm_stop(0);
66 869a5c6d aliguori
    } else {
67 869a5c6d aliguori
        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
68 869a5c6d aliguori
    }
69 869a5c6d aliguori
70 869a5c6d aliguori
    return 1;
71 869a5c6d aliguori
}
72 869a5c6d aliguori
73 6e02c38d aliguori
static void virtio_blk_rw_complete(void *opaque, int ret)
74 6e02c38d aliguori
{
75 6e02c38d aliguori
    VirtIOBlockReq *req = opaque;
76 6e02c38d aliguori
77 d28a1b6e aliguori
    if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
78 869a5c6d aliguori
        if (virtio_blk_handle_write_error(req, -ret))
79 869a5c6d aliguori
            return;
80 6e02c38d aliguori
    }
81 6e02c38d aliguori
82 869a5c6d aliguori
    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
83 869a5c6d aliguori
}
84 6e02c38d aliguori
85 869a5c6d aliguori
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
86 869a5c6d aliguori
{
87 869a5c6d aliguori
    VirtIOBlockReq *req = qemu_mallocz(sizeof(*req));
88 487414f1 aliguori
    req->dev = s;
89 869a5c6d aliguori
    return req;
90 6e02c38d aliguori
}
91 6e02c38d aliguori
92 6e02c38d aliguori
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
93 6e02c38d aliguori
{
94 869a5c6d aliguori
    VirtIOBlockReq *req = virtio_blk_alloc_request(s);
95 6e02c38d aliguori
96 869a5c6d aliguori
    if (req != NULL) {
97 869a5c6d aliguori
        if (!virtqueue_pop(s->vq, &req->elem)) {
98 869a5c6d aliguori
            qemu_free(req);
99 869a5c6d aliguori
            return NULL;
100 869a5c6d aliguori
        }
101 6e02c38d aliguori
    }
102 6e02c38d aliguori
103 6e02c38d aliguori
    return req;
104 6e02c38d aliguori
}
105 6e02c38d aliguori
106 d28a1b6e aliguori
static void virtio_blk_handle_write(VirtIOBlockReq *req)
107 869a5c6d aliguori
{
108 d28a1b6e aliguori
    bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
109 d28a1b6e aliguori
                    req->qiov.size / 512, virtio_blk_rw_complete, req);
110 d28a1b6e aliguori
}
111 869a5c6d aliguori
112 d28a1b6e aliguori
static void virtio_blk_handle_read(VirtIOBlockReq *req)
113 d28a1b6e aliguori
{
114 d28a1b6e aliguori
    bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
115 d28a1b6e aliguori
                   req->qiov.size / 512, virtio_blk_rw_complete, req);
116 869a5c6d aliguori
}
117 869a5c6d aliguori
118 6e02c38d aliguori
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
119 6e02c38d aliguori
{
120 6e02c38d aliguori
    VirtIOBlock *s = to_virtio_blk(vdev);
121 6e02c38d aliguori
    VirtIOBlockReq *req;
122 6e02c38d aliguori
123 6e02c38d aliguori
    while ((req = virtio_blk_get_request(s))) {
124 6e02c38d aliguori
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
125 6e02c38d aliguori
            fprintf(stderr, "virtio-blk missing headers\n");
126 6e02c38d aliguori
            exit(1);
127 6e02c38d aliguori
        }
128 6e02c38d aliguori
129 6e02c38d aliguori
        if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
130 6e02c38d aliguori
            req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
131 6e02c38d aliguori
            fprintf(stderr, "virtio-blk header not in correct element\n");
132 6e02c38d aliguori
            exit(1);
133 6e02c38d aliguori
        }
134 6e02c38d aliguori
135 6e02c38d aliguori
        req->out = (void *)req->elem.out_sg[0].iov_base;
136 6e02c38d aliguori
        req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
137 6e02c38d aliguori
138 6e02c38d aliguori
        if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
139 6e02c38d aliguori
            unsigned int len = sizeof(*req->in);
140 6e02c38d aliguori
141 6e02c38d aliguori
            req->in->status = VIRTIO_BLK_S_UNSUPP;
142 6e02c38d aliguori
            virtqueue_push(vq, &req->elem, len);
143 6e02c38d aliguori
            virtio_notify(vdev, vq);
144 6e02c38d aliguori
            qemu_free(req);
145 6e02c38d aliguori
        } else if (req->out->type & VIRTIO_BLK_T_OUT) {
146 d28a1b6e aliguori
            qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
147 d28a1b6e aliguori
                                     req->elem.out_num - 1);
148 d28a1b6e aliguori
            virtio_blk_handle_write(req);
149 6e02c38d aliguori
        } else {
150 d28a1b6e aliguori
            qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
151 d28a1b6e aliguori
                                     req->elem.in_num - 1);
152 d28a1b6e aliguori
            virtio_blk_handle_read(req);
153 6e02c38d aliguori
        }
154 6e02c38d aliguori
    }
155 6e02c38d aliguori
    /*
156 6e02c38d aliguori
     * FIXME: Want to check for completions before returning to guest mode,
157 6e02c38d aliguori
     * so cached reads and writes are reported as quickly as possible. But
158 6e02c38d aliguori
     * that should be done in the generic block layer.
159 6e02c38d aliguori
     */
160 6e02c38d aliguori
}
161 6e02c38d aliguori
162 869a5c6d aliguori
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
163 869a5c6d aliguori
{
164 869a5c6d aliguori
    VirtIOBlock *s = opaque;
165 869a5c6d aliguori
    VirtIOBlockReq *req = s->rq;
166 869a5c6d aliguori
167 869a5c6d aliguori
    if (!running)
168 869a5c6d aliguori
        return;
169 869a5c6d aliguori
170 869a5c6d aliguori
    s->rq = NULL;
171 869a5c6d aliguori
172 869a5c6d aliguori
    while (req) {
173 869a5c6d aliguori
        virtio_blk_handle_write(req);
174 869a5c6d aliguori
        req = req->next;
175 869a5c6d aliguori
    }
176 869a5c6d aliguori
}
177 869a5c6d aliguori
178 6e02c38d aliguori
static void virtio_blk_reset(VirtIODevice *vdev)
179 6e02c38d aliguori
{
180 6e02c38d aliguori
    /*
181 6e02c38d aliguori
     * This should cancel pending requests, but can't do nicely until there
182 6e02c38d aliguori
     * are per-device request lists.
183 6e02c38d aliguori
     */
184 6e02c38d aliguori
    qemu_aio_flush();
185 6e02c38d aliguori
}
186 6e02c38d aliguori
187 6e02c38d aliguori
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
188 6e02c38d aliguori
{
189 6e02c38d aliguori
    VirtIOBlock *s = to_virtio_blk(vdev);
190 6e02c38d aliguori
    struct virtio_blk_config blkcfg;
191 6e02c38d aliguori
    uint64_t capacity;
192 6e02c38d aliguori
    int cylinders, heads, secs;
193 6e02c38d aliguori
194 6e02c38d aliguori
    bdrv_get_geometry(s->bs, &capacity);
195 6e02c38d aliguori
    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
196 6e02c38d aliguori
    stq_raw(&blkcfg.capacity, capacity);
197 6e02c38d aliguori
    stl_raw(&blkcfg.seg_max, 128 - 2);
198 6e02c38d aliguori
    stw_raw(&blkcfg.cylinders, cylinders);
199 6e02c38d aliguori
    blkcfg.heads = heads;
200 6e02c38d aliguori
    blkcfg.sectors = secs;
201 6e02c38d aliguori
    memcpy(config, &blkcfg, sizeof(blkcfg));
202 6e02c38d aliguori
}
203 6e02c38d aliguori
204 6e02c38d aliguori
static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
205 6e02c38d aliguori
{
206 6e02c38d aliguori
    return (1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_GEOMETRY);
207 6e02c38d aliguori
}
208 6e02c38d aliguori
209 6e02c38d aliguori
static void virtio_blk_save(QEMUFile *f, void *opaque)
210 6e02c38d aliguori
{
211 6e02c38d aliguori
    VirtIOBlock *s = opaque;
212 869a5c6d aliguori
    VirtIOBlockReq *req = s->rq;
213 869a5c6d aliguori
214 6e02c38d aliguori
    virtio_save(&s->vdev, f);
215 869a5c6d aliguori
    
216 869a5c6d aliguori
    while (req) {
217 869a5c6d aliguori
        qemu_put_sbyte(f, 1);
218 869a5c6d aliguori
        qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
219 869a5c6d aliguori
        req = req->next;
220 869a5c6d aliguori
    }
221 869a5c6d aliguori
    qemu_put_sbyte(f, 0);
222 6e02c38d aliguori
}
223 6e02c38d aliguori
224 6e02c38d aliguori
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
225 6e02c38d aliguori
{
226 6e02c38d aliguori
    VirtIOBlock *s = opaque;
227 6e02c38d aliguori
228 869a5c6d aliguori
    if (version_id != 2)
229 6e02c38d aliguori
        return -EINVAL;
230 6e02c38d aliguori
231 6e02c38d aliguori
    virtio_load(&s->vdev, f);
232 869a5c6d aliguori
    while (qemu_get_sbyte(f)) {
233 869a5c6d aliguori
        VirtIOBlockReq *req = virtio_blk_alloc_request(s);
234 869a5c6d aliguori
        qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
235 869a5c6d aliguori
        req->next = s->rq;
236 869a5c6d aliguori
        s->rq = req->next;
237 869a5c6d aliguori
    }
238 6e02c38d aliguori
239 6e02c38d aliguori
    return 0;
240 6e02c38d aliguori
}
241 6e02c38d aliguori
242 9b32d5a5 aliguori
void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs)
243 6e02c38d aliguori
{
244 6e02c38d aliguori
    VirtIOBlock *s;
245 6e02c38d aliguori
    int cylinders, heads, secs;
246 6e02c38d aliguori
    static int virtio_blk_id;
247 6e02c38d aliguori
248 9b32d5a5 aliguori
    s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk",
249 9b32d5a5 aliguori
                                       PCI_VENDOR_ID_REDHAT_QUMRANET,
250 9b32d5a5 aliguori
                                       PCI_DEVICE_ID_VIRTIO_BLOCK,
251 99b3718e aliguori
                                       PCI_VENDOR_ID_REDHAT_QUMRANET,
252 99b3718e aliguori
                                       VIRTIO_ID_BLOCK,
253 173a543b blueswir1
                                       PCI_CLASS_STORAGE_OTHER, 0x00,
254 6e02c38d aliguori
                                       sizeof(struct virtio_blk_config), sizeof(VirtIOBlock));
255 6e02c38d aliguori
    if (!s)
256 6e02c38d aliguori
        return NULL;
257 6e02c38d aliguori
258 6e02c38d aliguori
    s->vdev.get_config = virtio_blk_update_config;
259 6e02c38d aliguori
    s->vdev.get_features = virtio_blk_get_features;
260 6e02c38d aliguori
    s->vdev.reset = virtio_blk_reset;
261 6e02c38d aliguori
    s->bs = bs;
262 869a5c6d aliguori
    s->rq = NULL;
263 b0a7b120 aliguori
    bs->private = &s->vdev.pci_dev;
264 6e02c38d aliguori
    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
265 6e02c38d aliguori
    bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);
266 6e02c38d aliguori
267 6e02c38d aliguori
    s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
268 6e02c38d aliguori
269 869a5c6d aliguori
    qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
270 869a5c6d aliguori
    register_savevm("virtio-blk", virtio_blk_id++, 2,
271 6e02c38d aliguori
                    virtio_blk_save, virtio_blk_load, s);
272 6e02c38d aliguori
273 6e02c38d aliguori
    return s;
274 6e02c38d aliguori
}