brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / drivers / ide / raid / silraid.c
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
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
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
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
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
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
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
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
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                            
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
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
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
474 static int silraid_open(struct inode * inode, struct file * filp) 
475 {
476         MOD_INC_USE_COUNT;
477         return 0;
478 }
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");