The discovered bit in PGCCSR register indicates if the device has been
[linux-2.6/next.git] / tools / kvm / virtio / blk.c
blob5f312b538ff58e95ca33158341c9c2383fc80eb4
1 #include "kvm/virtio-blk.h"
3 #include "kvm/virtio-pci-dev.h"
4 #include "kvm/disk-image.h"
5 #include "kvm/virtio.h"
6 #include "kvm/mutex.h"
7 #include "kvm/util.h"
8 #include "kvm/kvm.h"
9 #include "kvm/pci.h"
10 #include "kvm/threadpool.h"
11 #include "kvm/ioeventfd.h"
12 #include "kvm/guest_compat.h"
13 #include "kvm/virtio-pci.h"
15 #include <linux/virtio_ring.h>
16 #include <linux/virtio_blk.h>
18 #include <linux/kernel.h>
19 #include <linux/list.h>
20 #include <linux/types.h>
21 #include <pthread.h>
23 #define VIRTIO_BLK_MAX_DEV 4
24 #define NUM_VIRT_QUEUES 1
26 #define VIRTIO_BLK_QUEUE_SIZE 128
28 * the header and status consume too entries
30 #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2)
32 struct blk_dev_job {
33 struct virt_queue *vq;
34 struct blk_dev *bdev;
35 struct iovec iov[VIRTIO_BLK_QUEUE_SIZE];
36 u16 out, in, head;
37 struct thread_pool__job job_id;
40 struct blk_dev {
41 pthread_mutex_t mutex;
42 struct list_head list;
44 struct virtio_pci vpci;
45 struct virtio_blk_config blk_config;
46 struct disk_image *disk;
47 int compat_id;
48 u32 features;
50 struct virt_queue vqs[NUM_VIRT_QUEUES];
51 struct blk_dev_job jobs[VIRTIO_BLK_QUEUE_SIZE];
52 u16 job_idx;
55 static LIST_HEAD(bdevs);
57 static void virtio_blk_do_io_request(struct kvm *kvm, void *param)
59 struct virtio_blk_outhdr *req;
60 u8 *status;
61 ssize_t block_cnt;
62 struct blk_dev_job *job;
63 struct blk_dev *bdev;
64 struct virt_queue *queue;
65 struct iovec *iov;
66 u16 out, in, head;
68 block_cnt = -1;
69 job = param;
70 bdev = job->bdev;
71 queue = job->vq;
72 iov = job->iov;
73 out = job->out;
74 in = job->in;
75 head = job->head;
76 req = iov[0].iov_base;
78 switch (req->type) {
79 case VIRTIO_BLK_T_IN:
80 block_cnt = disk_image__read(bdev->disk, req->sector, iov + 1, in + out - 2);
81 break;
82 case VIRTIO_BLK_T_OUT:
83 block_cnt = disk_image__write(bdev->disk, req->sector, iov + 1, in + out - 2);
84 break;
85 case VIRTIO_BLK_T_FLUSH:
86 block_cnt = disk_image__flush(bdev->disk);
87 break;
88 case VIRTIO_BLK_T_GET_ID:
89 block_cnt = VIRTIO_BLK_ID_BYTES;
90 disk_image__get_serial(bdev->disk, (iov + 1)->iov_base, &block_cnt);
91 break;
92 default:
93 pr_warning("request type %d", req->type);
94 block_cnt = -1;
95 break;
98 /* status */
99 status = iov[out + in - 1].iov_base;
100 *status = (block_cnt < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
102 mutex_lock(&bdev->mutex);
103 virt_queue__set_used_elem(queue, head, block_cnt);
104 mutex_unlock(&bdev->mutex);
106 virtio_pci__signal_vq(kvm, &bdev->vpci, queue - bdev->vqs);
109 static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
111 while (virt_queue__available(vq)) {
112 struct blk_dev_job *job = &bdev->jobs[bdev->job_idx++ % VIRTIO_BLK_QUEUE_SIZE];
114 *job = (struct blk_dev_job) {
115 .vq = vq,
116 .bdev = bdev,
118 job->head = virt_queue__get_iov(vq, job->iov, &job->out, &job->in, kvm);
120 thread_pool__init_job(&job->job_id, kvm, virtio_blk_do_io_request, job);
121 thread_pool__do_job(&job->job_id);
125 static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
127 struct blk_dev *bdev = dev;
129 ((u8 *)(&bdev->blk_config))[offset] = data;
132 static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
134 struct blk_dev *bdev = dev;
136 return ((u8 *)(&bdev->blk_config))[offset];
139 static u32 get_host_features(struct kvm *kvm, void *dev)
141 return 1UL << VIRTIO_BLK_F_SEG_MAX | 1UL << VIRTIO_BLK_F_FLUSH;
144 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
146 struct blk_dev *bdev = dev;
148 bdev->features = features;
151 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
153 struct blk_dev *bdev = dev;
154 struct virt_queue *queue;
155 void *p;
157 compat__remove_message(bdev->compat_id);
159 queue = &bdev->vqs[vq];
160 queue->pfn = pfn;
161 p = guest_pfn_to_host(kvm, queue->pfn);
163 vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
165 return 0;
168 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
170 struct blk_dev *bdev = dev;
172 virtio_blk_do_io(kvm, &bdev->vqs[vq], bdev);
174 return 0;
177 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
179 struct blk_dev *bdev = dev;
181 return bdev->vqs[vq].pfn;
184 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
186 return VIRTIO_BLK_QUEUE_SIZE;
189 void virtio_blk__init(struct kvm *kvm, struct disk_image *disk)
191 struct blk_dev *bdev;
193 if (!disk)
194 return;
196 bdev = calloc(1, sizeof(struct blk_dev));
197 if (bdev == NULL)
198 die("Failed allocating bdev");
200 *bdev = (struct blk_dev) {
201 .mutex = PTHREAD_MUTEX_INITIALIZER,
202 .disk = disk,
203 .blk_config = (struct virtio_blk_config) {
204 .capacity = disk->size / SECTOR_SIZE,
205 .seg_max = DISK_SEG_MAX,
209 virtio_pci__init(kvm, &bdev->vpci, bdev, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK);
210 bdev->vpci.ops = (struct virtio_pci_ops) {
211 .set_config = set_config,
212 .get_config = get_config,
213 .get_host_features = get_host_features,
214 .set_guest_features = set_guest_features,
215 .init_vq = init_vq,
216 .notify_vq = notify_vq,
217 .get_pfn_vq = get_pfn_vq,
218 .get_size_vq = get_size_vq,
221 list_add_tail(&bdev->list, &bdevs);
223 bdev->compat_id = compat__add_message("virtio-blk device was not detected",
224 "While you have requested a virtio-blk device, "
225 "the guest kernel didn't seem to detect it.\n"
226 "Please make sure that the kernel was compiled"
227 "with CONFIG_VIRTIO_BLK.");
230 void virtio_blk__init_all(struct kvm *kvm)
232 int i;
234 for (i = 0; i < kvm->nr_disks; i++)
235 virtio_blk__init(kvm, kvm->disks[i]);
238 void virtio_blk__delete_all(struct kvm *kvm)
240 while (!list_empty(&bdevs)) {
241 struct blk_dev *bdev;
243 bdev = list_first_entry(&bdevs, struct blk_dev, list);
244 list_del(&bdev->list);
245 free(bdev);