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/blkdev.h>
37 #include <linux/list.h>
39 #define BLKIF_MAJOR(dev) ((dev)>>8)
40 #define BLKIF_MINOR(dev) ((dev) & 0xff)
43 * For convenience we distinguish between ide, scsi and 'other' (i.e.,
44 * potentially combinations of the two) in the naming scheme and in a few other
48 #define NUM_IDE_MAJORS 10
49 #define NUM_SCSI_MAJORS 9
50 #define NUM_VBD_MAJORS 1
52 static struct xlbd_type_info xlbd_ide_type = {
59 static struct xlbd_type_info xlbd_scsi_type = {
61 .disks_per_major = 16,
66 static struct xlbd_type_info xlbd_vbd_type = {
68 .disks_per_major = 16,
73 static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
76 #define XLBD_MAJOR_IDE_START 0
77 #define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
78 #define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
80 #define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
81 #define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
82 #define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
84 /* Information about our VBDs. */
86 static LIST_HEAD(vbds_list);
88 static struct block_device_operations xlvbd_block_fops =
92 .release = blkif_release,
96 spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
98 static struct xlbd_major_info *
99 xlbd_alloc_major_info(int major, int minor, int index)
101 struct xlbd_major_info *ptr;
103 ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
110 case XLBD_MAJOR_IDE_RANGE:
111 ptr->type = &xlbd_ide_type;
112 ptr->index = index - XLBD_MAJOR_IDE_START;
114 case XLBD_MAJOR_SCSI_RANGE:
115 ptr->type = &xlbd_scsi_type;
116 ptr->index = index - XLBD_MAJOR_SCSI_START;
118 case XLBD_MAJOR_VBD_RANGE:
119 ptr->type = &xlbd_vbd_type;
120 ptr->index = index - XLBD_MAJOR_VBD_START;
124 printk("Registering block device major %i\n", ptr->major);
125 if (register_blkdev(ptr->major, ptr->type->devname)) {
126 WPRINTK("can't get major %d with name %s\n",
127 ptr->major, ptr->type->devname);
132 devfs_mk_dir(ptr->type->devname);
133 major_info[index] = ptr;
137 static struct xlbd_major_info *
138 xlbd_get_major_info(int vdevice)
140 struct xlbd_major_info *mi;
141 int major, minor, index;
143 major = BLKIF_MAJOR(vdevice);
144 minor = BLKIF_MINOR(vdevice);
147 case IDE0_MAJOR: index = 0; break;
148 case IDE1_MAJOR: index = 1; break;
149 case IDE2_MAJOR: index = 2; break;
150 case IDE3_MAJOR: index = 3; break;
151 case IDE4_MAJOR: index = 4; break;
152 case IDE5_MAJOR: index = 5; break;
153 case IDE6_MAJOR: index = 6; break;
154 case IDE7_MAJOR: index = 7; break;
155 case IDE8_MAJOR: index = 8; break;
156 case IDE9_MAJOR: index = 9; break;
157 case SCSI_DISK0_MAJOR: index = 10; break;
158 case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
159 index = 11 + major - SCSI_DISK1_MAJOR;
161 case SCSI_CDROM_MAJOR: index = 18; break;
162 default: index = 19; break;
165 mi = ((major_info[index] != NULL) ? major_info[index] :
166 xlbd_alloc_major_info(major, minor, index));
173 xlbd_put_major_info(struct xlbd_major_info *mi)
176 /* XXX: release major if 0 */
180 xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
184 rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
188 elevator_init(rq, "noop");
190 /* Hard sector size and max sectors impersonate the equiv. hardware. */
191 blk_queue_hardsect_size(rq, sector_size);
192 blk_queue_max_sectors(rq, 512);
194 /* Each segment in a request is up to an aligned page in size. */
195 blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
196 blk_queue_max_segment_size(rq, PAGE_SIZE);
198 /* Ensure a merged request will fit in a single I/O ring slot. */
199 blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
200 blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
202 /* Make sure buffer addresses are sector-aligned. */
203 blk_queue_dma_alignment(rq, 511);
211 xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
212 u16 vdisk_info, u16 sector_size,
213 struct blkfront_info *info)
216 struct xlbd_major_info *mi;
220 BUG_ON(info->gd != NULL);
221 BUG_ON(info->mi != NULL);
222 BUG_ON(info->rq != NULL);
224 mi = xlbd_get_major_info(vdevice);
229 if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
230 nr_minors = 1 << mi->type->partn_shift;
232 gd = alloc_disk(nr_minors);
237 sprintf(gd->disk_name, "%s%c", mi->type->diskname,
238 'a' + mi->index * mi->type->disks_per_major +
239 (minor >> mi->type->partn_shift));
241 sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
242 'a' + mi->index * mi->type->disks_per_major +
243 (minor >> mi->type->partn_shift),
244 minor & ((1 << mi->type->partn_shift) - 1));
246 gd->major = mi->major;
247 gd->first_minor = minor;
248 gd->fops = &xlvbd_block_fops;
249 gd->private_data = info;
250 gd->driverfs_dev = &(info->xbdev->dev);
251 set_capacity(gd, capacity);
253 if (xlvbd_init_blk_queue(gd, sector_size)) {
258 info->rq = gd->queue;
260 if (vdisk_info & VDISK_READONLY)
263 if (vdisk_info & VDISK_REMOVABLE)
264 gd->flags |= GENHD_FL_REMOVABLE;
266 if (vdisk_info & VDISK_CDROM)
267 gd->flags |= GENHD_FL_CD;
275 xlbd_put_major_info(mi);
281 xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
282 u16 sector_size, struct blkfront_info *info)
284 struct block_device *bd;
287 info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
289 bd = bdget(info->dev);
293 err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
294 vdisk_info, sector_size, info);
301 xlvbd_del(struct blkfront_info *info)
303 if (info->mi == NULL)
306 BUG_ON(info->gd == NULL);
307 del_gendisk(info->gd);
311 xlbd_put_major_info(info->mi);
314 BUG_ON(info->rq == NULL);
315 blk_cleanup_queue(info->rq);
321 * c-file-style: "linux"
322 * indent-tabs-mode: t