include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / block / virtio_blk.c
index 51042f0..4b12b82 100644 (file)
@@ -1,5 +1,6 @@
 //#define DEBUG
 #include <linux/spinlock.h>
+#include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/virtio.h>
@@ -243,10 +244,12 @@ static int index_to_minor(int index)
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
+       struct request_queue *q;
        int err;
        u64 cap;
-       u32 v;
-       u32 blk_size, sg_elems;
+       u32 v, blk_size, sg_elems, opt_io_size;
+       u16 min_io_size;
+       u8 physical_block_exp, alignment_offset;
 
        if (index_to_minor(index) >= 1 << MINORBITS)
                return -ENOSPC;
@@ -293,13 +296,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                goto out_mempool;
        }
 
-       vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
-       if (!vblk->disk->queue) {
+       q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+       if (!q) {
                err = -ENOMEM;
                goto out_put_disk;
        }
 
-       vblk->disk->queue->queuedata = vblk;
+       q->queuedata = vblk;
 
        if (index < 26) {
                sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -323,10 +326,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
 
        /* If barriers are supported, tell block layer that queue is ordered */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
-               blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+               blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
                                  virtblk_prepare_flush);
        else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
-               blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+               blk_queue_ordered(q, 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))
@@ -345,14 +348,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        set_capacity(vblk->disk, cap);
 
        /* We can handle whatever the host told us to handle. */
-       blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
-       blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
+       blk_queue_max_phys_segments(q, vblk->sg_elems-2);
+       blk_queue_max_hw_segments(q, vblk->sg_elems-2);
 
        /* No need to bounce any requests */
-       blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);
+       blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
 
        /* No real sector limit. */
-       blk_queue_max_sectors(vblk->disk->queue, -1U);
+       blk_queue_max_sectors(q, -1U);
 
        /* Host can optionally specify maximum segment size and number of
         * segments. */
@@ -360,16 +363,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                                offsetof(struct virtio_blk_config, size_max),
                                &v);
        if (!err)
-               blk_queue_max_segment_size(vblk->disk->queue, v);
+               blk_queue_max_segment_size(q, v);
        else
-               blk_queue_max_segment_size(vblk->disk->queue, -1U);
+               blk_queue_max_segment_size(q, -1U);
 
        /* 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_logical_block_size(vblk->disk->queue, blk_size);
+               blk_queue_logical_block_size(q, blk_size);
+       else
+               blk_size = queue_logical_block_size(q);
+
+       /* Use topology information if available */
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, physical_block_exp),
+                       &physical_block_exp);
+       if (!err && physical_block_exp)
+               blk_queue_physical_block_size(q,
+                               blk_size * (1 << physical_block_exp));
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, alignment_offset),
+                       &alignment_offset);
+       if (!err && alignment_offset)
+               blk_queue_alignment_offset(q, blk_size * alignment_offset);
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, min_io_size),
+                       &min_io_size);
+       if (!err && min_io_size)
+               blk_queue_io_min(q, blk_size * min_io_size);
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, opt_io_size),
+                       &opt_io_size);
+       if (!err && opt_io_size)
+               blk_queue_io_opt(q, blk_size * opt_io_size);
+
 
        add_disk(vblk->disk);
        return 0;
@@ -404,7 +436,7 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        kfree(vblk);
 }
 
-static struct virtio_device_id id_table[] = {
+static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
        { 0 },
 };
@@ -412,7 +444,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,
-       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
+       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
 };
 
 /*