2 silraid.c Copyright (C) 2002 Red Hat, Inc. All rights reserved.
4 The contents of this file are subject to the Open Software License version 1.1
5 that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is
6 included herein by reference.
8 Alternatively, the contents of this file may be used under the
9 terms of the GNU General Public License version 2 (the "GPL") as
10 distributed in the kernel source COPYING file, in which
11 case the provisions of the GPL are applicable instead of the
12 above. If you wish to allow the use of your version of this file
13 only under the terms of the GPL and not to allow others to use
14 your version of this file under the OSL, indicate your decision
15 by deleting the provisions above and replace them with the notice
16 and other provisions required by the GPL. If you do not delete
17 the provisions above, a recipient may use your version of this
18 file under either the OSL or the GPL.
20 Authors: Arjan van de Ven <arjanv@redhat.com>
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/smp_lock.h>
30 #include <linux/blkdev.h>
31 #include <linux/blkpg.h>
32 #include <linux/genhd.h>
33 #include <linux/ioctl.h>
35 #include <linux/ide.h>
36 #include <asm/uaccess.h>
40 static int silraid_open(struct inode * inode, struct file * filp);
41 static int silraid_release(struct inode * inode, struct file * filp);
42 static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
43 static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
51 static struct disk_dev devlist[]= {
53 {IDE0_MAJOR, 64, -1 },
55 {IDE1_MAJOR, 64, -1 },
57 {IDE2_MAJOR, 64, -1 },
59 {IDE3_MAJOR, 64, -1 },
61 {IDE4_MAJOR, 64, -1 },
63 {IDE5_MAJOR, 64, -1 },
65 {IDE6_MAJOR, 64, -1 },
71 unsigned long sectors;
72 struct block_device *bdev;
73 unsigned long last_pos;
79 unsigned long sectors;
82 struct sildisk disk[8];
84 unsigned long cutoff[8];
85 unsigned int cutoff_disks[8];
88 static struct raid_device_operations silraid0_ops = {
90 release: silraid_release,
92 make_request: silraid0_make_request
95 static struct silraid raid[16];
98 static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
101 unsigned long sectors;
103 if (!inode || !inode->i_rdev)
106 minor = MINOR(inode->i_rdev)>>SHIFT;
110 case BLKGETSIZE: /* Return device size */
111 if (!arg) return -EINVAL;
112 sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
113 if (MINOR(inode->i_rdev)&15)
114 return put_user(sectors, (unsigned long *) arg);
115 return put_user(raid[minor].sectors , (unsigned long *) arg);
121 struct hd_geometry *loc = (struct hd_geometry *) arg;
122 unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
124 if (!loc) return -EINVAL;
125 if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
126 if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
127 if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
128 if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
129 (unsigned long *) &loc->start)) return -EFAULT;
133 case HDIO_GETGEO_BIG:
135 struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
136 if (!loc) return -EINVAL;
137 if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
138 if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
139 if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
140 if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
141 (unsigned long *) &loc->start)) return -EFAULT;
149 return blk_ioctl(inode->i_rdev, cmd, arg);
152 printk("Invalid ioctl \n");
160 static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
162 return block + partition_off;
165 static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
168 unsigned long rsect_left,rsect_accum = 0;
170 unsigned int disk=0,real_disk=0;
173 struct silraid *thisraid;
175 rsect = bh->b_rsector;
177 /* Ok. We need to modify this sector number to a new disk + new sector number.
178 * If there are disks of different sizes, this gets tricky.
179 * Example with 3 disks (1Gb, 4Gb and 5 GB):
180 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
181 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
182 * and the last 1Gb is disk 3 only.
184 * the way this is solved is like this: We have a list of "cutoff" points where everytime
185 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
186 * point, we have to divide by one less.
189 device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
190 thisraid = &raid[device];
191 if (thisraid->stride==0)
194 /* Partitions need adding of the start sector of the partition to the requested sector */
196 rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
198 /* Woops we need to split the request to avoid crossing a stride barrier */
199 if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
206 if (thisraid->cutoff_disks[i]==0)
208 if (rsect > thisraid->cutoff[i]) {
209 /* we're in the wrong area so far */
210 rsect_left -= thisraid->cutoff[i];
211 rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
213 block = rsect_left / thisraid->stride;
214 disk = block % thisraid->cutoff_disks[i];
215 block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
216 rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
222 if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
226 if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
235 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
236 * is the only IO operation happening on this bh.
238 bh->b_rdev = thisraid->disk[disk].device;
239 bh->b_rsector = rsect;
242 * Let the main block layer submit the IO and resolve recursion:
249 static unsigned long calc_silblock_offset (int major,int minor)
251 unsigned long lba = 0, cylinders;
253 ide_drive_t *ideinfo;
255 dev = MKDEV(major,minor);
256 ideinfo = ide_info_ptr (dev, 0);
261 /* last sector second to last cylinder */
262 if (ideinfo->head==0)
264 if (ideinfo->sect==0)
266 cylinders = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
267 lba = (cylinders - 1) * (ideinfo->head*ideinfo->sect);
268 lba = lba - ideinfo->head -1;
271 printk("Guestimating sector %li for superblock\n",lba);
278 static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
281 struct buffer_head *bh = NULL;
282 kdev_t dev = MKDEV(major,minor);
283 unsigned long sb_offset;
285 if (blksize_size[major]==NULL) /* device doesn't exist */
290 * Calculate the position of the superblock,
291 * it's at first sector of the last cylinder
293 sb_offset = calc_silblock_offset(major,minor)/8;
294 /* The /8 transforms sectors into 4Kb blocks */
299 set_blocksize (dev, 4096);
301 bh = bread (dev, sb_offset, 4096);
304 memcpy (buffer, bh->b_data, bufsize);
306 printk(KERN_ERR "silraid: Error reading superblock.\n");
312 brelse (bh); return ret;
315 static unsigned short checksum1(unsigned short *buffer)
319 for (i=0; i<0x13f/2; i++)
321 return (-sum)&0xFFFF;
324 static int cookie = 0;
326 static void __init probedisk(int devindex,int device, int raidlevel)
330 struct signature *superblock;
331 static unsigned char block[4096];
332 struct block_device *bdev;
334 if (devlist[devindex].device!=-1) /* already assigned to another array */
337 major = devlist[devindex].major;
338 minor = devlist[devindex].minor;
340 if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
343 superblock = (struct signature*)&block[4096-512];
345 if (superblock->unknown[0] != 'Z') /* Need better check here */
348 if (superblock->checksum1 != checksum1((unsigned short*)superblock))
353 if (superblock->raidlevel!=raidlevel) /* different raidlevel */
356 /* This looks evil. But basically, we have to search for our adapternumber
357 in the arraydefinition, both of which are in the superblock */
358 i = superblock->disk_in_set;
360 bdev = bdget(MKDEV(major,minor));
361 if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
362 raid[device].disk[i].bdev = bdev;
364 raid[device].disk[i].device = MKDEV(major,minor);
365 raid[device].disk[i].sectors = superblock->thisdisk_sectors;
366 raid[device].stride = superblock->raid0_sectors_per_stride;
367 raid[device].disks = superblock->disks_in_set;
368 raid[device].sectors = superblock->array_sectors;
369 raid[device].geom.heads = 255;
370 raid[device].geom.sectors = 63;
371 raid[device].geom.cylinders = raid[device].sectors / raid[device].geom.heads / raid[device].geom.sectors;
373 devlist[devindex].device=device;
377 static void __init fill_cutoff(int device)
380 unsigned long smallest;
388 if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
389 smallest = raid[device].disk[j].sectors;
392 if (raid[device].disk[j].sectors >= smallest)
395 smallest = smallest * count;
397 raid[device].cutoff[i] = smallest;
398 raid[device].cutoff_disks[i] = count;
402 static __init int silraid_init_one(int device,int raidlevel)
407 probedisk(i, device, raidlevel);
412 /* Initialize the gendisk structure */
414 ataraid_register_disk(device,raid[device].sectors);
419 if (raid[device].disk[i].device!=0) {
420 printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
421 i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
426 printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
433 static __init int silraid_init(void)
435 int retval, device, count = 0;
439 device=ataraid_get_device(&silraid0_ops);
442 retval = silraid_init_one(device,0);
444 ataraid_release_device(device);
452 printk(KERN_INFO "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1\n");
455 printk(KERN_DEBUG "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1: No raid array found\n");
459 static void __exit silraid_exit (void)
462 for (device = 0; device<16; device++) {
464 struct block_device *bdev = raid[device].disk[i].bdev;
465 raid[device].disk[i].bdev = NULL;
467 blkdev_put(bdev, BDEV_RAW);
469 if (raid[device].sectors)
470 ataraid_release_device(device);
474 static int silraid_open(struct inode * inode, struct file * filp)
479 static int silraid_release(struct inode * inode, struct file * filp)
485 module_init(silraid_init);
486 module_exit(silraid_exit);
487 MODULE_LICENSE("GPL and additional rights");