~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to hw/virtio-blk.c

  • Committer: Bazaar Package Importer
  • Author(s): Riku Voipio, Josh Triplett, Riku Voipio
  • Date: 2009-07-29 13:28:05 UTC
  • mfrom: (1.4.1 upstream)
  • mto: (12.1.1 sid) (10.1.13 sid)
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20090729132805-cau7rfexh7dawyb8
Tags: 0.10.50+git20090729-1
[ Josh Triplett ]
* Remove myself from Uploaders.

[ Riku Voipio ]
* new upstream RC version
* nuke all linux-user patches (applied upstream)
  06_exit_segfault
  12_signal_powerpc_support
  21_net_soopts
  30_syscall_ipc
  32_syscall_sysctl
  35_syscall_sockaddr
  48_signal_terminate
  55_unmux_socketcall
* nuke all other applied-upstream patches
  01_nostrip (better version upstream)
  07_i386_exec_name (can be reintroduced in debian/rules)
  50_linuxbios_isa_bios_ram (shouldn't be needed anymore)
  51_linuxbios_piix_ram_size (applied)
  56_dhcp (crap)
  60_ppc_ld (reintroduce if needed)
  64_ppc_asm_constraints (ditto)
  66_tls_ld.patch (ditto)
  81_compile_dtb.patch (applied upstream)
  82_qemu-img_decimal (ditto)
* move to git
* simplify build rules
* Correct my email address

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include <sysemu.h>
16
16
#include "virtio-blk.h"
17
17
#include "block_int.h"
 
18
#ifdef __linux__
 
19
# include <scsi/sg.h>
 
20
#endif
18
21
 
19
22
typedef struct VirtIOBlock
20
23
{
22
25
    BlockDriverState *bs;
23
26
    VirtQueue *vq;
24
27
    void *rq;
 
28
    char serial_str[BLOCK_SERIAL_STRLEN + 1];
25
29
} VirtIOBlock;
26
30
 
27
31
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
29
33
    return (VirtIOBlock *)vdev;
30
34
}
31
35
 
 
36
/* store identify data in little endian format
 
37
 */
 
38
static inline void put_le16(uint16_t *p, unsigned int v)
 
39
{
 
40
    *p = cpu_to_le16(v);
 
41
}
 
42
 
 
43
/* copy to *dst from *src, nul pad dst tail as needed to len bytes
 
44
 */
 
45
static inline void padstr(char *dst, const char *src, int len)
 
46
{
 
47
    while (len--)
 
48
        *dst++ = *src ? *src++ : '\0';
 
49
}
 
50
 
 
51
/* setup simulated identify data as appropriate for virtio block device
 
52
 *
 
53
 * ref: AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
 
54
 */
 
55
static inline void virtio_identify_template(struct virtio_blk_config *bc)
 
56
{
 
57
    uint16_t *p = &bc->identify[0];
 
58
    uint64_t lba_sectors = bc->capacity;
 
59
 
 
60
    memset(p, 0, sizeof(bc->identify));
 
61
    put_le16(p + 0, 0x0);                            /* ATA device */
 
62
    padstr((char *)(p + 23), QEMU_VERSION, 8);       /* firmware revision */
 
63
    padstr((char *)(p + 27), "QEMU VIRT_BLK", 40);   /* model# */
 
64
    put_le16(p + 47, 0x80ff);                        /* max xfer 255 sectors */
 
65
    put_le16(p + 49, 0x0b00);                        /* support IORDY/LBA/DMA */
 
66
    put_le16(p + 59, 0x1ff);                         /* cur xfer 255 sectors */
 
67
    put_le16(p + 80, 0x1f0);                         /* support ATA8/7/6/5/4 */
 
68
    put_le16(p + 81, 0x16);
 
69
    put_le16(p + 82, 0x400);
 
70
    put_le16(p + 83, 0x400);
 
71
    put_le16(p + 100, lba_sectors);
 
72
    put_le16(p + 101, lba_sectors >> 16);
 
73
    put_le16(p + 102, lba_sectors >> 32);
 
74
    put_le16(p + 103, lba_sectors >> 48);
 
75
}
 
76
 
