ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / partitions / nec98.c
1 /*
2  *  NEC PC-9800 series partition supports
3  *
4  *  Copyright (C) 1999  Kyoto University Microcomputer Club
5  */
6
7 #include <linux/config.h>
8 #include <linux/fs.h>
9 #include <linux/genhd.h>
10 #include <linux/kernel.h>
11 #include <linux/hdreg.h>
12
13 #include "check.h"
14 #include "nec98.h"
15
16 struct nec98_partition {
17         __u8    mid;            /* 0x80 - active */
18         __u8    sid;            /* 0x80 - bootable */
19         __u16   pad1;           /* dummy for padding */
20         __u8    ipl_sector;     /* IPL sector   */
21         __u8    ipl_head;       /* IPL head     */
22         __u16   ipl_cyl;        /* IPL cylinder */
23         __u8    sector;         /* starting sector      */
24         __u8    head;           /* starting head        */
25         __u16   cyl;            /* starting cylinder    */
26         __u8    end_sector;     /* end sector   */
27         __u8    end_head;       /* end head     */
28         __u16   end_cyl;        /* end cylinder */
29         unsigned char name[16];
30 } __attribute__((__packed__));
31
32 #define NEC98_BSD_PARTITION_MID 0x14
33 #define NEC98_BSD_PARTITION_SID 0x44
34 #define MID_SID_16(mid, sid)    (((mid) & 0xFF) | (((sid) & 0xFF) << 8))
35 #define NEC98_BSD_PARTITION_MID_SID     \
36         MID_SID_16(NEC98_BSD_PARTITION_MID, NEC98_BSD_PARTITION_SID)
37 #define NEC98_VALID_PTABLE_ENTRY(P) \
38         (!(P)->pad1 && (P)->cyl <= (P)->end_cyl)
39
40 extern int pc98_bios_param(struct block_device *bdev, int *ip);
41
42 static inline int
43 is_valid_nec98_partition_table(const struct nec98_partition *ptable,
44                                 __u8 nsectors, __u8 nheads)
45 {
46         int i;
47         int valid = 0;
48
49         for (i = 0; i < 16; i++) {
50                 if (!*(__u16 *)&ptable[i])
51                         continue;       /* empty slot */
52                 if (ptable[i].pad1      /* `pad1' contains junk */
53                     || ptable[i].ipl_sector     >= nsectors
54                     || ptable[i].sector         >= nsectors
55                     || ptable[i].end_sector     >= nsectors
56                     || ptable[i].ipl_head       >= nheads
57                     || ptable[i].head           >= nheads
58                     || ptable[i].end_head       >= nheads
59                     || ptable[i].cyl > ptable[i].end_cyl)
60                         return 0;
61                 valid = 1;      /* We have a valid partition.  */
62         }
63         /* If no valid PC-9800-style partitions found,
64            the disk may have other type of partition table.  */
65         return valid;
66 }
67
68 int nec98_partition(struct parsed_partitions *state, struct block_device *bdev)
69 {
70         unsigned int nr;
71         struct hd_geometry geo;
72         Sector sect;
73         const struct nec98_partition *part;
74         unsigned char *data;
75         int sector_size = bdev_hardsect_size(bdev);
76
77         if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)&geo) != 0) {
78                 printk(" unsupported disk (%s)\n", bdev->bd_disk->disk_name);
79                 return 0;
80         }
81
82 #ifdef NEC98_PARTITION_DEBUG
83         printk("ioctl_by_bdev head=%d sect=%d\n", geo.heads, geo.sectors);
84 #endif
85         data = read_dev_sector(bdev, 0, &sect);
86         if (!data) {
87                 if (warn_no_part)
88                         printk(" unable to read partition table\n");
89                 return -1;
90         }
91
92         /* magic(?) check */
93         if (*(__u16 *)(data + sector_size - 2) != NEC98_PTABLE_MAGIC) {
94                 put_dev_sector(sect);
95                 return 0;
96         }
97
98         put_dev_sector(sect);
99         data = read_dev_sector(bdev, 1, &sect);
100         if (!data) {
101                 if (warn_no_part)
102                         printk(" unable to read partition table\n");
103                 return -1;
104         }
105
106         if (!is_valid_nec98_partition_table((struct nec98_partition *)data,
107                                              geo.sectors, geo.heads)) {
108 #ifdef NEC98_PARTITION_DEBUG
109                 if (warn_no_part)
110                         printk(" partition table consistency check failed"
111                                 " (not PC-9800 disk?)\n");
112 #endif
113                 put_dev_sector(sect);
114                 return 0;
115         }
116
117         part = (const struct nec98_partition *)data;
118         for (nr = 0; nr < 16; nr++, part++) {
119                 unsigned int start_sect, end_sect;
120
121                 if (part->mid == 0 || part->sid == 0)
122                         continue;
123
124                 if (nr)
125                         printk("     ");
126
127                 {       /* Print partition name. Fdisk98 might put NUL
128                            characters in partition name... */
129
130                         int j;
131                         unsigned char *p;
132                         unsigned char buf[sizeof (part->name) * 2 + 1];
133
134                         for (p = buf, j = 0; j < sizeof (part->name); j++, p++)
135                                 if ((*p = part->name[j]) < ' ') {
136                                         *p++ = '^';
137                                         *p = part->name[j] + '@';
138                                 }
139
140                         *p = 0;
141                         printk(" <%s>", buf);
142                 }
143                 start_sect = (part->cyl * geo.heads + part->head) * geo.sectors
144                         + part->sector;
145                 end_sect = (part->end_cyl + 1) * geo.heads * geo.sectors;
146                 if (end_sect <= start_sect) {
147                         printk(" (invalid partition info)\n");
148                         continue;
149                 }
150
151                 put_partition(state, nr + 1, start_sect, end_sect - start_sect);
152 #ifdef CONFIG_BSD_DISKLABEL
153                 if ((*(__u16 *)&part->mid & 0x7F7F)
154                     == NEC98_BSD_PARTITION_MID_SID) {
155                         printk("!");
156                         /* NEC98_BSD_PARTITION_MID_SID is not valid SYSIND for
157                            IBM PC's MS-DOS partition table, so we simply pass
158                            it to bsd_disklabel_partition;
159                            it will just print `<bsd: ... >'. */
160                         parse_bsd(state, bdev, start_sect,
161                                         end_sect - start_sect, nr + 1,
162                                         "bsd98", BSD_MAXPARTITIONS);
163                 }
164 #endif
165                 {       /* Pretty size printing. */
166                         /* XXX sector size? */
167                         unsigned int psize = (end_sect - start_sect) / 2;
168                         int unit_char = 'K';
169
170                         if (psize > 99999) {
171                                 psize >>= 10;
172                                 unit_char = 'M';
173                         }
174                         printk(" %5d%cB (%5d-%5d)\n", 
175                                psize, unit_char, part->cyl, part->end_cyl);
176                 }
177         }
178
179         put_dev_sector(sect);
180
181         return nr ? 1 : 0;
182 }
183 \f
184 /*
185  * Local variables:
186  * c-basic-offset: 8
187  * End:
188  */