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.
16 #include "block_int.h"
19 /* from Linux's linux/virtio_blk.h */
21 /* The ID for virtio_block */
22 #define VIRTIO_ID_BLOCK 2
25 #define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
26 #define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
27 #define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
29 struct virtio_blk_config
36 /* These two define direction. */
37 #define VIRTIO_BLK_T_IN 0
38 #define VIRTIO_BLK_T_OUT 1
40 /* This bit says it's a scsi command, not an actual read or write. */
41 #define VIRTIO_BLK_T_SCSI_CMD 2
43 /* Barrier before this op. */
44 #define VIRTIO_BLK_T_BARRIER 0x80000000
46 /* This is the first element of the read scatter-gather list. */
47 struct virtio_blk_outhdr
53 /* Sector (ie. 512 byte offset) */
55 /* Where to put reply. */
59 #define VIRTIO_BLK_S_OK 0
60 #define VIRTIO_BLK_S_IOERR 1
61 #define VIRTIO_BLK_S_UNSUPP 2
63 /* This is the first element of the write scatter-gather list */
64 struct virtio_blk_inhdr
69 typedef struct VirtIOBlock
75 static VirtIOBlock
*to_virtio_blk(VirtIODevice
*vdev
)
77 return (VirtIOBlock
*)vdev
;
80 static void virtio_blk_handle_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
82 VirtIOBlock
*s
= to_virtio_blk(vdev
);
83 VirtQueueElement elem
;
86 while ((count
= virtqueue_pop(vq
, &elem
)) != 0) {
87 struct virtio_blk_inhdr
*in
;
88 struct virtio_blk_outhdr
*out
;
93 out
= (void *)elem
.out_sg
[0].iov_base
;
94 in
= (void *)elem
.in_sg
[elem
.in_num
- 1].iov_base
;
97 if (out
->type
& VIRTIO_BLK_T_SCSI_CMD
) {
99 in
->status
= VIRTIO_BLK_S_UNSUPP
;
100 } else if (out
->type
& VIRTIO_BLK_T_OUT
) {
103 for (i
= 1; i
< elem
.out_num
; i
++) {
104 bdrv_write(s
->bs
, off
,
105 elem
.out_sg
[i
].iov_base
,
106 elem
.out_sg
[i
].iov_len
/ 512);
107 off
+= elem
.out_sg
[i
].iov_len
/ 512;
110 in
->status
= VIRTIO_BLK_S_OK
;
114 for (i
= 0; i
< elem
.in_num
- 1; i
++) {
115 bdrv_read(s
->bs
, off
,
116 elem
.in_sg
[i
].iov_base
,
117 elem
.in_sg
[i
].iov_len
/ 512);
118 off
+= elem
.in_sg
[i
].iov_len
/ 512;
119 wlen
+= elem
.in_sg
[i
].iov_len
;
122 in
->status
= VIRTIO_BLK_S_OK
;
125 virtqueue_push(vq
, &elem
, wlen
);
126 virtio_notify(vdev
, vq
);
130 static void virtio_blk_update_config(VirtIODevice
*vdev
, uint8_t *config
)
132 VirtIOBlock
*s
= to_virtio_blk(vdev
);
133 struct virtio_blk_config blkcfg
;
136 bdrv_get_geometry(s
->bs
, &capacity
);
137 blkcfg
.capacity
= cpu_to_le64(capacity
);
138 blkcfg
.seg_max
= cpu_to_le32(128 - 2);
139 memcpy(config
, &blkcfg
, sizeof(blkcfg
));
142 static uint32_t virtio_blk_get_features(VirtIODevice
*vdev
)
144 return (1 << VIRTIO_BLK_F_SEG_MAX
);
147 void *virtio_blk_init(PCIBus
*bus
, uint16_t vendor
, uint16_t device
,
148 BlockDriverState
*bs
)
152 s
= (VirtIOBlock
*)virtio_init_pci(bus
, "virtio-blk", vendor
, device
,
155 16, sizeof(VirtIOBlock
));
157 s
->vdev
.update_config
= virtio_blk_update_config
;
158 s
->vdev
.get_features
= virtio_blk_get_features
;
160 bs
->devfn
= s
->vdev
.pci_dev
.devfn
;
162 virtio_add_queue(&s
->vdev
, 128, virtio_blk_handle_output
);