1 /*
2 * Code extracted from
3 * linux/kernel/hd.c
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 *
8 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
9 * in the early extended-partition checks and added DM partitions
10 *
11 * Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
12 * with information provided by OnTrack. This now works for linux fdisk
13 * and LILO, as well as loadlin and bootln. Note that disks other than
14 * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
15 *
16 * More flexible handling of extended partitions - aeb, 950831
17 */
18
19 #include <linux/config.h>
20 #include <linux/fs.h>
21 #include <linux/genhd.h>
22 #include <linux/kernel.h>
23 #include <linux/major.h>
24 #include <linux/string.h>
25
26 #include <asm/system.h>
27
28 #ifdef __alpha__
29 /*
30 * On the Alpha, we get unaligned access exceptions on
31 * p->nr_sects and p->start_sect, when the partition table
32 * is not on a 4-byte boundary, which is frequently the case.
33 * This code uses unaligned load instructions to prevent
34 * such exceptions.
35 */
36 #include <asm/unaligned.h>
37 #define NR_SECTS(p) ldl_u(&p->nr_sects)
38 #define START_SECT(p) ldl_u(&p->start_sect)
39 #else /* __alpha__ */
40 #define NR_SECTS(p) p->nr_sects
41 #define START_SECT(p) p->start_sect
42 #endif /* __alpha__ */
43
44 struct gendisk *gendisk_head = NULL;
45
46 static int current_minor = 0;
47 extern int *blk_size[];
48 extern void rd_load(void);
49
50 extern int chr_dev_init(void);
51 extern int blk_dev_init(void);
52 extern int scsi_dev_init(void);
53 extern int net_dev_init(void);
54
55 static void print_minor_name (struct gendisk *hd, int minor)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
56 {
57 unsigned int unit = minor >> hd->minor_shift;
58 unsigned int part = minor & ((1 << hd->minor_shift) - 1);
59
60 #ifdef CONFIG_BLK_DEV_IDE
61 /*
62 * IDE devices use multiple major numbers, but the drives
63 * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
64 * This requires some creative handling here to find the
65 * correct name to use, with some help from ide.c
66 */
67 if (!strcmp(hd->major_name,"ide")) {
68 char name[16]; /* more than large enough */
69 strcpy(name, hd->real_devices); /* courtesy ide.c */
70 name[strlen(name)-1] += unit;
71 printk(" %s", name);
72 } else
73 #endif
74 printk(" %s%c", hd->major_name, 'a' + unit);
75 if (part)
76 printk("%d", part);
77 else
78 printk(":");
79 }
80
81 static void add_partition (struct gendisk *hd, int minor, int start, int size)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
82 {
83 hd->part[minor].start_sect = start;
84 hd->part[minor].nr_sects = size;
85 print_minor_name(hd, minor);
86 }
87
88 static inline int is_extended_partition(struct partition *p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
89 {
90 return (p->sys_ind == DOS_EXTENDED_PARTITION ||
91 p->sys_ind == LINUX_EXTENDED_PARTITION);
92 }
93
94 #ifdef CONFIG_MSDOS_PARTITION
95 /*
96 * Create devices for each logical partition in an extended partition.
97 * The logical partitions form a linked list, with each entry being
98 * a partition table with two entries. The first entry
99 * is the real data partition (with a start relative to the partition
100 * table start). The second is a pointer to the next logical partition
101 * (with a start relative to the entire extended partition).
102 * We do not create a Linux partition for the partition tables, but
103 * only for the actual data partitions.
104 */
105
106 static void extended_partition(struct gendisk *hd, kdev_t dev)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
107 {
108 struct buffer_head *bh;
109 struct partition *p;
110 unsigned long first_sector, first_size, this_sector, this_size;
111 int mask = (1 << hd->minor_shift) - 1;
112 int i;
113
114 first_sector = hd->part[MINOR(dev)].start_sect;
115 first_size = hd->part[MINOR(dev)].nr_sects;
116 this_sector = first_sector;
117
118 while (1) {
119 if ((current_minor & mask) == 0)
120 return;
121 if (!(bh = bread(dev,0,1024)))
122 return;
123 /*
124 * This block is from a device that we're about to stomp on.
125 * So make sure nobody thinks this block is usable.
126 */
127 bh->b_state = 0;
128
129 if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
130 goto done;
131
132 p = (struct partition *) (0x1BE + bh->b_data);
133
134 this_size = hd->part[MINOR(dev)].nr_sects;
135
136 /*
137 * Usually, the first entry is the real data partition,
138 * the 2nd entry is the next extended partition, or empty,
139 * and the 3rd and 4th entries are unused.
140 * However, DRDOS sometimes has the extended partition as
141 * the first entry (when the data partition is empty),
142 * and OS/2 seems to use all four entries.
143 */
144
145 /*
146 * First process the data partition(s)
147 */
148 for (i=0; i<4; i++, p++) {
149 if (!NR_SECTS(p) || is_extended_partition(p))
150 continue;
151
152 /* Check the 3rd and 4th entries -
153 these sometimes contain random garbage */
154 if (i >= 2
155 && START_SECT(p) + NR_SECTS(p) > this_size
156 && (this_sector + START_SECT(p) < first_sector ||
157 this_sector + START_SECT(p) + NR_SECTS(p) >
158 first_sector + first_size))
159 continue;
160
161 add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p));
162 current_minor++;
163 if ((current_minor & mask) == 0)
164 goto done;
165 }
166 /*
167 * Next, process the (first) extended partition, if present.
168 * (So far, there seems to be no reason to make
169 * extended_partition() recursive and allow a tree
170 * of extended partitions.)
171 * It should be a link to the next logical partition.
172 * Create a minor for this just long enough to get the next
173 * partition table. The minor will be reused for the next
174 * data partition.
175 */
176 p -= 4;
177 for (i=0; i<4; i++, p++)
178 if(NR_SECTS(p) && is_extended_partition(p))
179 break;
180 if (i == 4)
181 goto done; /* nothing left to do */
182
183 hd->part[current_minor].nr_sects = NR_SECTS(p);
184 hd->part[current_minor].start_sect = first_sector + START_SECT(p);
185 this_sector = first_sector + START_SECT(p);
186 dev = MKDEV(hd->major, current_minor);
187 brelse(bh);
188 }
189 done:
190 brelse(bh);
191 }
192
193 static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
194 {
195 int i, minor = current_minor;
196 struct buffer_head *bh;
197 struct partition *p;
198 unsigned char *data;
199 int mask = (1 << hd->minor_shift) - 1;
200 #ifdef CONFIG_BLK_DEV_IDE
201 int tested_for_dm6 = 0;
202
203 read_mbr:
204 #endif
205 if (!(bh = bread(dev,0,1024))) {
206 printk(" unable to read partition table\n");
207 return -1;
208 }
209 data = bh->b_data;
210 /* In some cases we modify the geometry */
211 /* of the drive (below), so ensure that */
212 /* nobody else tries to re-use this data. */
213 bh->b_state = 0;
214 #ifdef CONFIG_BLK_DEV_IDE
215 check_table:
216 #endif
217 if (*(unsigned short *) (0x1fe + data) != 0xAA55) {
218 brelse(bh);
219 return 0;
220 }
221 p = (struct partition *) (0x1be + data);
222
223 #ifdef CONFIG_BLK_DEV_IDE
224 /*
225 * Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
226 */
227 if (!tested_for_dm6++) { /* only check for DM6 *once* */
228 extern int ide_xlate_1024(kdev_t, int, const char *);
229 /* check for various "disk managers" which do strange things */
230 if (p->sys_ind == EZD_PARTITION) {
231 /*
232 * The remainder of the disk must be accessed using
233 * a translated geometry that reduces the number of
234 * apparent cylinders to less than 1024 if possible.
235 *
236 * ide_xlate_1024() will take care of the necessary
237 * adjustments to fool fdisk/LILO and partition check.
238 */
239 if (ide_xlate_1024(dev, -1, " [EZD]")) {
240 data += 512;
241 goto check_table;
242 }
243 } else if (p->sys_ind == DM6_PARTITION) {
244
245 /*
246 * Everything on the disk is offset by 63 sectors,
247 * including a "new" MBR with its own partition table,
248 * and the remainder of the disk must be accessed using
249 * a translated geometry that reduces the number of
250 * apparent cylinders to less than 1024 if possible.
251 *
252 * ide_xlate_1024() will take care of the necessary
253 * adjustments to fool fdisk/LILO and partition check.
254 */
255 if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
256 brelse(bh);
257 goto read_mbr; /* start over with new MBR */
258 }
259 } else {
260 /* look for DM6 signature in MBR, courtesy of OnTrack */
261 unsigned int sig = *(unsigned short *)(data + 2);
262 if (sig <= 0x1ae
263 && *(unsigned short *)(data + sig) == 0x55AA
264 && (1 & *(unsigned char *)(data + sig + 2)) )
265 {
266 (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
267 } else {
268 /* look for DM6 AUX partition type in slot 1 */
269 if (p->sys_ind == DM6_AUX1PARTITION
270 || p->sys_ind == DM6_AUX3PARTITION)
271 {
272 (void)ide_xlate_1024(dev, 0, " [DM6:AUX]");
273 }
274 }
275 }
276 }
277 #endif /* CONFIG_BLK_DEV_IDE */
278
279 current_minor += 4; /* first "extra" minor (for extended partitions) */
280 for (i=1 ; i<=4 ; minor++,i++,p++) {
281 if (!NR_SECTS(p))
282 continue;
283 add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
284 if (is_extended_partition(p)) {
285 printk(" <");
286 /*
287 * If we are rereading the partition table, we need
288 * to set the size of the partition so that we will
289 * be able to bread the block containing the extended
290 * partition info.
291 */
292 hd->sizes[minor] = hd->part[minor].nr_sects
293 >> (BLOCK_SIZE_BITS - 9);
294 extended_partition(hd, MKDEV(hd->major, minor));
295 printk(" >");
296 /* prevent someone doing mkfs or mkswap on an
297 extended partition, but leave room for LILO */
298 if (hd->part[minor].nr_sects > 2)
299 hd->part[minor].nr_sects = 2;
300 }
301 }
302 /*
303 * Check for old-style Disk Manager partition table
304 */
305 if (*(unsigned short *) (data+0xfc) == 0x55AA) {
306 p = (struct partition *) (0x1be + data);
307 for (i = 4 ; i < 16 ; i++, current_minor++) {
308 p--;
309 if ((current_minor & mask) == 0)
310 break;
311 if (!(START_SECT(p) && NR_SECTS(p)))
312 continue;
313 add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
314 }
315 }
316 printk("\n");
317 brelse(bh);
318 return 1;
319 }
320
321 #endif /* CONFIG_MSDOS_PARTITION */
322
323 #ifdef CONFIG_OSF_PARTITION
324
325 static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
326 {
327 int i;
328 int mask = (1 << hd->minor_shift) - 1;
329 struct buffer_head *bh;
330 struct disklabel {
331 u32 d_magic;
332 u16 d_type,d_subtype;
333 u8 d_typename[16];
334 u8 d_packname[16];
335 u32 d_secsize;
336 u32 d_nsectors;
337 u32 d_ntracks;
338 u32 d_ncylinders;
339 u32 d_secpercyl;
340 u32 d_secprtunit;
341 u16 d_sparespertrack;
342 u16 d_sparespercyl;
343 u32 d_acylinders;
344 u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
345 u32 d_headswitch, d_trkseek, d_flags;
346 u32 d_drivedata[5];
347 u32 d_spare[5];
348 u32 d_magic2;
349 u16 d_checksum;
350 u16 d_npartitions;
351 u32 d_bbsize, d_sbsize;
352 struct d_partition {
353 u32 p_size;
354 u32 p_offset;
355 u32 p_fsize;
356 u8 p_fstype;
357 u8 p_frag;
358 u16 p_cpg;
359 } d_partitions[8];
360 } * label;
361 struct d_partition * partition;
362 #define DISKLABELMAGIC (0x82564557UL)
363
364 if (!(bh = bread(dev,0,1024))) {
365 printk("unable to read partition table\n");
366 return -1;
367 }
368 label = (struct disklabel *) (bh->b_data+64);
369 partition = label->d_partitions;
370 if (label->d_magic != DISKLABELMAGIC) {
371 printk("magic: %08x\n", label->d_magic);
372 brelse(bh);
373 return 0;
374 }
375 if (label->d_magic2 != DISKLABELMAGIC) {
376 printk("magic2: %08x\n", label->d_magic2);
377 brelse(bh);
378 return 0;
379 }
380 for (i = 0 ; i < label->d_npartitions; i++, partition++) {
381 if ((current_minor & mask) == 0)
382 break;
383 if (partition->p_size)
384 add_partition(hd, current_minor,
385 first_sector+partition->p_offset,
386 partition->p_size);
387 current_minor++;
388 }
389 printk("\n");
390 brelse(bh);
391 return 1;
392 }
393
394 #endif /* CONFIG_OSF_PARTITION */
395
396 #ifdef CONFIG_SUN_PARTITION
397
398 static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
399 {
400 int i, csum;
401 unsigned short *ush;
402 struct buffer_head *bh;
403 struct sun_disklabel {
404 unsigned char info[128]; /* Informative text string */
405 unsigned char spare[292]; /* Boot information etc. */
406 unsigned short rspeed; /* Disk rotational speed */
407 unsigned short pcylcount; /* Physical cylinder count */
408 unsigned short sparecyl; /* extra sects per cylinder */
409 unsigned char spare2[4]; /* More magic... */
410 unsigned short ilfact; /* Interleave factor */
411 unsigned short ncyl; /* Data cylinder count */
412 unsigned short nacyl; /* Alt. cylinder count */
413 unsigned short ntrks; /* Tracks per cylinder */
414 unsigned short nsect; /* Sectors per track */
415 unsigned char spare3[4]; /* Even more magic... */
416 struct sun_partition {
417 unsigned long start_cylinder;
418 unsigned long num_sectors;
419 } partitions[8];
420 unsigned short magic; /* Magic number */
421 unsigned short csum; /* Label xor'd checksum */
422 } * label;
423 struct sun_partition *p;
424 unsigned long spc;
425 #define SUN_LABEL_MAGIC 0xDABE
426
427 if(!(bh = bread(dev, 0, 1024))) {
428 printk("Dev %d: unable to read partition table\n", dev);
429 return -1;
430 }
431 label = (struct sun_disklabel *) bh->b_data;
432 p = label->partitions;
433 if(label->magic != SUN_LABEL_MAGIC) {
434 printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic);
435 brelse(bh);
436 return 0;
437 }
438 /* Look at the checksum */
439 ush = ((unsigned short *) (label+1)) - 1;
440 for(csum = 0; ush >= ((unsigned short *) label);)
441 csum ^= *ush--;
442 if(csum) {
443 printk("Dev %d Sun disklabel: Csum bad, label corrupted\n", dev);
444 brelse(bh);
445 return 0;
446 }
447 /* All Sun disks have 8 partition entries */
448 spc = (label->ntrks * label->nsect);
449 for(i=0; i < 8; i++, p++) {
450 unsigned long st_sector;
451
452 /* We register all partitions, even if zero size, so that
453 * the minor numbers end up ok as per SunOS interpretation.
454 */
455 st_sector = first_sector + (p->start_cylinder * spc);
456 add_partition(hd, current_minor, st_sector, p->num_sectors);
457 current_minor++;
458 }
459 printk("\n");
460 brelse(bh);
461 return 1;
462 }
463
464 #endif /* CONFIG_SUN_PARTITION */
465
466 static void check_partition(struct gendisk *hd, kdev_t dev)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
467 {
468 static int first_time = 1;
469 unsigned long first_sector;
470
471 if (first_time)
472 printk("Partition check:\n");
473 first_time = 0;
474 first_sector = hd->part[MINOR(dev)].start_sect;
475
476 /*
477 * This is a kludge to allow the partition check to be
478 * skipped for specific drives (e.g. IDE cd-rom drives)
479 */
480 if ((int)first_sector == -1) {
481 hd->part[MINOR(dev)].start_sect = 0;
482 return;
483 }
484
485 printk(" ");
486 print_minor_name(hd, MINOR(dev));
487 #ifdef CONFIG_MSDOS_PARTITION
488 if (msdos_partition(hd, dev, first_sector))
489 return;
490 #endif
491 #ifdef CONFIG_OSF_PARTITION
492 if (osf_partition(hd, dev, first_sector))
493 return;
494 #endif
495 #ifdef CONFIG_SUN_PARTITION
496 if(sun_partition(hd, dev, first_sector))
497 return;
498 #endif
499 printk(" unknown partition table\n");
500 }
501
502 /* This function is used to re-read partition tables for removable disks.
503 Much of the cleanup from the old partition tables should have already been
504 done */
505
506 /* This function will re-read the partition tables for a given device,
507 and set things back up again. There are some important caveats,
508 however. You must ensure that no one is using the device, and no one
509 can start using the device while this function is being executed. */
510
511 void resetup_one_dev(struct gendisk *dev, int drive)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
512 {
513 int i;
514 int first_minor = drive << dev->minor_shift;
515 int end_minor = first_minor + dev->max_p;
516
517 blk_size[dev->major] = NULL;
518 current_minor = 1 + first_minor;
519 check_partition(dev, MKDEV(dev->major, first_minor));
520
521 /*
522 * We need to set the sizes array before we will be able to access
523 * any of the partitions on this device.
524 */
525 if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
526 for (i = first_minor; i < end_minor; i++)
527 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
528 blk_size[dev->major] = dev->sizes;
529 }
530 }
531
532 static void setup_dev(struct gendisk *dev)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
533 {
534 int i, drive;
535 int end_minor = dev->max_nr * dev->max_p;
536
537 blk_size[dev->major] = NULL;
538 for (i = 0 ; i < end_minor; i++) {
539 dev->part[i].start_sect = 0;
540 dev->part[i].nr_sects = 0;
541 }
542 dev->init(dev);
543 for (drive = 0 ; drive < dev->nr_real ; drive++) {
544 int first_minor = drive << dev->minor_shift;
545 current_minor = 1 + first_minor;
546 check_partition(dev, MKDEV(dev->major, first_minor));
547 }
548 if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
549 for (i = 0; i < end_minor; i++)
550 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
551 blk_size[dev->major] = dev->sizes;
552 }
553 }
554
555 void device_setup(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
556 {
557 extern void console_map_init(void);
558 struct gendisk *p;
559 int nr=0;
560
561 chr_dev_init();
562 blk_dev_init();
563 sti();
564 #ifdef CONFIG_SCSI
565 scsi_dev_init();
566 #endif
567 #ifdef CONFIG_INET
568 net_dev_init();
569 #endif
570 console_map_init();
571
572 for (p = gendisk_head ; p ; p=p->next) {
573 setup_dev(p);
574 nr += p->nr_real;
575 }
576 #ifdef CONFIG_BLK_DEV_RAM
577 rd_load();
578 #endif
579 }