32
77
typedef struct VirtIOBlockReq
33
78
{
34
79
    VirtIOBlock *dev;
35
80
    VirtQueueElement elem;
36
81
    struct virtio_blk_inhdr *in;
37
82
    struct virtio_blk_outhdr *out;
38
 
    size_t size;
39
 
    uint8_t *buffer;
 
83
    struct virtio_scsi_inhdr *scsi;
 
84
    QEMUIOVector qiov;
40
85
    struct VirtIOBlockReq *next;
41
86
} VirtIOBlockReq;
42
87
 
45
90
    VirtIOBlock *s = req->dev;
46
91
 
47
92
    req->in->status = status;
48
 
    virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in));
 
93
    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
49
94
    virtio_notify(&s->vdev, s->vq);
50
95
 
51
 
    qemu_free(req->buffer);
52
96
    qemu_free(req);
53
97
}
54
98
 
76
120
{
77
121
    VirtIOBlockReq *req = opaque;
78
122
 
79
 
    /* Copy read data to the guest */
80
 
    if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) {
81
 
        size_t offset = 0;
82
 
        int i;
83
 
 
84
 
        for (i = 0; i < req->elem.in_num - 1; i++) {
85
 
            size_t len;
86
 
 
87
 
            /* Be pretty defensive wrt malicious guests */
88
 
            len = MIN(req->elem.in_sg[i].iov_len,
89
 
                      req->size - offset);
90
 
 
91
 
            memcpy(req->elem.in_sg[i].iov_base,
92
 
                   req->buffer + offset,
93
 
                   len);
94
 
            offset += len;
95
 
        }
96
 
    } else if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
 
123
    if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
97
124
        if (virtio_blk_handle_write_error(req, -ret))
98
125
            return;
99
126
    }
122
149
    return req;
123
150
}
124
151
 
125
 
static int virtio_blk_handle_write(VirtIOBlockReq *req)
126
 
{
127
 
    if (!req->buffer) {
128
 
        size_t offset = 0;
129
 
        int i;
130
 
 
131
 
        for (i = 1; i < req->elem.out_num; i++)
132
 
            req->size += req->elem.out_sg[i].iov_len;
133
 
 
134
 
        req->buffer = qemu_memalign(512, req->size);
135
 
        if (req->buffer == NULL) {
136
 
            qemu_free(req);
137
 
            return -1;
138
 
        }
139
 
 
140
 
        /* We copy the data from the SG list to avoid splitting up the request.
141
 
           This helps performance a lot until we can pass full sg lists as AIO
142
 
           operations */
143
 
        for (i = 1; i < req->elem.out_num; i++) {
144
 
            size_t len;
145
 
 
146
 
            len = MIN(req->elem.out_sg[i].iov_len,
147
 
                    req->size - offset);
148
 
            memcpy(req->buffer + offset,
149
 
                    req->elem.out_sg[i].iov_base,
150
 
                    len);
151
 
            offset += len;
152
 
        }
153
 
    }
154
 
 
155
 
    bdrv_aio_write(req->dev->bs, req->out->sector, req->buffer, req->size / 512,
156
 
            virtio_blk_rw_complete, req);
157
 
    return 0;
 
152
#ifdef __linux__
 
153
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 
154
{
 
155
    struct sg_io_hdr hdr;
 
156
    int ret, size = 0;
 
157
    int status;
 
158
    int i;
 
159
 
 
160
    /*
 
161
     * We require at least one output segment each for the virtio_blk_outhdr
 
162
     * and the SCSI command block.
 
163
     *
 
164
     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
 
165
     * and the sense buffer pointer in the input segments.
 
166
     */
 
167
    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
 
168
        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
 
169
        return;
 
170
    }
 
171
 
 
172
    /*
 
173
     * No support for bidirection commands yet.
 
174
     */
 
175
    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
 
176
        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
 
177
        return;
 
178
    }
 
179
 
 
180
    /*
 
181
     * The scsi inhdr is placed in the second-to-last input segment, just
 
182
     * before the regular inhdr.
 
183
     */
 
184
    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
 
185
    size = sizeof(*req->in) + sizeof(*req->scsi);
 
186
 
 
187
    memset(&hdr, 0, sizeof(struct sg_io_hdr));
 
188
    hdr.interface_id = 'S';
 
189
    hdr.cmd_len = req->elem.out_sg[1].iov_len;
 
190
    hdr.cmdp = req->elem.out_sg[1].iov_base;
 
