V4L/DVB (9131): cx18: Add entries for the Leadtek PVR2100 and Toshiba Qosmio DVB...
[safe/jmp/linux-2.6] / drivers / block / virtio_blk.c
index 78be6b8..6ec5fc0 100644 (file)
@@ -47,20 +47,20 @@ static void blk_done(struct virtqueue *vq)
 
        spin_lock_irqsave(&vblk->lock, flags);
        while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
-               int uptodate;
+               int error;
                switch (vbr->status) {
                case VIRTIO_BLK_S_OK:
-                       uptodate = 1;
+                       error = 0;
                        break;
                case VIRTIO_BLK_S_UNSUPP:
-                       uptodate = -ENOTTY;
+                       error = -ENOTTY;
                        break;
                default:
-                       uptodate = 0;
+                       error = -EIO;
                        break;
                }
 
-               end_dequeued_request(vbr->req, uptodate);
+               __blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
                list_del(&vbr->list);
                mempool_free(vbr, vblk->pool);
        }
@@ -84,11 +84,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        if (blk_fs_request(vbr->req)) {
                vbr->out_hdr.type = 0;
                vbr->out_hdr.sector = vbr->req->sector;
-               vbr->out_hdr.ioprio = vbr->req->ioprio;
+               vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
        } else if (blk_pc_request(vbr->req)) {
                vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
                vbr->out_hdr.sector = 0;
-               vbr->out_hdr.ioprio = vbr->req->ioprio;
+               vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
        } else {
                /* We don't put anything else in the queue. */
                BUG();
@@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
-       /* some standard values, similar to sd */
-       geo->heads = 1 << 6;
-       geo->sectors = 1 << 5;
-       geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+       struct virtio_blk *vblk = bd->bd_disk->private_data;
+       struct virtio_blk_geometry vgeo;
+       int err;
+
+       /* see if the host passed in geometry config */
+       err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
+                               offsetof(struct virtio_blk_config, geometry),
+                               &vgeo);
+
+       if (!err) {
+               geo->heads = vgeo.heads;
+               geo->sectors = vgeo.sectors;
+               geo->cylinders = vgeo.cylinders;
+       } else {
+               /* some standard values, similar to sd */
+               geo->heads = 1 << 6;
+               geo->sectors = 1 << 5;
+               geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+       }
        return 0;
 }
 
@@ -181,6 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        int err;
        u64 cap;
        u32 v;
+       u32 blk_size;
 
        if (index_to_minor(index) >= 1 << MINORBITS)
                return -ENOSPC;
@@ -245,6 +261,10 @@ static int virtblk_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
                blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
 
+       /* If disk is read-only in the host, the guest should obey */
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
+               set_disk_ro(vblk->disk, 1);
+
        /* Host must always specify the capacity. */
        vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
                          &cap, sizeof(cap));
@@ -271,6 +291,13 @@ static int virtblk_probe(struct virtio_device *vdev)
        if (!err)
                blk_queue_max_hw_segments(vblk->disk->queue, v);
 
+       /* Host can optionally specify the block size of the device */
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
+                               offsetof(struct virtio_blk_config, blk_size),
+                               &blk_size);
+       if (!err)
+               blk_queue_hardsect_size(vblk->disk->queue, blk_size);
+
        add_disk(vblk->disk);
        return 0;
 
@@ -296,6 +323,7 @@ static void virtblk_remove(struct virtio_device *vdev)
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
+       del_gendisk(vblk->disk);
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
        mempool_destroy(vblk->pool);
@@ -310,6 +338,7 @@ static struct virtio_device_id id_table[] = {
 
 static unsigned int features[] = {
        VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
+       VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
 };
 
 static struct virtio_driver virtio_blk = {