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,
94 .getgeo = blkif_getgeo
97 DEFINE_SPINLOCK(blkif_io_lock);
99 static struct xlbd_major_info *
100 xlbd_alloc_major_info(int major, int minor, int index)
102 struct xlbd_major_info *ptr;
104 ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
111 case XLBD_MAJOR_IDE_RANGE:
112 ptr->type = &xlbd_ide_type;
113 ptr->index = index - XLBD_MAJOR_IDE_START;
115 case XLBD_MAJOR_SCSI_RANGE:
116 ptr->type = &xlbd_scsi_type;
117 ptr->index = index - XLBD_MAJOR_SCSI_START;
119 case XLBD_MAJOR_VBD_RANGE:
120 ptr->type = &xlbd_vbd_type;
121 ptr->index = index - XLBD_MAJOR_VBD_START;
125 printk("Registering block device major %i\n", ptr->major);
126 if (register_blkdev(ptr->major, ptr->type->devname)) {
127 WPRINTK("can't get major %d with name %s\n",
128 ptr->major, ptr->type->devname);
133 devfs_mk_dir(ptr->type->devname);
134 major_info[index] = ptr;
138 static struct xlbd_major_info *
139 xlbd_get_major_info(int vdevice)
141 struct xlbd_major_info *mi;
142 int major, minor, index;
144 major = BLKIF_MAJOR(vdevice);
145 minor = BLKIF_MINOR(vdevice);
148 case IDE0_MAJOR: index = 0; break;
149 case IDE1_MAJOR: index = 1; break;
150 case IDE2_MAJOR: index = 2; break;
151 case IDE3_MAJOR: index = 3; break;
152 case IDE4_MAJOR: index = 4; break;
153 case IDE5_MAJOR: index = 5; break;
154 case IDE6_MAJOR: index = 6; break;
155 case IDE7_MAJOR: index = 7; break;
156 case IDE8_MAJOR: index = 8; break;
157 case IDE9_MAJOR: index = 9; break;
158 case SCSI_DISK0_MAJOR: index = 10; break;
159 case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
160 index = 11 + major - SCSI_DISK1_MAJOR;
162 case SCSI_CDROM_MAJOR: index = 18; break;
163 default: index = 19; break;
166 mi = ((major_info[index] != NULL) ? major_info[index] :
167 xlbd_alloc_major_info(major, minor, index));
174 xlbd_put_major_info(struct xlbd_major_info *mi)
177 /* XXX: release major if 0 */
181 xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
185 rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
189 elevator_init(rq, "noop");
191 /* Hard sector size and max sectors impersonate the equiv. hardware. */
192 blk_queue_hardsect_size(rq, sector_size);
193 blk_queue_max_sectors(rq, 512);
195 /* Each segment in a request is up to an aligned page in size. */
196 blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
197 blk_queue_max_segment_size(rq, PAGE_SIZE);
199 /* Ensure a merged request will fit in a single I/O ring slot. */
200 blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
201 blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
203 /* Make sure buffer addresses are sector-aligned. */
204 blk_queue_dma_alignment(rq, 511);
212 xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
213 u16 vdisk_info, u16 sector_size,
214 struct blkfront_info *info)
217 struct xlbd_major_info *mi;
221 BUG_ON(info->gd != NULL);
222 BUG_ON(info->mi != NULL);
223 BUG_ON(info->rq != NULL);
225 mi = xlbd_get_major_info(vdevice);
230 if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
231 nr_minors = 1 << mi->type->partn_shift;
233 gd = alloc_disk(nr_minors);
238 sprintf(gd->disk_name, "%s%c", mi->type->diskname,
239 'a' + mi->index * mi->type->disks_per_major +
240 (minor >> mi->type->partn_shift));
242 sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
243 'a' + mi->index * mi->type->disks_per_major +
244 (minor >> mi->type->partn_shift),
245 minor & ((1 << mi->type->partn_shift) - 1));
247 gd->major = mi->major;
248 gd->first_minor = minor;
249 gd->fops = &xlvbd_block_fops;
250 gd->private_data = info;
251 gd->driverfs_dev = &(info->xbdev->dev);
252 set_capacity(gd, capacity);
254 if (xlvbd_init_blk_queue(gd, sector_size)) {
259 info->rq = gd->queue;
261 if (vdisk_info & VDISK_READONLY)
264 if (vdisk_info & VDISK_REMOVABLE)
265 gd->flags |= GENHD_FL_REMOVABLE;
267 if (vdisk_info & VDISK_CDROM)
268 gd->flags |= GENHD_FL_CD;
276 xlbd_put_major_info(mi);
282 xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
283 u16 sector_size, struct blkfront_info *info)
285 struct block_device *bd;
288 info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
290 bd = bdget(info->dev);
294 err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
295 vdisk_info, sector_size, info);
302 xlvbd_del(struct blkfront_info *info)
304 if (info->mi == NULL)
307 BUG_ON(info->gd == NULL);
308 del_gendisk(info->gd);
312 xlbd_put_major_info(info->mi);
315 BUG_ON(info->rq == NULL);
316 blk_cleanup_queue(info->rq);