2 * fs/partitions/msdos.c
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
7 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
8 * in the early extended-partition checks and added DM partitions
10 * Support for DiskManager v6.0x added by Mark Lord,
11 * with information provided by OnTrack. This now works for linux fdisk
12 * and LILO, as well as loadlin and bootln. Note that disks other than
13 * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
15 * More flexible handling of extended partitions - aeb, 950831
17 * Check partition table on IDE disks for common CHS translations
19 * Re-organised Feb 1998 Russell King
22 #include <linux/config.h>
24 #include <linux/genhd.h>
25 #include <linux/kernel.h>
26 #include <linux/major.h>
27 #include <linux/string.h>
28 #include <linux/blk.h>
29 #include <linux/ide.h> /* IDE xlate */
31 #include <asm/system.h>
36 static int current_minor
;
39 * Many architectures don't like unaligned accesses, which is
40 * frequently the case with the nr_sects and start_sect partition
43 #include <asm/unaligned.h>
45 #define SYS_IND(p) (get_unaligned(&p->sys_ind))
46 #define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
47 get_unaligned(&p->nr_sects); \
51 #define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
52 get_unaligned(&p->start_sect); \
56 static inline int is_extended_partition(struct partition
*p
)
58 return (SYS_IND(p
) == DOS_EXTENDED_PARTITION
||
59 SYS_IND(p
) == WIN98_EXTENDED_PARTITION
||
60 SYS_IND(p
) == LINUX_EXTENDED_PARTITION
);
64 * Create devices for each logical partition in an extended partition.
65 * The logical partitions form a linked list, with each entry being
66 * a partition table with two entries. The first entry
67 * is the real data partition (with a start relative to the partition
68 * table start). The second is a pointer to the next logical partition
69 * (with a start relative to the entire extended partition).
70 * We do not create a Linux partition for the partition tables, but
71 * only for the actual data partitions.
74 static void extended_partition(struct gendisk
*hd
, kdev_t dev
)
76 struct buffer_head
*bh
;
78 unsigned long first_sector
, first_size
, this_sector
, this_size
;
79 int mask
= (1 << hd
->minor_shift
) - 1;
80 int sector_size
= get_hardsect_size(dev
) / 512;
81 int loopct
= 0; /* number of links followed
82 without finding a data partition */
85 first_sector
= hd
->part
[MINOR(dev
)].start_sect
;
86 first_size
= hd
->part
[MINOR(dev
)].nr_sects
;
87 this_sector
= first_sector
;
92 if ((current_minor
& mask
) == 0)
94 if (!(bh
= bread(dev
,0,get_ptable_blocksize(dev
))))
97 if ((*(__u16
*) (bh
->b_data
+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC
))
100 p
= (struct partition
*) (0x1BE + bh
->b_data
);
102 this_size
= hd
->part
[MINOR(dev
)].nr_sects
;
105 * Usually, the first entry is the real data partition,
106 * the 2nd entry is the next extended partition, or empty,
107 * and the 3rd and 4th entries are unused.
108 * However, DRDOS sometimes has the extended partition as
109 * the first entry (when the data partition is empty),
110 * and OS/2 seems to use all four entries.
114 * First process the data partition(s)
116 for (i
=0; i
<4; i
++, p
++) {
117 if (!NR_SECTS(p
) || is_extended_partition(p
))
120 /* Check the 3rd and 4th entries -
121 these sometimes contain random garbage */
123 && START_SECT(p
) + NR_SECTS(p
) > this_size
124 && (this_sector
+ START_SECT(p
) < first_sector
||
125 this_sector
+ START_SECT(p
) + NR_SECTS(p
) >
126 first_sector
+ first_size
))
129 add_gd_partition(hd
, current_minor
,
130 this_sector
+START_SECT(p
)*sector_size
,
131 NR_SECTS(p
)*sector_size
);
134 if ((current_minor
& mask
) == 0)
138 * Next, process the (first) extended partition, if present.
139 * (So far, there seems to be no reason to make
140 * extended_partition() recursive and allow a tree
141 * of extended partitions.)
142 * It should be a link to the next logical partition.
143 * Create a minor for this just long enough to get the next
144 * partition table. The minor will be reused for the next
148 for (i
=0; i
<4; i
++, p
++)
149 if(NR_SECTS(p
) && is_extended_partition(p
))
152 goto done
; /* nothing left to do */
154 hd
->part
[current_minor
].nr_sects
= NR_SECTS(p
) * sector_size
; /* JSt */
155 hd
->part
[current_minor
].start_sect
= first_sector
+ START_SECT(p
) * sector_size
;
156 this_sector
= first_sector
+ START_SECT(p
) * sector_size
;
157 dev
= MKDEV(hd
->major
, current_minor
);
159 /* Use bforget(), as we have changed the disk geometry */
166 #ifdef CONFIG_SOLARIS_X86_PARTITION
168 solaris_x86_partition(struct gendisk
*hd
, kdev_t dev
, long offset
) {
170 struct buffer_head
*bh
;
171 struct solaris_x86_vtoc
*v
;
172 struct solaris_x86_slice
*s
;
175 if(!(bh
= bread(dev
, 0, get_ptable_blocksize(dev
))))
177 v
= (struct solaris_x86_vtoc
*)(bh
->b_data
+ 512);
178 if(v
->v_sanity
!= SOLARIS_X86_VTOC_SANE
) {
182 printk(" <solaris:");
183 if(v
->v_version
!= 1) {
184 printk(" cannot handle version %ld vtoc>", v
->v_version
);
188 for(i
=0; i
<SOLARIS_X86_NUMSLICE
; i
++) {
194 /* solaris partitions are relative to current MS-DOS
195 * one but add_gd_partition starts relative to sector
196 * zero of the disk. Therefore, must add the offset
197 * of the current partition */
198 add_gd_partition(hd
, current_minor
, s
->s_start
+offset
, s
->s_size
);
206 #ifdef CONFIG_BSD_DISKLABEL
207 static void check_and_add_bsd_partition(struct gendisk
*hd
,
208 struct bsd_partition
*bsd_p
, kdev_t dev
)
210 struct hd_struct
*lin_p
;
211 /* check relative position of partitions. */
212 for (lin_p
= hd
->part
+ 1 + MINOR(dev
);
213 lin_p
- hd
->part
- MINOR(dev
) < current_minor
; lin_p
++) {
214 /* no relationship -> try again */
215 if (lin_p
->start_sect
+ lin_p
->nr_sects
<= bsd_p
->p_offset
216 || lin_p
->start_sect
>= bsd_p
->p_offset
+ bsd_p
->p_size
)
218 /* equal -> no need to add */
219 if (lin_p
->start_sect
== bsd_p
->p_offset
&&
220 lin_p
->nr_sects
== bsd_p
->p_size
)
222 /* bsd living within dos partition */
223 if (lin_p
->start_sect
<= bsd_p
->p_offset
&& lin_p
->start_sect
224 + lin_p
->nr_sects
>= bsd_p
->p_offset
+ bsd_p
->p_size
) {
225 #ifdef DEBUG_BSD_DISKLABEL
226 printk("w: %d %ld+%ld,%d+%d",
228 lin_p
->start_sect
, lin_p
->nr_sects
,
229 bsd_p
->p_offset
, bsd_p
->p_size
);
233 /* ouch: bsd and linux overlap. Don't even try for that partition */
234 #ifdef DEBUG_BSD_DISKLABEL
235 printk("???: %d %ld+%ld,%d+%d",
236 lin_p
- hd
->part
, lin_p
->start_sect
, lin_p
->nr_sects
,
237 bsd_p
->p_offset
, bsd_p
->p_size
);
241 } /* if the bsd partition is not currently known to linux, we end
244 add_gd_partition(hd
, current_minor
, bsd_p
->p_offset
, bsd_p
->p_size
);
248 * Create devices for BSD partitions listed in a disklabel, under a
249 * dos-like partition. See extended_partition() for more information.
251 static void bsd_disklabel_partition(struct gendisk
*hd
, kdev_t dev
,
254 struct buffer_head
*bh
;
255 struct bsd_disklabel
*l
;
256 struct bsd_partition
*p
;
257 int mask
= (1 << hd
->minor_shift
) - 1;
259 if (!(bh
= bread(dev
,0,get_ptable_blocksize(dev
))))
261 l
= (struct bsd_disklabel
*) (bh
->b_data
+512);
262 if (l
->d_magic
!= BSD_DISKMAGIC
) {
267 if (l
->d_npartitions
< max_partitions
)
268 max_partitions
= l
->d_npartitions
;
269 for (p
= l
->d_partitions
; p
- l
->d_partitions
< max_partitions
; p
++) {
270 if ((current_minor
& mask
) >= (4 + hd
->max_p
))
273 if (p
->p_fstype
!= BSD_FS_UNUSED
)
274 check_and_add_bsd_partition(hd
, p
, dev
);
277 /* Use bforget(), as we have changed the disk setup */
283 #ifdef CONFIG_UNIXWARE_DISKLABEL
285 * Create devices for Unixware partitions listed in a disklabel, under a
286 * dos-like partition. See extended_partition() for more information.
288 static void unixware_partition(struct gendisk
*hd
, kdev_t dev
)
290 struct buffer_head
*bh
;
291 struct unixware_disklabel
*l
;
292 struct unixware_slice
*p
;
293 int mask
= (1 << hd
->minor_shift
) - 1;
295 if (!(bh
= bread(dev
, 14, get_ptable_blocksize(dev
))))
297 l
= (struct unixware_disklabel
*) (bh
->b_data
+512);
298 if (le32_to_cpu(l
->d_magic
) != UNIXWARE_DISKMAGIC
||
299 le32_to_cpu(l
->vtoc
.v_magic
) != UNIXWARE_DISKMAGIC2
) {
303 printk(" <unixware:");
304 p
= &l
->vtoc
.v_slice
[1];
305 /* I omit the 0th slice as it is the same as whole disk. */
306 while (p
- &l
->vtoc
.v_slice
[0] < UNIXWARE_NUMSLICE
) {
307 if ((current_minor
& mask
) == 0)
310 if (p
->s_label
!= UNIXWARE_FS_UNUSED
) {
311 add_gd_partition(hd
, current_minor
, START_SECT(p
), NR_SECTS(p
));
316 /* Use bforget, as we have changed the disk setup */
322 int msdos_partition(struct gendisk
*hd
, kdev_t dev
, unsigned long first_sector
, int first_part_minor
)
324 int i
, minor
= current_minor
= first_part_minor
;
325 struct buffer_head
*bh
;
328 int mask
= (1 << hd
->minor_shift
) - 1;
329 int sector_size
= get_hardsect_size(dev
) / 512;
330 #ifdef CONFIG_BSD_DISKLABEL
331 /* no bsd disklabel as a default */
333 int bsd_maxpart
= BSD_MAXPARTITIONS
;
335 #ifdef CONFIG_BLK_DEV_IDE
336 int tested_for_xlate
= 0;
340 if (!(bh
= bread(dev
,0,get_ptable_blocksize(dev
)))) {
341 printk(" unable to read partition table\n");
345 #ifdef CONFIG_BLK_DEV_IDE
348 /* Use bforget(), because we have potentially changed the disk geometry */
349 if (*(unsigned short *) (0x1fe + data
) != cpu_to_le16(MSDOS_LABEL_MAGIC
)) {
353 p
= (struct partition
*) (0x1be + data
);
355 #ifdef CONFIG_BLK_DEV_IDE
356 if (!tested_for_xlate
++) { /* Do this only once per disk */
358 * Look for various forms of IDE disk geometry translation
360 unsigned int sig
= le16_to_cpu(*(unsigned short *)(data
+ 2));
363 * The i386 partition handling programs very often
364 * make partitions end on cylinder boundaries.
365 * There is no need to do so, and Linux fdisk doesnt always
366 * do this, and Windows NT on Alpha doesnt do this either,
367 * but still, this helps to guess #heads.
369 for (i
= 0; i
< 4; i
++) {
370 struct partition
*q
= &p
[i
];
372 if ((q
->sector
& 63) == 1 &&
373 (q
->end_sector
& 63) == 63)
374 heads
= q
->end_head
+ 1;
378 if (SYS_IND(p
) == EZD_PARTITION
) {
380 * Accesses to sector 0 must go to sector 1 instead.
382 if (ide_xlate_1024(dev
, -1, heads
, " [EZD]")) {
386 } else if (SYS_IND(p
) == DM6_PARTITION
) {
389 * Everything on the disk is offset by 63 sectors,
390 * including a "new" MBR with its own partition table.
392 if (ide_xlate_1024(dev
, 1, heads
, " [DM6:DDO]")) {
394 goto read_mbr
; /* start over with new MBR */
396 } else if (sig
<= 0x1ae &&
397 data
[sig
] == 0xAA && data
[sig
+1] == 0x55 &&
399 /* DM6 signature in MBR, courtesy of OnTrack */
400 (void) ide_xlate_1024 (dev
, 0, heads
, " [DM6:MBR]");
401 } else if (SYS_IND(p
) == DM6_AUX1PARTITION
||
402 SYS_IND(p
) == DM6_AUX3PARTITION
) {
404 * DM6 on other than the first (boot) drive
406 (void) ide_xlate_1024(dev
, 0, heads
, " [DM6:AUX]");
408 (void) ide_xlate_1024(dev
, 2, heads
, " [PTBL]");
411 #endif /* CONFIG_BLK_DEV_IDE */
413 current_minor
+= 4; /* first "extra" minor (for extended partitions) */
414 for (i
=1 ; i
<=4 ; minor
++,i
++,p
++) {
417 add_gd_partition(hd
, minor
, first_sector
+START_SECT(p
)*sector_size
, NR_SECTS(p
)*sector_size
);
418 if (is_extended_partition(p
)) {
421 * If we are rereading the partition table, we need
422 * to set the size of the partition so that we will
423 * be able to bread the block containing the extended
426 hd
->sizes
[minor
] = hd
->part
[minor
].nr_sects
427 >> (BLOCK_SIZE_BITS
- 9);
428 extended_partition(hd
, MKDEV(hd
->major
, minor
));
430 /* prevent someone doing mkfs or mkswap on an
431 extended partition, but leave room for LILO */
432 if (hd
->part
[minor
].nr_sects
> 2)
433 hd
->part
[minor
].nr_sects
= 2;
435 #ifdef CONFIG_BSD_DISKLABEL
436 /* tag first disklabel for late recognition */
437 if (SYS_IND(p
) == BSD_PARTITION
|| SYS_IND(p
) == NETBSD_PARTITION
) {
440 bsd_kdev
= MKDEV(hd
->major
, minor
);
441 } else if (SYS_IND(p
) == OPENBSD_PARTITION
) {
444 bsd_kdev
= MKDEV(hd
->major
, minor
);
445 bsd_maxpart
= OPENBSD_MAXPARTITIONS
;
449 #ifdef CONFIG_UNIXWARE_DISKLABEL
450 if (SYS_IND(p
) == UNIXWARE_PARTITION
)
451 unixware_partition(hd
, MKDEV(hd
->major
, minor
));
453 #ifdef CONFIG_SOLARIS_X86_PARTITION
455 /* james@bpgc.com: Solaris has a nasty indicator: 0x82
456 * which also means linux swap. For that reason, all
457 * of the prints are done inside the
458 * solaris_x86_partition routine */
460 if(SYS_IND(p
) == SOLARIS_X86_PARTITION
) {
461 solaris_x86_partition(hd
, MKDEV(hd
->major
, minor
),
462 first_sector
+START_SECT(p
));
466 #ifdef CONFIG_BSD_DISKLABEL
469 bsd_disklabel_partition(hd
, bsd_kdev
, bsd_maxpart
);
474 * Check for old-style Disk Manager partition table
476 if (*(unsigned short *) (data
+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC
)) {
477 p
= (struct partition
*) (0x1be + data
);
478 for (i
= 4 ; i
< 16 ; i
++, current_minor
++) {
480 if ((current_minor
& mask
) == 0)
482 if (!(START_SECT(p
) && NR_SECTS(p
)))
484 add_gd_partition(hd
, current_minor
, START_SECT(p
), NR_SECTS(p
));