191
    hdr.dxfer_len = 0;
 
192
 
 
193
    if (req->elem.out_num > 2) {
 
194
        /*
 
195
         * If there are more than the minimally required 2 output segments
 
196
         * there is write payload starting from the third iovec.
 
197
         */
 
198
        hdr.dxfer_direction = SG_DXFER_TO_DEV;
 
199
        hdr.iovec_count = req->elem.out_num - 2;
 
200
 
 
201
        for (i = 0; i < hdr.iovec_count; i++)
 
202
            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
 
203
 
 
204
        hdr.dxferp = req->elem.out_sg + 2;
 
205
 
 
206
    } else if (req->elem.in_num > 3) {
 
207
        /*
 
208
         * If we have more than 3 input segments the guest wants to actually
 
209
         * read data.
 
210
         */
 
211
        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
 
212
        hdr.iovec_count = req->elem.in_num - 3;
 
213
        for (i = 0; i < hdr.iovec_count; i++)
 
214
            hdr.dxfer_len += req->elem.in_sg[i].iov_len;
 
215
 
 
216
        hdr.dxferp = req->elem.in_sg;
 
217
        size += hdr.dxfer_len;
 
218
    } else {
 
219
        /*
 
220
         * Some SCSI commands don't actually transfer any data.
 
221
         */
 
222
        hdr.dxfer_direction = SG_DXFER_NONE;
 
223
    }
 
224
 
 
225
    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
 
226
    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
 
227
    size += hdr.mx_sb_len;
 
228
 
 
229
    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
 
230
    if (ret) {
 
231
        status = VIRTIO_BLK_S_UNSUPP;
 
232
        hdr.status = ret;
 
233
        hdr.resid = hdr.dxfer_len;
 
234
    } else if (hdr.status) {
 
235
        status = VIRTIO_BLK_S_IOERR;
 
236
    } else {
 
237
        status = VIRTIO_BLK_S_OK;
 
238
    }
 
239
 
 
240
    req->scsi->errors = hdr.status;
 
241
    req->scsi->residual = hdr.resid;
 
242
    req->scsi->sense_len = hdr.sb_len_wr;
 
243
    req->scsi->data_len = hdr.dxfer_len;
 
244
 
 
245
    virtio_blk_req_complete(req, status);
 
246
}
 
247
#else
 
248
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 
249
{
 
250
    virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
 
251
}
 
252
#endif /* __linux__ */
 
253
 
 
254
static void virtio_blk_handle_write(VirtIOBlockReq *req)
 
255
{
 
256
    bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
 
257
                    req->qiov.size / 512, virtio_blk_rw_complete, req);
 
258
}
 
259
 
 
260
static void virtio_blk_handle_read(VirtIOBlockReq *req)
 
261
{
 
262
    bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
 
263
                   req->qiov.size / 512, virtio_blk_rw_complete, req);
158
264
}
159
265
 
160
266
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
163
269
    VirtIOBlockReq *req;
164
270
 
165
271
    while ((req = virtio_blk_get_request(s))) {
166
 
        int i;
167
 
 
168
272
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
169
273
            fprintf(stderr, "virtio-blk missing headers\n");
170
274
            exit(1);
180
284
        req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
181
285
 
182
286
        if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
183
 
            unsigned int len = sizeof(*req->in);
184
 
 
185
 
            req->in->status = VIRTIO_BLK_S_UNSUPP;
186
 
            virtqueue_push(vq, &req->elem, len);
187
 
            virtio_notify(vdev, vq);
188
 
            qemu_free(req);
 
287
            virtio_blk_handle_scsi(req);
189
288
        } else if (req->out->type & VIRTIO_BLK_T_OUT) {
190
 
            if (virtio_blk_handle_write(req) < 0)
191
 
                break;
 
289
            qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
 
290
                                     req->elem.out_num - 1);
 
291
            virtio_blk_handle_write(req);
192
292
        } else {
193
 
            for (i = 0; i < req->elem.in_num - 1; i++)
194
 
                req->size += req->elem.in_sg[i].iov_len;
195
 
 
196
 
            req->buffer = qemu_memalign(512, req->size);
197
 
            if (req->buffer == NULL) {
198
 
                qemu_free(req);
199
 
                break;
200
 
            }
201
 
 
202
 
            bdrv_aio_read(s->bs, req->out->sector,
203
 
                          req->buffer,
204
 
                          req->size / 512,
205
 
                          virtio_blk_rw_complete,
206
 
                          req);
 
293
            qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
 
294
                                     req->elem.in_num - 1);
 
