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 struct gendisk *gendisk_head = NULL;
29
30 static int current_minor = 0;
31 extern int *blk_size[];
32 extern void rd_load(void);
33 extern int ramdisk_size;
34
35 extern int chr_dev_init(void);
36 extern int blk_dev_init(void);
37 extern int scsi_dev_init(void);
38 extern int net_dev_init(void);
39
40 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)
*/
41 {
42 unsigned int unit = minor >> hd->minor_shift;
43 unsigned int part = minor & ((1 << hd->minor_shift) - 1);
44
45 #ifdef CONFIG_BLK_DEV_IDE
46 /*
47 * IDE devices use multiple major numbers, but the drives
48 * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
49 * This requires some creative handling here to find the
50 * correct name to use, with some help from ide.c
51 */
52 if (!strcmp(hd->major_name,"ide")) {
53 char name[16]; /* more than large enough */
54 strcpy(name, hd->real_devices); /* courtesy ide.c */
55 name[strlen(name)-1] += unit;
56 printk(" %s", name);
57 } else
58 #endif
59 printk(" %s%c", hd->major_name, 'a' + unit);
60 if (part)
61 printk("%d", part);
62 else
63 printk(":");
64 }
65
66 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)
*/
67 {
68 hd->part[minor].start_sect = start;
69 hd->part[minor].nr_sects = size;
70 print_minor_name(hd, minor);
71 }
72
73 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)
*/
74 {
75 return (p->sys_ind == DOS_EXTENDED_PARTITION ||
76 p->sys_ind == LINUX_EXTENDED_PARTITION);
77 }
78
79 #ifdef CONFIG_MSDOS_PARTITION
80 /*
81 * Create devices for each logical partition in an extended partition.
82 * The logical partitions form a linked list, with each entry being
83 * a partition table with two entries. The first entry
84 * is the real data partition (with a start relative to the partition
85 * table start). The second is a pointer to the next logical partition
86 * (with a start relative to the entire extended partition).
87 * We do not create a Linux partition for the partition tables, but
88 * only for the actual data partitions.
89 */
90
91 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)
*/
92 {
93 struct buffer_head *bh;
94 struct partition *p;
95 unsigned long first_sector, first_size, this_sector, this_size;
96 int mask = (1 << hd->minor_shift) - 1;
97 int i;
98
99 first_sector = hd->part[MINOR(dev)].start_sect;
100 first_size = hd->part[MINOR(dev)].nr_sects;
101 this_sector = first_sector;
102
103 while (1) {
104 if ((current_minor & mask) == 0)
105 return;
106 if (!(bh = bread(dev,0,1024)))
107 return;
108 /*
109 * This block is from a device that we're about to stomp on.
110 * So make sure nobody thinks this block is usable.
111 */
112 bh->b_dirt = 0;
113 bh->b_uptodate = 0;
114 bh->b_req = 0;
115
116 if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
117 goto done;
118
119 p = (struct partition *) (0x1BE + bh->b_data);
120
121 this_size = hd->part[MINOR(dev)].nr_sects;
122
123 /*
124 * Usually, the first entry is the real data partition,
125 * the 2nd entry is the next extended partition, or empty,
126 * and the 3rd and 4th entries are unused.
127 * However, DRDOS sometimes has the extended partition as
128 * the first entry (when the data partition is empty),
129 * and OS/2 seems to use all four entries.
130 */
131
132 /*
133 * First process the data partition(s)
134 */
135 for (i=0; i<4; i++, p++) {
136 if (!p->nr_sects || is_extended_partition(p))
137 continue;
138
139 /* Check the 3rd and 4th entries -
140 these sometimes contain random garbage */
141 if (i >= 2
142 && p->start_sect + p->nr_sects > this_size
143 && (this_sector + p->start_sect < first_sector ||
144 this_sector + p->start_sect + p->nr_sects >
145 first_sector + first_size))
146 continue;
147
148 add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
149 current_minor++;
150 if ((current_minor & mask) == 0)
151 goto done;
152 }
153 /*
154 * Next, process the (first) extended partition, if present.
155 * (So far, there seems to be no reason to make
156 * extended_partition() recursive and allow a tree
157 * of extended partitions.)
158 * It should be a link to the next logical partition.
159 * Create a minor for this just long enough to get the next
160 * partition table. The minor will be reused for the next
161 * data partition.
162 */
163 p -= 4;
164 for (i=0; i<4; i++, p++)
165 if(p->nr_sects && is_extended_partition(p))
166 break;
167 if (i == 4)
168 goto done; /* nothing left to do */
169
170 hd->part[current_minor].nr_sects = p->nr_sects;
171 hd->part[current_minor].start_sect = first_sector + p->start_sect;
172 this_sector = first_sector + p->start_sect;
173 dev = MKDEV(hd->major, current_minor);
174 brelse(bh);
175 }
176 done:
177 brelse(bh);
178 }
179
180 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)
*/
181 {
182 int i, minor = current_minor;
183 struct buffer_head *bh;
184 struct partition *p;
185 unsigned char *data;
186 int mask = (1 << hd->minor_shift) - 1;
187 #ifdef CONFIG_BLK_DEV_IDE
188 int tested_for_dm6 = 0;
189
190 read_mbr:
191 #endif
192 if (!(bh = bread(dev,0,1024))) {
193 printk(" unable to read partition table\n");
194 return -1;
195 }
196 data = bh->b_data;
197 bh->b_dirt = 0; /* In some cases we modify the geometry */
198 bh->b_uptodate = 0; /* of the drive (below), so ensure that */
199 bh->b_req = 0; /* nobody else tries to re-use this data. */
200 #ifdef CONFIG_BLK_DEV_IDE
201 check_table:
202 #endif
203 if (*(unsigned short *) (0x1fe + data) != 0xAA55) {
204 brelse(bh);
205 return 0;
206 }
207 p = (struct partition *) (0x1be + data);
208
209 #ifdef CONFIG_BLK_DEV_IDE
210 /*
211 * Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
212 */
213 if (!tested_for_dm6++) { /* only check for DM6 *once* */
214 extern int ide_xlate_1024(kdev_t, int, const char *);
215 /* check for various "disk managers" which do strange things */
216 if (p->sys_ind == EZD_PARTITION) {
217 /*
218 * The remainder of the disk must be accessed using
219 * a translated geometry that reduces the number of
220 * apparent cylinders to less than 1024 if possible.
221 *
222 * ide_xlate_1024() will take care of the necessary
223 * adjustments to fool fdisk/LILO and partition check.
224 */
225 if (ide_xlate_1024(dev, -1, " [EZD]")) {
226 data += 512;
227 goto check_table;
228 }
229 } else if (p->sys_ind == DM6_PARTITION) {
230
231 /*
232 * Everything on the disk is offset by 63 sectors,
233 * including a "new" MBR with its own partition table,
234 * and the remainder of the disk must be accessed using
235 * a translated geometry that reduces the number of
236 * apparent cylinders to less than 1024 if possible.
237 *
238 * ide_xlate_1024() will take care of the necessary
239 * adjustments to fool fdisk/LILO and partition check.
240 */
241 if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
242 brelse(bh);
243 goto read_mbr; /* start over with new MBR */
244 }
245 } else {
246 /* look for DM6 signature in MBR, courtesy of OnTrack */
247 unsigned int sig = *(unsigned short *)(data + 2);
248 if (sig <= 0x1ae
249 && *(unsigned short *)(data + sig) == 0x55AA
250 && (1 & *(unsigned char *)(data + sig + 2)) )
251 {
252 (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
253 } else {
254 /* look for DM6 AUX partition type in slot 1 */
255 if (p->sys_ind == DM6_AUX1PARTITION
256 || p->sys_ind == DM6_AUX3PARTITION)
257 {
258 (void)ide_xlate_1024(dev, 0, " [DM6:AUX]");
259 }
260 }
261 }
262 }
263 #endif /* CONFIG_BLK_DEV_IDE */
264
265 current_minor += 4; /* first "extra" minor (for extended partitions) */
266 for (i=1 ; i<=4 ; minor++,i++,p++) {
267 if (!p->nr_sects)
268 continue;
269 add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects);
270 if (is_extended_partition(p)) {
271 printk(" <");
272 /*
273 * If we are rereading the partition table, we need
274 * to set the size of the partition so that we will
275 * be able to bread the block containing the extended
276 * partition info.
277 */
278 hd->sizes[minor] = hd->part[minor].nr_sects
279 >> (BLOCK_SIZE_BITS - 9);
280 extended_partition(hd, MKDEV(hd->major, minor));
281 printk(" >");
282 /* prevent someone doing mkfs or mkswap on an
283 extended partition, but leave room for LILO */
284 if (hd->part[minor].nr_sects > 2)
285 hd->part[minor].nr_sects = 2;
286 }
287 }
288 /*
289 * Check for old-style Disk Manager partition table
290 */
291 if (*(unsigned short *) (data+0xfc) == 0x55AA) {
292 p = (struct partition *) (0x1be + data);
293 for (i = 4 ; i < 16 ; i++, current_minor++) {
294 p--;
295 if ((current_minor & mask) == 0)
296 break;
297 if (!(p->start_sect && p->nr_sects))
298 continue;
299 add_partition(hd, current_minor, p->start_sect, p->nr_sects);
300 }
301 }
302 printk("\n");
303 brelse(bh);
304 return 1;
305 }
306
307 #endif /* CONFIG_MSDOS_PARTITION */
308
309 #ifdef CONFIG_OSF_PARTITION
310
311 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)
*/
312 {
313 int i;
314 int mask = (1 << hd->minor_shift) - 1;
315 struct buffer_head *bh;
316 struct disklabel {
317 u32 d_magic;
318 u16 d_type,d_subtype;
319 u8 d_typename[16];
320 u8 d_packname[16];
321 u32 d_secsize;
322 u32 d_nsectors;
323 u32 d_ntracks;
324 u32 d_ncylinders;
325 u32 d_secpercyl;
326 u32 d_secprtunit;
327 u16 d_sparespertrack;
328 u16 d_sparespercyl;
329 u32 d_acylinders;
330 u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
331 u32 d_headswitch, d_trkseek, d_flags;
332 u32 d_drivedata[5];
333 u32 d_spare[5];
334 u32 d_magic2;
335 u16 d_checksum;
336 u16 d_npartitions;
337 u32 d_bbsize, d_sbsize;
338 struct d_partition {
339 u32 p_size;
340 u32 p_offset;
341 u32 p_fsize;
342 u8 p_fstype;
343 u8 p_frag;
344 u16 p_cpg;
345 } d_partitions[8];
346 } * label;
347 struct d_partition * partition;
348 #define DISKLABELMAGIC (0x82564557UL)
349
350 if (!(bh = bread(dev,0,1024))) {
351 printk("unable to read partition table\n");
352 return -1;
353 }
354 label = (struct disklabel *) (bh->b_data+64);
355 partition = label->d_partitions;
356 if (label->d_magic != DISKLABELMAGIC) {
357 printk("magic: %08x\n", label->d_magic);
358 brelse(bh);
359 return 0;
360 }
361 if (label->d_magic2 != DISKLABELMAGIC) {
362 printk("magic2: %08x\n", label->d_magic2);
363 brelse(bh);
364 return 0;
365 }
366 for (i = 0 ; i < label->d_npartitions; i++, partition++) {
367 if ((current_minor & mask) == 0)
368 break;
369 if (partition->p_size)
370 add_partition(hd, current_minor,
371 first_sector+partition->p_offset,
372 partition->p_size);
373 current_minor++;
374 }
375 printk("\n");
376 brelse(bh);
377 return 1;
378 }
379
380 #endif /* CONFIG_OSF_PARTITION */
381
382 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)
*/
383 {
384 static int first_time = 1;
385 unsigned long first_sector;
386
387 if (first_time)
388 printk("Partition check:\n");
389 first_time = 0;
390 first_sector = hd->part[MINOR(dev)].start_sect;
391
392 /*
393 * This is a kludge to allow the partition check to be
394 * skipped for specific drives (e.g. IDE cd-rom drives)
395 */
396 if ((int)first_sector == -1) {
397 hd->part[MINOR(dev)].start_sect = 0;
398 return;
399 }
400
401 printk(" ");
402 print_minor_name(hd, MINOR(dev));
403 #ifdef CONFIG_MSDOS_PARTITION
404 if (msdos_partition(hd, dev, first_sector))
405 return;
406 #endif
407 #ifdef CONFIG_OSF_PARTITION
408 if (osf_partition(hd, dev, first_sector))
409 return;
410 #endif
411 printk(" unknown partition table\n");
412 }
413
414 /* This function is used to re-read partition tables for removable disks.
415 Much of the cleanup from the old partition tables should have already been
416 done */
417
418 /* This function will re-read the partition tables for a given device,
419 and set things back up again. There are some important caveats,
420 however. You must ensure that no one is using the device, and no one
421 can start using the device while this function is being executed. */
422
423 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)
*/
424 {
425 int i;
426 int first_minor = drive << dev->minor_shift;
427 int end_minor = first_minor + dev->max_p;
428
429 blk_size[dev->major] = NULL;
430 current_minor = 1 + first_minor;
431 check_partition(dev, MKDEV(dev->major, first_minor));
432
433 /*
434 * We need to set the sizes array before we will be able to access
435 * any of the partitions on this device.
436 */
437 if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
438 for (i = first_minor; i < end_minor; i++)
439 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
440 blk_size[dev->major] = dev->sizes;
441 }
442 }
443
444 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)
*/
445 {
446 int i, drive;
447 int end_minor = dev->max_nr * dev->max_p;
448
449 blk_size[dev->major] = NULL;
450 for (i = 0 ; i < end_minor; i++) {
451 dev->part[i].start_sect = 0;
452 dev->part[i].nr_sects = 0;
453 }
454 dev->init(dev);
455 for (drive = 0 ; drive < dev->nr_real ; drive++) {
456 int first_minor = drive << dev->minor_shift;
457 current_minor = 1 + first_minor;
458 check_partition(dev, MKDEV(dev->major, first_minor));
459 }
460 if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
461 for (i = 0; i < end_minor; i++)
462 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
463 blk_size[dev->major] = dev->sizes;
464 }
465 }
466
467 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)
*/
468 {
469 extern void console_map_init(void);
470 struct gendisk *p;
471 int nr=0;
472
473 chr_dev_init();
474 blk_dev_init();
475 sti();
476 #ifdef CONFIG_SCSI
477 scsi_dev_init();
478 #endif
479 #ifdef CONFIG_INET
480 net_dev_init();
481 #endif
482 console_map_init();
483
484 for (p = gendisk_head ; p ; p=p->next) {
485 setup_dev(p);
486 nr += p->nr_real;
487 }
488
489 if (ramdisk_size)
490 rd_load();
491 }