1 /******************************************************************************
4 * XenLinux virtual block-device driver (xvd).
6 * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
7 * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
8 * Copyright (c) 2004-2005, Christian Limpach
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation; or, when distributed
13 * separately from the Linux kernel or incorporated into other
14 * software packages, subject to the following license:
16 * Permission is hereby granted, free of charge, to any person obtaining a copy
17 * of this source file (the "Software"), to deal in the Software without
18 * restriction, including without limitation the rights to use, copy, modify,
19 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
20 * and to permit persons to whom the Software is furnished to do so, subject to
21 * the following conditions:
23 * The above copyright notice and this permission notice shall be included in
24 * all copies or substantial portions of the Software.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
36 #include <linux/bitmap.h>
37 #include <linux/blkdev.h>
38 #include <linux/list.h>
40 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
41 #include <xen/platform-compat.h>
44 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
45 #define XENVBD_MAJOR 202
48 #define BLKIF_MAJOR(dev) ((dev)>>8)
49 #define BLKIF_MINOR(dev) ((dev) & 0xff)
52 #define EXTENDED (1<<EXT_SHIFT)
53 #define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
54 #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
56 struct xlbd_minor_state {
58 unsigned long *bitmap;
63 * For convenience we distinguish between ide, scsi and 'other' (i.e.,
64 * potentially combinations of the two) in the naming scheme and in a few other
68 #define NUM_IDE_MAJORS 10
69 #define NUM_SD_MAJORS 16
70 #define NUM_VBD_MAJORS 2
80 static const struct xlbd_type_info xlbd_ide_type = {
87 static const struct xlbd_type_info xlbd_sd_type = {
89 .disks_per_major = 16,
94 static const struct xlbd_type_info xlbd_sr_type = {
96 .disks_per_major = 256,
101 static const struct xlbd_type_info xlbd_vbd_type = {
103 .disks_per_major = 16,
108 static const struct xlbd_type_info xlbd_vbd_type_ext = {
110 .disks_per_major = 256,
115 static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SD_MAJORS + 1 +
118 #define XLBD_MAJOR_IDE_START 0
119 #define XLBD_MAJOR_SD_START (NUM_IDE_MAJORS)
120 #define XLBD_MAJOR_SR_START (NUM_IDE_MAJORS + NUM_SD_MAJORS)
121 #define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SD_MAJORS + 1)
123 #define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SD_START - 1
124 #define XLBD_MAJOR_SD_RANGE XLBD_MAJOR_SD_START ... XLBD_MAJOR_SR_START - 1
125 #define XLBD_MAJOR_SR_RANGE XLBD_MAJOR_SR_START
126 #define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
128 #define XLBD_MAJOR_VBD_ALT(idx) ((idx) ^ XLBD_MAJOR_VBD_START ^ (XLBD_MAJOR_VBD_START + 1))
130 static const struct block_device_operations xlvbd_block_fops =
132 .owner = THIS_MODULE,
134 .release = blkif_release,
135 .ioctl = blkif_ioctl,
136 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
137 .getgeo = blkif_getgeo
141 static struct xlbd_major_info *
142 xlbd_alloc_major_info(int major, int minor, int index)
144 struct xlbd_major_info *ptr;
145 struct xlbd_minor_state *minors;
148 ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
153 minors = kmalloc(sizeof(*minors), GFP_KERNEL);
154 if (minors == NULL) {
159 minors->bitmap = kzalloc(BITS_TO_LONGS(256) * sizeof(*minors->bitmap),
161 if (minors->bitmap == NULL) {
167 spin_lock_init(&minors->lock);
172 case XLBD_MAJOR_IDE_RANGE:
173 ptr->type = &xlbd_ide_type;
174 ptr->index = index - XLBD_MAJOR_IDE_START;
176 case XLBD_MAJOR_SD_RANGE:
177 ptr->type = &xlbd_sd_type;
178 ptr->index = index - XLBD_MAJOR_SD_START;
180 case XLBD_MAJOR_SR_RANGE:
181 ptr->type = &xlbd_sr_type;
182 ptr->index = index - XLBD_MAJOR_SR_START;
184 case XLBD_MAJOR_VBD_RANGE:
186 if ((index - XLBD_MAJOR_VBD_START) == 0)
187 ptr->type = &xlbd_vbd_type;
189 ptr->type = &xlbd_vbd_type_ext;
192 * if someone already registered block major XENVBD_MAJOR,
193 * don't try to register it again
195 if (major_info[XLBD_MAJOR_VBD_ALT(index)] != NULL) {
196 kfree(minors->bitmap);
198 minors = major_info[XLBD_MAJOR_VBD_ALT(index)]->minors;
205 if (register_blkdev(ptr->major, ptr->type->devname)) {
206 kfree(minors->bitmap);
212 pr_info("xen-vbd: registered block device major %i\n",
216 ptr->minors = minors;
217 major_info[index] = ptr;
221 static struct xlbd_major_info *
222 xlbd_get_major_info(int major, int minor, int vdevice)
224 struct xlbd_major_info *mi;
228 case IDE0_MAJOR: index = 0; break;
229 case IDE1_MAJOR: index = 1; break;
230 case IDE2_MAJOR: index = 2; break;
231 case IDE3_MAJOR: index = 3; break;
232 case IDE4_MAJOR: index = 4; break;
233 case IDE5_MAJOR: index = 5; break;
234 case IDE6_MAJOR: index = 6; break;
235 case IDE7_MAJOR: index = 7; break;
236 case IDE8_MAJOR: index = 8; break;
237 case IDE9_MAJOR: index = 9; break;
238 case SCSI_DISK0_MAJOR: index = XLBD_MAJOR_SD_START; break;
239 case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
240 index = XLBD_MAJOR_SD_START + 1 + major - SCSI_DISK1_MAJOR;
242 case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR:
243 index = XLBD_MAJOR_SD_START + 8 + major - SCSI_DISK8_MAJOR;
245 case SCSI_CDROM_MAJOR:
246 index = XLBD_MAJOR_SR_START;
249 index = XLBD_MAJOR_VBD_START + !!VDEV_IS_EXTENDED(vdevice);
255 mi = ((major_info[index] != NULL) ? major_info[index] :
256 xlbd_alloc_major_info(major, minor, index));
263 xlbd_put_major_info(struct xlbd_major_info *mi)
266 /* XXX: release major if 0 */
270 xlbd_release_major_info(void)
275 for (i = 0; i < ARRAY_SIZE(major_info); ++i) {
276 struct xlbd_major_info *mi = major_info[i];
281 pr_warning("vbd: major %u still in use (%u times)\n",
282 mi->major, mi->usage);
283 if (mi->major != XENVBD_MAJOR || !vbd_done) {
284 unregister_blkdev(mi->major, mi->type->devname);
285 kfree(mi->minors->bitmap);
288 if (mi->major == XENVBD_MAJOR)
295 xlbd_reserve_minors(struct xlbd_major_info *mi, unsigned int minor,
296 unsigned int nr_minors)
298 struct xlbd_minor_state *ms = mi->minors;
299 unsigned int end = minor + nr_minors;
303 unsigned long *bitmap, *old;
305 bitmap = kcalloc(BITS_TO_LONGS(end), sizeof(*bitmap),
310 spin_lock(&ms->lock);
313 memcpy(bitmap, ms->bitmap,
314 BITS_TO_LONGS(ms->nr) * sizeof(*bitmap));
316 ms->nr = BITS_TO_LONGS(end) * BITS_PER_LONG;
319 spin_unlock(&ms->lock);
323 spin_lock(&ms->lock);
324 if (find_next_bit(ms->bitmap, end, minor) >= end) {
325 bitmap_set(ms->bitmap, minor, nr_minors);
329 spin_unlock(&ms->lock);
335 xlbd_release_minors(struct xlbd_major_info *mi, unsigned int minor,
336 unsigned int nr_minors)
338 struct xlbd_minor_state *ms = mi->minors;
340 BUG_ON(minor + nr_minors > ms->nr);
341 spin_lock(&ms->lock);
342 bitmap_clear(ms->bitmap, minor, nr_minors);
343 spin_unlock(&ms->lock);
346 static char *encode_disk_name(char *ptr, unsigned int n)
349 ptr = encode_disk_name(ptr, n / 26 - 1);
355 xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
356 struct blkfront_info *info)
358 struct request_queue *rq;
360 rq = blk_init_queue(do_blkif_request, &info->io_lock);
364 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
365 queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
368 if (info->feature_discard) {
369 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, rq);
370 blk_queue_max_discard_sectors(rq, get_capacity(gd));
371 rq->limits.discard_granularity = info->discard_granularity;
372 rq->limits.discard_alignment = info->discard_alignment;
373 if (info->feature_secdiscard)
374 queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq);
377 /* Hard sector size and max sectors impersonate the equiv. hardware. */
378 blk_queue_logical_block_size(rq, sector_size);
379 blk_queue_max_hw_sectors(rq, 512);
381 /* Each segment in a request is up to an aligned page in size. */
382 blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
383 blk_queue_max_segment_size(rq, PAGE_SIZE);
385 /* Ensure a merged request will fit in a single I/O ring slot. */
386 blk_queue_max_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
388 /* Make sure buffer addresses are sector-aligned. */
389 blk_queue_dma_alignment(rq, 511);
391 /* Make sure we don't use bounce buffers. */
392 blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
401 xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
402 u16 sector_size, struct blkfront_info *info)
406 struct xlbd_major_info *mi;
412 if ((vdevice>>EXT_SHIFT) > 1) {
413 /* this is above the extended range; something is wrong */
414 pr_warning("blkfront: vdevice %#x is above the extended range;"
415 " ignoring\n", vdevice);
419 if (!VDEV_IS_EXTENDED(vdevice)) {
420 major = BLKIF_MAJOR(vdevice);
421 minor = BLKIF_MINOR(vdevice);
424 major = XENVBD_MAJOR;
425 minor = BLKIF_MINOR_EXT(vdevice);
426 if (minor >> MINORBITS) {
427 pr_warning("blkfront: %#x's minor (%#x) out of range;"
428 " ignoring\n", vdevice, minor);
433 BUG_ON(info->gd != NULL);
434 BUG_ON(info->mi != NULL);
435 BUG_ON(info->rq != NULL);
437 mi = xlbd_get_major_info(major, minor, vdevice);
442 if ((vdisk_info & VDISK_CDROM) ||
443 !(minor & ((1 << mi->type->partn_shift) - 1)))
444 nr_minors = 1 << mi->type->partn_shift;
446 err = xlbd_reserve_minors(mi, minor & ~(nr_minors - 1), nr_minors);
451 gd = alloc_disk(vdisk_info & VDISK_CDROM ? 1 : nr_minors);
455 strcpy(gd->disk_name, mi->type->diskname);
456 ptr = gd->disk_name + strlen(mi->type->diskname);
457 offset = mi->index * mi->type->disks_per_major +
458 (minor >> mi->type->partn_shift);
459 if (mi->type->partn_shift) {
460 ptr = encode_disk_name(ptr, offset);
461 offset = minor & ((1 << mi->type->partn_shift) - 1);
463 gd->flags |= GENHD_FL_CD;
464 BUG_ON(ptr >= gd->disk_name + ARRAY_SIZE(gd->disk_name));
468 snprintf(ptr, gd->disk_name + ARRAY_SIZE(gd->disk_name) - ptr,
471 gd->major = mi->major;
472 gd->first_minor = minor;
473 gd->fops = &xlvbd_block_fops;
474 gd->private_data = info;
475 gd->driverfs_dev = &(info->xbdev->dev);
476 set_capacity(gd, capacity);
478 if (xlvbd_init_blk_queue(gd, sector_size, info)) {
487 if (vdisk_info & VDISK_READONLY)
490 if (vdisk_info & VDISK_REMOVABLE)
491 gd->flags |= GENHD_FL_REMOVABLE;
493 if (vdisk_info & VDISK_CDROM)
494 gd->flags |= GENHD_FL_CD;
499 xlbd_release_minors(mi, minor, nr_minors);
502 xlbd_put_major_info(mi);
508 xlvbd_del(struct blkfront_info *info)
510 unsigned int minor, nr_minors;
512 if (info->mi == NULL)
515 BUG_ON(info->gd == NULL);
516 minor = info->gd->first_minor;
517 nr_minors = (info->gd->flags & GENHD_FL_CD)
518 || !(minor & ((1 << info->mi->type->partn_shift) - 1))
519 ? 1 << info->mi->type->partn_shift : 1;
520 del_gendisk(info->gd);
524 xlbd_release_minors(info->mi, minor & ~(nr_minors - 1), nr_minors);
525 xlbd_put_major_info(info->mi);
528 BUG_ON(info->rq == NULL);
529 blk_cleanup_queue(info->rq);
534 xlvbd_flush(struct blkfront_info *info)
536 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
537 blk_queue_flush(info->rq, info->feature_flush);
538 pr_info("blkfront: %s: %s: %s\n",
540 info->flush_op == BLKIF_OP_WRITE_BARRIER ?
541 "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
542 "flush diskcache" : "barrier or flush"),
543 info->feature_flush ? "enabled" : "disabled");
544 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
548 switch (info->feature_flush) {
549 case QUEUE_ORDERED_DRAIN: barrier = "enabled (drain)"; break;
550 case QUEUE_ORDERED_TAG: barrier = "enabled (tag)"; break;
551 case QUEUE_ORDERED_NONE: barrier = "disabled"; break;
552 default: return -EINVAL;
555 err = blk_queue_ordered(info->rq, info->feature_flush);
558 pr_info("blkfront: %s: barriers %s\n",
559 info->gd->disk_name, barrier);
561 if (info->feature_flush)
562 pr_info("blkfront: %s: barriers disabled\n", info->gd->disk_name);
567 static ssize_t show_media(struct device *dev,
568 struct device_attribute *attr, char *buf)
570 struct xenbus_device *xendev = to_xenbus_device(dev);
571 struct blkfront_info *info = dev_get_drvdata(&xendev->dev);
573 if (info->gd->flags & GENHD_FL_CD)
574 return sprintf(buf, "cdrom\n");
575 return sprintf(buf, "disk\n");
578 static struct device_attribute xlvbd_attrs[] = {
579 __ATTR(media, S_IRUGO, show_media, NULL),
582 int xlvbd_sysfs_addif(struct blkfront_info *info)
587 for (i = 0; i < ARRAY_SIZE(xlvbd_attrs); i++) {
588 error = device_create_file(info->gd->driverfs_dev,
597 device_remove_file(info->gd->driverfs_dev, &xlvbd_attrs[i]);
601 void xlvbd_sysfs_delif(struct blkfront_info *info)
605 for (i = 0; i < ARRAY_SIZE(xlvbd_attrs); i++)
606 device_remove_file(info->gd->driverfs_dev, &xlvbd_attrs[i]);
609 #endif /* CONFIG_SYSFS */