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