import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / partitions / amiga.c
1 /*
2  *  fs/partitions/amiga.c
3  *
4  *  Code extracted from drivers/block/genhd.c
5  *
6  *  Copyright (C) 1991-1998  Linus Torvalds
7  *  Re-organised Feb 1998 Russell King
8  */
9
10 #include <linux/fs.h>
11 #include <linux/genhd.h>
12 #include <linux/kernel.h>
13 #include <linux/major.h>
14 #include <linux/string.h>
15 #include <linux/blk.h>
16
17 #include <asm/byteorder.h>
18 #include <linux/affs_hardblocks.h>
19
20 #include "check.h"
21 #include "amiga.h"
22
23 static __inline__ u32
24 checksum_block(u32 *m, int size)
25 {
26         u32 sum = 0;
27
28         while (size--)
29                 sum += be32_to_cpu(*m++);
30         return sum;
31 }
32
33 int
34 amiga_partition(struct gendisk *hd, struct block_device *bdev,
35                 unsigned long first_sector, int first_part_minor)
36 {
37         Sector sect;
38         unsigned char *data;
39         struct RigidDiskBlock *rdb;
40         struct PartitionBlock *pb;
41         int start_sect, nr_sects, blk, part, res = 0;
42         kdev_t dev = to_kdev_t(bdev->bd_dev);
43
44         for (blk = 0; ; blk++, put_dev_sector(sect)) {
45                 if (blk == RDB_ALLOCATION_LIMIT)
46                         goto rdb_done;
47                 data = read_dev_sector(bdev, blk, &sect);
48                 if (!data) {
49                         if (warn_no_part)
50                                 printk("Dev %s: unable to read RDB block %d\n",
51                                        bdevname(dev), blk);
52                         goto rdb_done;
53                 }
54                 if (*(u32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
55                         continue;
56
57                 rdb = (struct RigidDiskBlock *)data;
58                 if (checksum_block((u32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
59                         break;
60                 /* Try again with 0xdc..0xdf zeroed, Windows might have
61                  * trashed it.
62                  */
63                 *(u32 *)(data+0xdc) = 0;
64                 if (checksum_block((u32 *)data,
65                                 be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
66                         printk("Warning: Trashed word at 0xd0 in block %d "
67                                 "ignored in checksum calculation\n",blk);
68                         break;
69                 }
70
71                 printk("Dev %s: RDB in block %d has bad checksum\n",
72                                bdevname(dev),blk);
73         }
74
75         printk(" RDSK");
76         blk = be32_to_cpu(rdb->rdb_PartitionList);
77         put_dev_sector(sect);
78         for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
79                 data = read_dev_sector(bdev, blk, &sect);
80                 if (!data) {
81                         if (warn_no_part)
82                                 printk("Dev %s: unable to read partition block %d\n",
83                                        bdevname(dev),blk);
84                         goto rdb_done;
85                 }
86                 pb  = (struct PartitionBlock *)data;
87                 blk = be32_to_cpu(pb->pb_Next);
88                 if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
89                         continue;
90                 if (checksum_block((u32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
91                         continue;
92
93                 /* Tell Kernel about it */
94
95                 nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
96                             be32_to_cpu(pb->pb_Environment[9])) *
97                            be32_to_cpu(pb->pb_Environment[3]) *
98                            be32_to_cpu(pb->pb_Environment[5]);
99                 if (!nr_sects)
100                         continue;
101                 start_sect = be32_to_cpu(pb->pb_Environment[9]) *
102                              be32_to_cpu(pb->pb_Environment[3]) *
103                              be32_to_cpu(pb->pb_Environment[5]);
104                 add_gd_partition(hd,first_part_minor,start_sect,nr_sects);
105                 first_part_minor++;
106                 res = 1;
107         }
108         printk("\n");
109
110 rdb_done:
111         return res;
112 }