1 /*
2    silraid.c  Copyright (C) 2002 Red Hat, Inc. All rights reserved.
3 
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.
7 
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.
19 
20    Authors: 	Arjan van de Ven <arjanv@redhat.com>
21 
22 
23 */
24 
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>
34 
35 #include <linux/ide.h>
36 #include <asm/uaccess.h>
37 
38 #include "ataraid.h"
39 
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);
44 
45 struct disk_dev {
46 	int major;
47 	int minor;
48 	int device;
49 };
50 
51 static struct disk_dev devlist[]= {
52 	{IDE0_MAJOR,  0,  -1 },
53 	{IDE0_MAJOR, 64,  -1 },
54 	{IDE1_MAJOR,  0,  -1 },
55 	{IDE1_MAJOR, 64,  -1 },
56 	{IDE2_MAJOR,  0,  -1 },
57 	{IDE2_MAJOR, 64,  -1 },
58 	{IDE3_MAJOR,  0,  -1 },
59 	{IDE3_MAJOR, 64,  -1 },
60 	{IDE4_MAJOR,  0,  -1 },
61 	{IDE4_MAJOR, 64,  -1 },
62 	{IDE5_MAJOR,  0,  -1 },
63 	{IDE5_MAJOR, 64,  -1 },
64 	{IDE6_MAJOR,  0,  -1 },
65 	{IDE6_MAJOR, 64,  -1 },
66 };
67 
68 
69 struct sildisk {
70 	kdev_t	device;
71 	unsigned long sectors;
72 	struct block_device *bdev;
73 	unsigned long last_pos;
74 };
75 
76 struct silraid {
77 	unsigned int stride;
78 	unsigned int disks;
79 	unsigned long sectors;
80 	struct geom geom;
81 
82 	struct sildisk disk[8];
83 
84 	unsigned long cutoff[8];
85 	unsigned int cutoff_disks[8];
86 };
87 
88 static struct raid_device_operations silraid0_ops = {
89         open:                   silraid_open,
90 	release:                silraid_release,
91 	ioctl:			silraid_ioctl,
92 	make_request:		silraid0_make_request
93 };
94 
95 static struct silraid raid[16];
96 
97 
silraid_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)98 static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
99 {
100 	unsigned int minor;
101    	unsigned long sectors;
102 
103 	if (!inode || !inode->i_rdev)
104 		return -EINVAL;
105 
106 	minor = MINOR(inode->i_rdev)>>SHIFT;
107 
108 	switch (cmd) {
109 
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);
116 			break;
117 
118 
119 		case HDIO_GETGEO:
120 		{
121 			struct hd_geometry *loc = (struct hd_geometry *) arg;
122 			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
123 
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;
130 			return 0;
131 		}
132 
133 		case HDIO_GETGEO_BIG:
134 		{
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;
142 			return 0;
143 		}
144 
145 
146 		case BLKROSET:
147 		case BLKROGET:
148 		case BLKSSZGET:
149 			return blk_ioctl(inode->i_rdev, cmd, arg);
150 
151 		default:
152 			printk("Invalid ioctl \n");
153 			return -EINVAL;
154 	};
155 
156 	return 0;
157 }
158 
159 
partition_map_normal(unsigned long block,unsigned long partition_off,unsigned long partition_size,int stride)160 static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
161 {
162 	return block + partition_off;
163 }
164 
silraid0_make_request(request_queue_t * q,int rw,struct buffer_head * bh)165 static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
166 {
167 	unsigned long rsect;
168 	unsigned long rsect_left,rsect_accum = 0;
169 	unsigned long block;
170 	unsigned int disk=0,real_disk=0;
171 	int i;
172 	int device;
173 	struct silraid *thisraid;
174 
175 	rsect = bh->b_rsector;
176 
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.
183 	 *
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.
187 	 */
188 
189 	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
190 	thisraid = &raid[device];
191 	if (thisraid->stride==0)
192 		thisraid->stride=1;
193 
194 	/* Partitions need adding of the start sector of the partition to the requested sector */
195 
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);
197 
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)) {
200 		return -1;
201 	}
202 
203 	rsect_left = rsect;
204 
205 	for (i=0;i<8;i++) {
206 		if (thisraid->cutoff_disks[i]==0)
207 			break;
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];
212 		} else {
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;
217 			break;
218 		}
219 	}
220 
221 	for (i=0;i<8;i++) {
222 		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
223 			real_disk = i;
224 			break;
225 		}
226 		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
227 			disk--;
228 		}
229 
230 	}
231 	disk = real_disk;
232 
233 
234 	/*
235 	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
236 	 * is the only IO operation happening on this bh.
237 	 */
238 	bh->b_rdev = thisraid->disk[disk].device;
239 	bh->b_rsector = rsect;
240 
241 	/*
242 	 * Let the main block layer submit the IO and resolve recursion:
243 	 */
244 	return 1;
245 }
246 
247 #include "silraid.h"
248 
calc_silblock_offset(int major,int minor)249 static unsigned long calc_silblock_offset (int major,int minor)
250 {
251 	unsigned long lba = 0, cylinders;
252 	kdev_t dev;
253 	ide_drive_t *ideinfo;
254 
255 	dev = MKDEV(major,minor);
256 	ideinfo = ide_info_ptr (dev, 0);
257 	if (ideinfo==NULL)
258 		return 0;
259 
260 
261 	/* last sector second to last cylinder */
262 	if (ideinfo->head==0)
263 		return 0;
264 	if (ideinfo->sect==0)
265 		return 0;
266 	cylinders = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
267 	lba = (cylinders - 1) * (ideinfo->head*ideinfo->sect);
268 	lba = lba - ideinfo->head -1;
269 
270 //	return 80417215;
271 	printk("Guestimating sector %li for superblock\n",lba);
272 	return lba;
273 
274 }
275 
276 
277 
read_disk_sb(int major,int minor,unsigned char * buffer,int bufsize)278 static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
279 {
280 	int ret = -EINVAL;
281 	struct buffer_head *bh = NULL;
282 	kdev_t dev = MKDEV(major,minor);
283 	unsigned long sb_offset;
284 
285 	if (blksize_size[major]==NULL)   /* device doesn't exist */
286 		return -EINVAL;
287 
288 
289 	/*
290 	 * Calculate the position of the superblock,
291 	 * it's at first sector of the last cylinder
292 	 */
293 	sb_offset = calc_silblock_offset(major,minor)/8;
294 	/* The /8 transforms sectors into 4Kb blocks */
295 
296 	if (sb_offset==0)
297 		return -1;
298 
299 	set_blocksize (dev, 4096);
300 
301 	bh = bread (dev, sb_offset, 4096);
302 
303 	if (bh) {
304 		memcpy (buffer, bh->b_data, bufsize);
305 	} else {
306 		printk(KERN_ERR "silraid: Error reading superblock.\n");
307 		goto abort;
308 	}
309 	ret = 0;
310 abort:
311 	if (bh)
312 		brelse (bh); return ret;
313 }
314 
checksum1(unsigned short * buffer)315 static unsigned short checksum1(unsigned short *buffer)
316 {
317 	int i;
318 	int sum = 0;
319 	for (i=0; i<0x13f/2; i++)
320 		sum += buffer[i];
321 	return (-sum)&0xFFFF;
322 }
323 
324 static int cookie = 0;
325 
probedisk(int devindex,int device,int raidlevel)326 static void __init probedisk(int devindex,int device, int raidlevel)
327 {
328 	int i;
329 	int major, minor;
330         struct signature *superblock;
331 	static unsigned char block[4096];
332 	struct block_device *bdev;
333 
334 	if (devlist[devindex].device!=-1) /* already assigned to another array */
335 		return;
336 
337 	major = devlist[devindex].major;
338 	minor = devlist[devindex].minor;
339 
340         if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
341         	return;
342 
343         superblock = (struct signature*)&block[4096-512];
344 
345         if (superblock->unknown[0] != 'Z') /* Need better check here */
346         	return;
347 
348         if (superblock->checksum1 != checksum1((unsigned short*)superblock))
349         	return;
350 
351 
352 
353 	if (superblock->raidlevel!=raidlevel) /* different raidlevel */
354 		return;
355 
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;
359 
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;
363 	}
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;
372 
373 	devlist[devindex].device=device;
374 
375 }
376 
fill_cutoff(int device)377 static void __init fill_cutoff(int device)
378 {
379 	int i,j;
380 	unsigned long smallest;
381 	unsigned long bar;
382 	int count;
383 
384 	bar = 0;
385 	for (i=0;i<8;i++) {
386 		smallest = ~0;
387 		for (j=0;j<8;j++)
388 			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
389 				smallest = raid[device].disk[j].sectors;
390 		count = 0;
391 		for (j=0;j<8;j++)
392 			if (raid[device].disk[j].sectors >= smallest)
393 				count++;
394 
395 		smallest = smallest * count;
396 		bar = smallest;
397 		raid[device].cutoff[i] = smallest;
398 		raid[device].cutoff_disks[i] = count;
399 	}
400 }
401 
silraid_init_one(int device,int raidlevel)402 static __init int silraid_init_one(int device,int raidlevel)
403 {
404 	int i, count;
405 
406 	for (i=0; i<14; i++)
407 		probedisk(i, device, raidlevel);
408 
409 	if (raidlevel==0)
410 		fill_cutoff(device);
411 
412 	/* Initialize the gendisk structure */
413 
414 	ataraid_register_disk(device,raid[device].sectors);
415 
416 	count=0;
417 
418 	for (i=0;i<8;i++) {
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));
422 			count++;
423 		}
424 	}
425 	if (count) {
426 		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
427 		return 0;
428 	} else {
429 		return -ENODEV;
430 	}
431 }
432 
silraid_init(void)433 static __init int silraid_init(void)
434 {
435 	int retval, device, count = 0;
436 
437 	do {
438 		cookie = 0;
439 		device=ataraid_get_device(&silraid0_ops);
440 		if (device<0)
441 			break;
442 		retval = silraid_init_one(device,0);
443 		if (retval) {
444 			ataraid_release_device(device);
445 			break;
446 		} else {
447 			count++;
448 		}
449 	} while (1);
450 
451 	if (count) {
452 		printk(KERN_INFO "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1\n");
453 		return 0;
454 	}
455 	printk(KERN_DEBUG "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1: No raid array found\n");
456 	return -ENODEV;
457 }
458 
silraid_exit(void)459 static void __exit silraid_exit (void)
460 {
461 	int i,device;
462 	for (device = 0; device<16; device++) {
463 		for (i=0;i<8;i++) {
464 			struct block_device *bdev = raid[device].disk[i].bdev;
465 			raid[device].disk[i].bdev = NULL;
466 			if (bdev)
467 				blkdev_put(bdev, BDEV_RAW);
468 		}
469 		if (raid[device].sectors)
470 			ataraid_release_device(device);
471 	}
472 }
473 
silraid_open(struct inode * inode,struct file * filp)474 static int silraid_open(struct inode * inode, struct file * filp)
475 {
476 	MOD_INC_USE_COUNT;
477 	return 0;
478 }
silraid_release(struct inode * inode,struct file * filp)479 static int silraid_release(struct inode * inode, struct file * filp)
480 {
481 	MOD_DEC_USE_COUNT;
482 	return 0;
483 }
484 
485 module_init(silraid_init);
486 module_exit(silraid_exit);
487 MODULE_LICENSE("GPL and additional rights");
488