aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/virtio_blk.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2010-02-24 15:22:25 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:26 -0500
commit69740c8ba878f58bc3c71f74618fc2cd1da990da (patch)
tree95a86d35fe234db2fd08b10cab0400ad1b2e56dd /drivers/block/virtio_blk.c
parentd57ed95da483418e8b0433da693c9168dd0a2df6 (diff)
virtio_blk: add block topology support
Allow reading various alignment values from the config page. This allows the guest to much better align I/O requests depending on the storage topology. Note that the formats for the config values appear a bit messed up, but we follow the formats used by ATA and SCSI so they are expected in the storage world. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/block/virtio_blk.c')
-rw-r--r--drivers/block/virtio_blk.c61
1 files changed, 46 insertions, 15 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 51042f0ba7e1..7eff828b2117 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -243,10 +243,12 @@ static int index_to_minor(int index)
243static int __devinit virtblk_probe(struct virtio_device *vdev) 243static int __devinit virtblk_probe(struct virtio_device *vdev)
244{ 244{
245 struct virtio_blk *vblk; 245 struct virtio_blk *vblk;
246 struct request_queue *q;
246 int err; 247 int err;
247 u64 cap; 248 u64 cap;
248 u32 v; 249 u32 v, blk_size, sg_elems, opt_io_size;
249 u32 blk_size, sg_elems; 250 u16 min_io_size;
251 u8 physical_block_exp, alignment_offset;
250 252
251 if (index_to_minor(index) >= 1 << MINORBITS) 253 if (index_to_minor(index) >= 1 << MINORBITS)
252 return -ENOSPC; 254 return -ENOSPC;
@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
293 goto out_mempool; 295 goto out_mempool;
294 } 296 }
295 297
296 vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); 298 q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
297 if (!vblk->disk->queue) { 299 if (!q) {
298 err = -ENOMEM; 300 err = -ENOMEM;
299 goto out_put_disk; 301 goto out_put_disk;
300 } 302 }
301 303
302 vblk->disk->queue->queuedata = vblk; 304 q->queuedata = vblk;
303 305
304 if (index < 26) { 306 if (index < 26) {
305 sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); 307 sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
323 325
324 /* If barriers are supported, tell block layer that queue is ordered */ 326 /* If barriers are supported, tell block layer that queue is ordered */
325 if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) 327 if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
326 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH, 328 blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
327 virtblk_prepare_flush); 329 virtblk_prepare_flush);
328 else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) 330 else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
329 blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); 331 blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL);
330 332
331 /* If disk is read-only in the host, the guest should obey */ 333 /* If disk is read-only in the host, the guest should obey */
332 if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) 334 if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
345 set_capacity(vblk->disk, cap); 347 set_capacity(vblk->disk, cap);
346 348
347 /* We can handle whatever the host told us to handle. */ 349 /* We can handle whatever the host told us to handle. */
348 blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2); 350 blk_queue_max_phys_segments(q, vblk->sg_elems-2);
349 blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2); 351 blk_queue_max_hw_segments(q, vblk->sg_elems-2);
350 352
351 /* No need to bounce any requests */ 353 /* No need to bounce any requests */
352 blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY); 354 blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
353 355
354 /* No real sector limit. */ 356 /* No real sector limit. */
355 blk_queue_max_sectors(vblk->disk->queue, -1U); 357 blk_queue_max_sectors(q, -1U);
356 358
357 /* Host can optionally specify maximum segment size and number of 359 /* Host can optionally specify maximum segment size and number of
358 * segments. */ 360 * segments. */
@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
360 offsetof(struct virtio_blk_config, size_max), 362 offsetof(struct virtio_blk_config, size_max),
361 &v); 363 &v);
362 if (!err) 364 if (!err)
363 blk_queue_max_segment_size(vblk->disk->queue, v); 365 blk_queue_max_segment_size(q, v);
364 else 366 else
365 blk_queue_max_segment_size(vblk->disk->queue, -1U); 367 blk_queue_max_segment_size(q, -1U);
366 368
367 /* Host can optionally specify the block size of the device */ 369 /* Host can optionally specify the block size of the device */
368 err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, 370 err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
369 offsetof(struct virtio_blk_config, blk_size), 371 offsetof(struct virtio_blk_config, blk_size),
370 &blk_size); 372 &blk_size);
371 if (!err) 373 if (!err)
372 blk_queue_logical_block_size(vblk->disk->queue, blk_size); 374 blk_queue_logical_block_size(q, blk_size);
375 else
376 blk_size = queue_logical_block_size(q);
377
378 /* Use topology information if available */
379 err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
380 offsetof(struct virtio_blk_config, physical_block_exp),
381 &physical_block_exp);
382 if (!err && physical_block_exp)
383 blk_queue_physical_block_size(q,
384 blk_size * (1 << physical_block_exp));
385
386 err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
387 offsetof(struct virtio_blk_config, alignment_offset),
388 &alignment_offset);
389 if (!err && alignment_offset)
390 blk_queue_alignment_offset(q, blk_size * alignment_offset);
391
392 err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
393 offsetof(struct virtio_blk_config, min_io_size),
394 &min_io_size);
395 if (!err && min_io_size)
396 blk_queue_io_min(q, blk_size * min_io_size);
397
398 err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
399 offsetof(struct virtio_blk_config, opt_io_size),
400 &opt_io_size);
401 if (!err && opt_io_size)
402 blk_queue_io_opt(q, blk_size * opt_io_size);
403
373 404
374 add_disk(vblk->disk); 405 add_disk(vblk->disk);
375 return 0; 406 return 0;
@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = {
412static unsigned int features[] = { 443static unsigned int features[] = {
413 VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, 444 VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
414 VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, 445 VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
415 VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH 446 VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
416}; 447};
417 448
418/* 449/*