295
            virtio_blk_handle_read(req);
207
296
        }
208
297
    }
209
298
    /*
238
327
    qemu_aio_flush();
239
328
}
240
329
 
 
330
/* coalesce internal state, copy to pci i/o region 0
 
331
 */
241
332
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
242
333
{
243
334
    VirtIOBlock *s = to_virtio_blk(vdev);
247
338
 
248
339
    bdrv_get_geometry(s->bs, &capacity);
249
340
    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
 
341
    memset(&blkcfg, 0, sizeof(blkcfg));
250
342
    stq_raw(&blkcfg.capacity, capacity);
251
343
    stl_raw(&blkcfg.seg_max, 128 - 2);
252
344
    stw_raw(&blkcfg.cylinders, cylinders);
253
345
    blkcfg.heads = heads;
254
346
    blkcfg.sectors = secs;
 
347
    blkcfg.size_max = 0;
 
348
    virtio_identify_template(&blkcfg);
 
349
    memcpy(&blkcfg.identify[VIRTIO_BLK_ID_SN], s->serial_str,
 
350
        VIRTIO_BLK_ID_SN_BYTES);
255
351
    memcpy(config, &blkcfg, sizeof(blkcfg));
256
352
}
257
353
 
258
354
static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
259
355
{
260
 
    return (1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_GEOMETRY);
 
356
    VirtIOBlock *s = to_virtio_blk(vdev);
 
357
    uint32_t features = 0;
 
358
 
 
359
    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
 
360
    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
 
361
#ifdef __linux__
 
362
    features |= (1 << VIRTIO_BLK_F_SCSI);
 
363
#endif
 
364
    if (strcmp(s->serial_str, "0"))
 
365
        features |= 1 << VIRTIO_BLK_F_IDENTIFY;
 
366
 
 
367
    return features;
261
368
}
262
369
 
263
370
static void virtio_blk_save(QEMUFile *f, void *opaque)
293
400
    return 0;
294
401
}
295
402
 
296
 
void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs)
 
403
VirtIODevice *virtio_blk_init(DeviceState *dev)
297
404
{
298
405
    VirtIOBlock *s;
299
406
    int cylinders, heads, secs;
300
407
    static int virtio_blk_id;
301
 
 
302
 
    s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk",
303
 
                                       PCI_VENDOR_ID_REDHAT_QUMRANET,
304
 
                                       PCI_DEVICE_ID_VIRTIO_BLOCK,
305
 
                                       PCI_VENDOR_ID_REDHAT_QUMRANET,
306
 
                                       VIRTIO_ID_BLOCK,
307
 
                                       PCI_CLASS_STORAGE_OTHER, 0x00,
308
 
                                       sizeof(struct virtio_blk_config), sizeof(VirtIOBlock));
309
 
    if (!s)
310
 
        return NULL;
311
 
 
 
408
    BlockDriverState *bs;
 
409
    char *ps;
 
410
 
 
411
    s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
 
412
                                          sizeof(struct virtio_blk_config),
 
413
                                          sizeof(VirtIOBlock));
 
414
 
 
415
    bs = qdev_init_bdrv(dev, IF_VIRTIO);
312
416
    s->vdev.get_config = virtio_blk_update_config;
313
417
    s->vdev.get_features = virtio_blk_get_features;
314
418
    s->vdev.reset = virtio_blk_reset;
315
419
    s->bs = bs;
316
420
    s->rq = NULL;
317
 
    bs->private = &s->vdev.pci_dev;
 
421
    if (strlen(ps = (char *)drive_get_serial(bs)))
 
422
        strncpy(s->serial_str, ps, sizeof(s->serial_str));
 
423
    else
 
424
        snprintf(s->serial_str, sizeof(s->serial_str), "0");
 
425
    bs->private = dev;
318
426
    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
319
427
    bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);
320
428
 
324
432
    register_savevm("virtio-blk", virtio_blk_id++, 2,
325
433
                    virtio_blk_save, virtio_blk_load, s);
326
434
 
327
 
    return s;
 
435
    return &s->vdev;
328
436
}