aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/virtio_blk.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 0cfbe8c594a5..84e064ffee52 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -35,7 +35,7 @@ struct virtblk_req
35 struct list_head list; 35 struct list_head list;
36 struct request *req; 36 struct request *req;
37 struct virtio_blk_outhdr out_hdr; 37 struct virtio_blk_outhdr out_hdr;
38 struct virtio_blk_inhdr in_hdr; 38 u8 status;
39}; 39};
40 40
41static void blk_done(struct virtqueue *vq) 41static void blk_done(struct virtqueue *vq)
@@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq)
48 spin_lock_irqsave(&vblk->lock, flags); 48 spin_lock_irqsave(&vblk->lock, flags);
49 while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { 49 while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
50 int uptodate; 50 int uptodate;
51 switch (vbr->in_hdr.status) { 51 switch (vbr->status) {
52 case VIRTIO_BLK_S_OK: 52 case VIRTIO_BLK_S_OK:
53 uptodate = 1; 53 uptodate = 1;
54 break; 54 break;
@@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
101 sg_init_table(vblk->sg, VIRTIO_MAX_SG); 101 sg_init_table(vblk->sg, VIRTIO_MAX_SG);
102 sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); 102 sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
103 num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); 103 num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
104 sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr)); 104 sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
105 105
106 if (rq_data_dir(vbr->req) == WRITE) { 106 if (rq_data_dir(vbr->req) == WRITE) {
107 vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; 107 vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
@@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
157/* We provide getgeo only to please some old bootloader/partitioning tools */ 157/* We provide getgeo only to please some old bootloader/partitioning tools */
158static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) 158static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
159{ 159{
160 /* some standard values, similar to sd */ 160 struct virtio_blk *vblk = bd->bd_disk->private_data;
161 geo->heads = 1 << 6; 161 struct virtio_blk_geometry vgeo;
162 geo->sectors = 1 << 5; 162 int err;
163 geo->cylinders = get_capacity(bd->bd_disk) >> 11; 163
164 /* see if the host passed in geometry config */
165 err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
166 offsetof(struct virtio_blk_config, geometry),
167 &vgeo);
168
169 if (!err) {
170 geo->heads = vgeo.heads;
171 geo->sectors = vgeo.sectors;
172 geo->cylinders = vgeo.cylinders;
173 } else {
174 /* some standard values, similar to sd */
175 geo->heads = 1 << 6;
176 geo->sectors = 1 << 5;
177 geo->cylinders = get_capacity(bd->bd_disk) >> 11;
178 }
164 return 0; 179 return 0;
165} 180}
166 181
@@ -242,12 +257,12 @@ static int virtblk_probe(struct virtio_device *vdev)
242 index++; 257 index++;
243 258
244 /* If barriers are supported, tell block layer that queue is ordered */ 259 /* If barriers are supported, tell block layer that queue is ordered */
245 if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) 260 if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
246 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); 261 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
247 262
248 /* Host must always specify the capacity. */ 263 /* Host must always specify the capacity. */
249 __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity), 264 vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
250 &cap); 265 &cap, sizeof(cap));
251 266
252 /* If capacity is too big, truncate with warning. */ 267 /* If capacity is too big, truncate with warning. */
253 if ((sector_t)cap != cap) { 268 if ((sector_t)cap != cap) {
@@ -289,7 +304,6 @@ out:
289static void virtblk_remove(struct virtio_device *vdev) 304static void virtblk_remove(struct virtio_device *vdev)
290{ 305{
291 struct virtio_blk *vblk = vdev->priv; 306 struct virtio_blk *vblk = vdev->priv;
292 int major = vblk->disk->major;
293 307
294 /* Nothing should be pending. */ 308 /* Nothing should be pending. */
295 BUG_ON(!list_empty(&vblk->reqs)); 309 BUG_ON(!list_empty(&vblk->reqs));
@@ -299,7 +313,6 @@ static void virtblk_remove(struct virtio_device *vdev)
299 313
300 blk_cleanup_queue(vblk->disk->queue); 314 blk_cleanup_queue(vblk->disk->queue);
301 put_disk(vblk->disk); 315 put_disk(vblk->disk);
302 unregister_blkdev(major, "virtblk");
303 mempool_destroy(vblk->pool); 316 mempool_destroy(vblk->pool);
304 vdev->config->del_vq(vblk->vq); 317 vdev->config->del_vq(vblk->vq);
305 kfree(vblk); 318 kfree(vblk);
@@ -310,7 +323,14 @@ static struct virtio_device_id id_table[] = {
310 { 0 }, 323 { 0 },
311}; 324};
312 325
326static unsigned int features[] = {
327 VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
328 VIRTIO_BLK_F_GEOMETRY,
329};
330
313static struct virtio_driver virtio_blk = { 331static struct virtio_driver virtio_blk = {
332 .feature_table = features,
333 .feature_table_size = ARRAY_SIZE(features),
314 .driver.name = KBUILD_MODNAME, 334 .driver.name = KBUILD_MODNAME,
315 .driver.owner = THIS_MODULE, 335 .driver.owner = THIS_MODULE,
316 .id_table = id_table, 336 .id_table = id_table,