1/*
2 *  fs/partitions/msdos.c
3 *
4 *  Code extracted from drivers/block/genhd.c
5 *  Copyright (C) 1991-1998  Linus Torvalds
6 *
7 *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
8 *  in the early extended-partition checks and added DM partitions
9 *
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).
14 *
15 *  More flexible handling of extended partitions - aeb, 950831
16 *
17 *  Check partition table on IDE disks for common CHS translations
18 *
19 *  Re-organised Feb 1998 Russell King
20 */
21
22#include <linux/config.h>
23#include <linux/fs.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
30#ifdef CONFIG_BLK_DEV_IDE
31#include <linux/ide.h>	/* IDE xlate */
32#elif defined(CONFIG_BLK_DEV_IDE_MODULE)
33#include <linux/module.h>
34
35int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
36EXPORT_SYMBOL(ide_xlate_1024_hook);
37#define ide_xlate_1024 ide_xlate_1024_hook
38#endif
39
40#include <asm/system.h>
41
42#include "check.h"
43#include "msdos.h"
44
45#if CONFIG_BLK_DEV_MD
46extern void md_autodetect_dev(kdev_t dev);
47#endif
48
49/*
50 * Many architectures don't like unaligned accesses, which is
51 * frequently the case with the nr_sects and start_sect partition
52 * table entries.
53 */
54#include <asm/unaligned.h>
55
56#define SYS_IND(p)	(get_unaligned(&p->sys_ind))
57#define NR_SECTS(p)	({ __typeof__(p->nr_sects) __a =	\
58				get_unaligned(&p->nr_sects);	\
59				le32_to_cpu(__a); \
60			})
61
62#define START_SECT(p)	({ __typeof__(p->start_sect) __a =	\
63				get_unaligned(&p->start_sect);	\
64				le32_to_cpu(__a); \
65			})
66
67static inline int is_extended_partition(struct partition *p)
68{
69	return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
70		SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
71		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
72}
73
74/*
75 * msdos_partition_name() formats the short partition name into the supplied
76 * buffer, and returns a pointer to that buffer.
77 * Used by several partition types which makes conditional inclusion messy,
78 * use __attribute__ ((unused)) instead.
79 */
80static char __attribute__ ((unused))
81	*msdos_partition_name (struct gendisk *hd, int minor, char *buf)
82{
83#ifdef CONFIG_DEVFS_FS
84	sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1)));
85	return buf;
86#else
87	return disk_name(hd, minor, buf);
88#endif
89}
90
91#define MSDOS_LABEL_MAGIC1	0x55
92#define MSDOS_LABEL_MAGIC2	0xAA
93
94static inline int
95msdos_magic_present(unsigned char *p)
96{
97	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
98}
99
100/*
101 * Create devices for each logical partition in an extended partition.
102 * The logical partitions form a linked list, with each entry being
103 * a partition table with two entries.  The first entry
104 * is the real data partition (with a start relative to the partition
105 * table start).  The second is a pointer to the next logical partition
106 * (with a start relative to the entire extended partition).
107 * We do not create a Linux partition for the partition tables, but
108 * only for the actual data partitions.
109 */
110
111static void extended_partition(struct gendisk *hd, struct block_device *bdev,
112			int minor, unsigned long first_size, int *current_minor)
113{
114	struct partition *p;
115	Sector sect;
116	unsigned char *data;
117	unsigned long first_sector, this_sector, this_size;
118	int mask = (1 << hd->minor_shift) - 1;
119	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
120	int loopct = 0;		/* number of links followed
121				   without finding a data partition */
122	int i;
123
124	this_sector = first_sector = hd->part[minor].start_sect;
125	this_size = first_size;
126
127	while (1) {
128		if (++loopct > 100)
129			return;
130		if ((*current_minor & mask) == 0)
131			return;
132		data = read_dev_sector(bdev, this_sector, &sect);
133		if (!data)
134			return;
135
136		if (!msdos_magic_present(data + 510))
137			goto done;
138
139		p = (struct partition *) (data + 0x1be);
140
141		/*
142		 * Usually, the first entry is the real data partition,
143		 * the 2nd entry is the next extended partition, or empty,
144		 * and the 3rd and 4th entries are unused.
145		 * However, DRDOS sometimes has the extended partition as
146		 * the first entry (when the data partition is empty),
147		 * and OS/2 seems to use all four entries.
148		 */
149
150		/*
151		 * First process the data partition(s)
152		 */
153		for (i=0; i<4; i++, p++) {
154			unsigned long offs, size, next;
155			if (!NR_SECTS(p) || is_extended_partition(p))
156				continue;
157
158			/* Check the 3rd and 4th entries -
159			   these sometimes contain random garbage */
160			offs = START_SECT(p)*sector_size;
161			size = NR_SECTS(p)*sector_size;
162			next = this_sector + offs;
163			if (i >= 2) {
164				if (offs + size > this_size)
165					continue;
166				if (next < first_sector)
167					continue;
168				if (next + size > first_sector + first_size)
169					continue;
170			}
171
172			add_gd_partition(hd, *current_minor, next, size);
173#if CONFIG_BLK_DEV_MD
174			if (SYS_IND(p) == LINUX_RAID_PARTITION) {
175			    md_autodetect_dev(MKDEV(hd->major,*current_minor));
176			}
177#endif
178
179			(*current_minor)++;
180			loopct = 0;
181			if ((*current_minor & mask) == 0)
182				goto done;
183		}
184		/*
185		 * Next, process the (first) extended partition, if present.
186		 * (So far, there seems to be no reason to make
187		 *  extended_partition()  recursive and allow a tree
188		 *  of extended partitions.)
189		 * It should be a link to the next logical partition.
190		 * Create a minor for this just long enough to get the next
191		 * partition table.  The minor will be reused for the next
192		 * data partition.
193		 */
194		p -= 4;
195		for (i=0; i<4; i++, p++)
196			if (NR_SECTS(p) && is_extended_partition(p))
197				break;
198		if (i == 4)
199			goto done;	 /* nothing left to do */
200
201		this_sector = first_sector + START_SECT(p) * sector_size;
202		this_size = NR_SECTS(p) * sector_size;
203		minor = *current_minor;
204		put_dev_sector(sect);
205	}
206done:
207	put_dev_sector(sect);
208}
209
210/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
211   indicates linux swap.  Be careful before believing this is Solaris. */
212
213static void
214solaris_x86_partition(struct gendisk *hd, struct block_device *bdev,
215		int minor, int *current_minor)
216{
217
218#ifdef CONFIG_SOLARIS_X86_PARTITION
219	long offset = hd->part[minor].start_sect;
220	Sector sect;
221	struct solaris_x86_vtoc *v;
222	struct solaris_x86_slice *s;
223	int mask = (1 << hd->minor_shift) - 1;
224	int i;
225	char buf[40];
226
227	v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, &sect);
228	if (!v)
229		return;
230	if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
231		put_dev_sector(sect);
232		return;
233	}
234	printk(" %s: <solaris:", msdos_partition_name(hd, minor, buf));
235	if (le32_to_cpu(v->v_version) != 1) {
236		printk("  cannot handle version %d vtoc>\n",
237			le32_to_cpu(v->v_version));
238		put_dev_sector(sect);
239		return;
240	}
241	for (i=0; i<SOLARIS_X86_NUMSLICE; i++) {
242		if ((*current_minor & mask) == 0)
243			break;
244		s = &v->v_slice[i];
245
246		if (s->s_size == 0)
247			continue;
248		printk(" [s%d]", i);
249		/* solaris partitions are relative to current MS-DOS
250		 * one but add_gd_partition starts relative to sector
251		 * zero of the disk.  Therefore, must add the offset
252		 * of the current partition */
253		add_gd_partition(hd, *current_minor,
254				 le32_to_cpu(s->s_start)+offset,
255				 le32_to_cpu(s->s_size));
256		(*current_minor)++;
257	}
258	put_dev_sector(sect);
259	printk(" >\n");
260#endif
261}
262
263#ifdef CONFIG_BSD_DISKLABEL
264static void
265check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p,
266	int baseminor, int *current_minor)
267{
268	int i, bsd_start, bsd_size;
269
270	bsd_start = le32_to_cpu(bsd_p->p_offset);
271	bsd_size = le32_to_cpu(bsd_p->p_size);
272
273	/* check relative position of already allocated partitions */
274	for (i = baseminor+1; i < *current_minor; i++) {
275		int start = hd->part[i].start_sect;
276		int size = hd->part[i].nr_sects;
277
278		if (start+size <= bsd_start || start >= bsd_start+bsd_size)
279			continue;	/* no overlap */
280
281		if (start == bsd_start && size == bsd_size)
282			return;		/* equal -> no need to add */
283
284		if (start <= bsd_start && start+size >= bsd_start+bsd_size) {
285			/* bsd living within dos partition */
286#ifdef DEBUG_BSD_DISKLABEL
287			printk("w: %d %ld+%ld,%d+%d",
288			       i, start, size, bsd_start, bsd_size);
289#endif
290			break;		/* ok */
291		}
292
293		/* ouch: bsd and linux overlap */
294#ifdef DEBUG_BSD_DISKLABEL
295		printk("???: %d %ld+%ld,%d+%d",
296		       i, start, size, bsd_start, bsd_size);
297#endif
298		printk("???");
299		return;
300	}
301
302	add_gd_partition(hd, *current_minor, bsd_start, bsd_size);
303	(*current_minor)++;
304}
305
306/*
307 * Create devices for BSD partitions listed in a disklabel, under a
308 * dos-like partition. See extended_partition() for more information.
309 */
310static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev,
311	int minor, int *current_minor, char *name, int max_partitions)
312{
313	long offset = hd->part[minor].start_sect;
314	Sector sect;
315	struct bsd_disklabel *l;
316	struct bsd_partition *p;
317	int mask = (1 << hd->minor_shift) - 1;
318	int baseminor = (minor & ~mask);
319	char buf[40];
320
321	l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, &sect);
322	if (!l)
323		return;
324	if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
325		put_dev_sector(sect);
326		return;
327	}
328	printk(" %s: <%s:", msdos_partition_name(hd, minor, buf), name);
329
330	if (le16_to_cpu(l->d_npartitions) < max_partitions)
331		max_partitions = le16_to_cpu(l->d_npartitions);
332	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
333		if ((*current_minor & mask) == 0)
334			break;
335		if (p->p_fstype == BSD_FS_UNUSED)
336			continue;
337		check_and_add_bsd_partition(hd, p, baseminor, current_minor);
338	}
339	put_dev_sector(sect);
340	printk(" >\n");
341}
342#endif
343
344static void bsd_partition(struct gendisk *hd, struct block_device *bdev,
345	int minor, int *current_minor)
346{
347#ifdef CONFIG_BSD_DISKLABEL
348	do_bsd_partition(hd, bdev, minor, current_minor, "bsd",
349		BSD_MAXPARTITIONS);
350#endif
351}
352
353static void netbsd_partition(struct gendisk *hd, struct block_device *bdev,
354		int minor, int *current_minor)
355{
356#ifdef CONFIG_BSD_DISKLABEL
357	do_bsd_partition(hd, bdev, minor, current_minor, "netbsd",
358			BSD_MAXPARTITIONS);
359#endif
360}
361
362static void openbsd_partition(struct gendisk *hd, struct block_device *bdev,
363		int minor, int *current_minor)
364{
365#ifdef CONFIG_BSD_DISKLABEL
366	do_bsd_partition(hd, bdev, minor, current_minor,
367			"openbsd", OPENBSD_MAXPARTITIONS);
368#endif
369}
370
371/*
372 * Create devices for Unixware partitions listed in a disklabel, under a
373 * dos-like partition. See extended_partition() for more information.
374 */
375static void unixware_partition(struct gendisk *hd, struct block_device *bdev,
376		int minor, int *current_minor)
377{
378#ifdef CONFIG_UNIXWARE_DISKLABEL
379	long offset = hd->part[minor].start_sect;
380	Sector sect;
381	struct unixware_disklabel *l;
382	struct unixware_slice *p;
383	int mask = (1 << hd->minor_shift) - 1;
384	char buf[40];
385
386	l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, &sect);
387	if (!l)
388		return;
389	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
390	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
391		put_dev_sector(sect);
392		return;
393	}
394	printk(" %s: <unixware:", msdos_partition_name(hd, minor, buf));
395	p = &l->vtoc.v_slice[1];
396	/* I omit the 0th slice as it is the same as whole disk. */
397	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
398		if ((*current_minor & mask) == 0)
399			break;
400
401		if (p->s_label != UNIXWARE_FS_UNUSED) {
402			add_gd_partition(hd, *current_minor, START_SECT(p),
403					 NR_SECTS(p));
404			(*current_minor)++;
405		}
406		p++;
407	}
408	put_dev_sector(sect);
409	printk(" >\n");
410#endif
411}
412
413/*
414 * Minix 2.0.0/2.0.2 subpartition support.
415 * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
416 * Rajeev V. Pillai    <rajeevvp@yahoo.com>
417 */
418static void minix_partition(struct gendisk *hd, struct block_device *bdev,
419		int minor, int *current_minor)
420{
421#ifdef CONFIG_MINIX_SUBPARTITION
422	long offset = hd->part[minor].start_sect;
423	Sector sect;
424	unsigned char *data;
425	struct partition *p;
426	int mask = (1 << hd->minor_shift) - 1;
427	int i;
428	char buf[40];
429
430	data = read_dev_sector(bdev, offset, &sect);
431	if (!data)
432		return;
433
434	p = (struct partition *)(data + 0x1be);
435
436	/* The first sector of a Minix partition can have either
437	 * a secondary MBR describing its subpartitions, or
438	 * the normal boot sector. */
439	if (msdos_magic_present (data + 510) &&
440	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
441
442		printk(" %s: <minix:", msdos_partition_name(hd, minor, buf));
443		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
444			if ((*current_minor & mask) == 0)
445				break;
446			/* add each partition in use */
447			if (SYS_IND(p) == MINIX_PARTITION) {
448				add_gd_partition(hd, *current_minor,
449					      START_SECT(p), NR_SECTS(p));
450				(*current_minor)++;
451			}
452		}
453		printk(" >\n");
454	}
455	put_dev_sector(sect);
456#endif /* CONFIG_MINIX_SUBPARTITION */
457}
458
459static struct {
460	unsigned char id;
461	void (*parse)(struct gendisk *, struct block_device *, int, int *);
462} subtypes[] = {
463	{BSD_PARTITION, bsd_partition},
464	{NETBSD_PARTITION, netbsd_partition},
465	{OPENBSD_PARTITION, openbsd_partition},
466	{MINIX_PARTITION, minix_partition},
467	{UNIXWARE_PARTITION, unixware_partition},
468	{SOLARIS_X86_PARTITION, solaris_x86_partition},
469	{0, NULL},
470};
471/*
472 * Look for various forms of IDE disk geometry translation
473 */
474static int handle_ide_mess(struct block_device *bdev)
475{
476#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
477	Sector sect;
478	unsigned char *data;
479	kdev_t dev = to_kdev_t(bdev->bd_dev);
480	unsigned int sig;
481	int heads = 0;
482	struct partition *p;
483	int i;
484#ifdef CONFIG_BLK_DEV_IDE_MODULE
485	if (!ide_xlate_1024)
486		return 1;
487#endif
488	/*
489	 * The i386 partition handling programs very often
490	 * make partitions end on cylinder boundaries.
491	 * There is no need to do so, and Linux fdisk doesn't always
492	 * do this, and Windows NT on Alpha doesn't do this either,
493	 * but still, this helps to guess #heads.
494	 */
495	data = read_dev_sector(bdev, 0, &sect);
496	if (!data)
497		return -1;
498	if (!msdos_magic_present(data + 510)) {
499		put_dev_sector(sect);
500		return 0;
501	}
502	sig = le16_to_cpu(*(unsigned short *)(data + 2));
503	p = (struct partition *) (data + 0x1be);
504	for (i = 0; i < 4; i++) {
505		struct partition *q = &p[i];
506		if (NR_SECTS(q)) {
507			if ((q->sector & 63) == 1 &&
508			    (q->end_sector & 63) == 63)
509				heads = q->end_head + 1;
510			break;
511		}
512	}
513	if (SYS_IND(p) == EZD_PARTITION) {
514		/*
515		 * Accesses to sector 0 must go to sector 1 instead.
516		 */
517		if (ide_xlate_1024(dev, -1, heads, " [EZD]"))
518			goto reread;
519	} else if (SYS_IND(p) == DM6_PARTITION) {
520
521		/*
522		 * Everything on the disk is offset by 63 sectors,
523		 * including a "new" MBR with its own partition table.
524		 */
525		if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]"))
526			goto reread;
527	} else if (sig <= 0x1ae &&
528		   data[sig] == 0xAA && data[sig+1] == 0x55 &&
529		   (data[sig+2] & 1)) {
530		/* DM6 signature in MBR, courtesy of OnTrack */
531		(void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
532	} else if (SYS_IND(p) == DM6_AUX1PARTITION ||
533		   SYS_IND(p) == DM6_AUX3PARTITION) {
534		/*
535		 * DM6 on other than the first (boot) drive
536		 */
537		(void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
538	} else {
539		(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
540	}
541	put_dev_sector(sect);
542	return 1;
543
544reread:
545	put_dev_sector(sect);
546	/* Flush the cache */
547	invalidate_bdev(bdev, 1);
548	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
549#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
550	return 1;
551}
552
553int msdos_partition(struct gendisk *hd, struct block_device *bdev,
554		    unsigned long first_sector, int first_part_minor)
555{
556	int i, minor = first_part_minor;
557	Sector sect;
558	struct partition *p;
559	unsigned char *data;
560	int mask = (1 << hd->minor_shift) - 1;
561	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
562	int current_minor = first_part_minor;
563	int err;
564
565	err = handle_ide_mess(bdev);
566	if (err <= 0)
567		return err;
568	data = read_dev_sector(bdev, 0, &sect);
569	if (!data)
570		return -1;
571	if (!msdos_magic_present(data + 510)) {
572		put_dev_sector(sect);
573		return 0;
574	}
575	p = (struct partition *) (data + 0x1be);
576
577	/*
578	 * Look for partitions in two passes:
579	 * First find the primary and DOS-type extended partitions.
580	 * On the second pass look inside *BSD, Unixware and Solaris partitions.
581	 */
582
583	current_minor += 4;
584	for (i=1 ; i<=4 ; minor++,i++,p++) {
585		if (!NR_SECTS(p))
586			continue;
587		add_gd_partition(hd, minor,
588				first_sector+START_SECT(p)*sector_size,
589				NR_SECTS(p)*sector_size);
590#if CONFIG_BLK_DEV_MD
591		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
592			md_autodetect_dev(MKDEV(hd->major,minor));
593		}
594#endif
595		if (is_extended_partition(p)) {
596			unsigned long size = hd->part[minor].nr_sects;
597			printk(" <");
598			/* prevent someone doing mkfs or mkswap on an
599			   extended partition, but leave room for LILO */
600			if (size > 2)
601				hd->part[minor].nr_sects = 2;
602			extended_partition(hd, bdev, minor, size, &current_minor);
603			printk(" >");
604		}
605	}
606
607	/*
608	 *  Check for old-style Disk Manager partition table
609	 */
610	if (msdos_magic_present(data + 0xfc)) {
611		p = (struct partition *) (0x1be + data);
612		for (i = 4 ; i < 16 ; i++, current_minor++) {
613			p--;
614			if ((current_minor & mask) == 0)
615				break;
616			if (!(START_SECT(p) && NR_SECTS(p)))
617				continue;
618			add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
619		}
620	}
621	printk("\n");
622
623	/* second pass - output for each on a separate line */
624	minor -= 4;
625	p = (struct partition *) (0x1be + data);
626	for (i=1 ; i<=4 ; minor++,i++,p++) {
627		unsigned char id = SYS_IND(p);
628		int n;
629
630		if (!NR_SECTS(p))
631			continue;
632
633		for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
634			;
635
636		if (subtypes[n].parse)
637			subtypes[n].parse(hd, bdev, minor, &current_minor);
638	}
639	put_dev_sector(sect);
640	return 1;
641}
642