OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [block/] [genhd.c] - Blame information for rev 1765

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1622 jcastillo
/*
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,
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
 *  Modifications Copyright (C) 1995, 1996 Russell King
19
 *
20
 *  Origional from linux/drivers/genhd.c
21
 *
22
 *  Altered to find image files on ADFS-formatted hard drives.
23
 */
24
 
25
#include <linux/config.h>
26
#include <linux/fs.h>
27
#include <linux/genhd.h>
28
#include <linux/kernel.h>
29
#include <linux/major.h>
30
#include <linux/string.h>
31
#ifdef CONFIG_BLK_DEV_INITRD
32
#include <linux/blk.h>
33
#endif
34
 
35
#include <asm/system.h>
36
 
37
/*
38
 * Many architectures don't like unaligned accesses, which is
39
 * frequently the case with the nr_sects and start_sect partition
40
 * table entries.
41
 */
42
#include <asm/unaligned.h>
43
 
44
#define SYS_IND(p)      get_unaligned(&p->sys_ind)
45
#define NR_SECTS(p)     get_unaligned(&p->nr_sects)
46
#define START_SECT(p)   get_unaligned(&p->start_sect)
47
 
48
 
49
struct gendisk *gendisk_head;
50
 
51
static int current_minor;
52
extern int *blk_size[];
53
extern void rd_load(void);
54
extern void initrd_load(void);
55
 
56
extern int chr_dev_init(void);
57
extern int blk_dev_init(void);
58
extern int scsi_dev_init(void);
59
extern int net_dev_init(void);
60
 
61
/*
62
 * disk_name() is used by genhd.c and md.c.
63
 * It formats the devicename of the indicated disk
64
 * into the supplied buffer, and returns a pointer
65
 * to that same buffer (for convenience).
66
 */
67
char *disk_name (struct gendisk *hd, int minor, char *buf)
68
{
69
        unsigned int part;
70
        const char *maj = hd->major_name;
71
        char unit = (minor >> hd->minor_shift) + 'a';
72
 
73
#ifdef CONFIG_BLK_DEV_IDE
74
        /*
75
         * IDE devices use multiple major numbers, but the drives
76
         * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
77
         * This requires special handling here.
78
         */
79
        switch (hd->major) {
80
                case IDE3_MAJOR:
81
                        unit += 2;
82
                case IDE2_MAJOR:
83
                        unit += 2;
84
                case IDE1_MAJOR:
85
                        unit += 2;
86
                case IDE0_MAJOR:
87
                        maj = "hd";
88
        }
89
#endif
90
        part = minor & ((1 << hd->minor_shift) - 1);
91
        if (part)
92
                sprintf(buf, "%s%c%d", maj, unit, part);
93
        else
94
                sprintf(buf, "%s%c", maj, unit);
95
        return buf;
96
}
97
 
98
void add_partition (struct gendisk *hd, int minor, int start, int size)
99
{
100
        char buf[8];
101
        hd->part[minor].start_sect = start;
102
        hd->part[minor].nr_sects   = size;
103
        printk(" %s", disk_name(hd, minor, buf));
104
}
105
 
106
static inline int is_extended_partition(struct partition *p)
107
{
108
        return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
109
                SYS_IND(p) == LINUX_EXTENDED_PARTITION);
110
}
111
 
112
#ifdef CONFIG_MSDOS_PARTITION
113
/*
114
 * Create devices for each logical partition in an extended partition.
115
 * The logical partitions form a linked list, with each entry being
116
 * a partition table with two entries.  The first entry
117
 * is the real data partition (with a start relative to the partition
118
 * table start).  The second is a pointer to the next logical partition
119
 * (with a start relative to the entire extended partition).
120
 * We do not create a Linux partition for the partition tables, but
121
 * only for the actual data partitions.
122
 */
123
 
124
static void extended_partition(struct gendisk *hd, kdev_t dev)
125
{
126
        struct buffer_head *bh;
127
        struct partition *p;
128
        unsigned long first_sector, first_size, this_sector, this_size;
129
        int mask = (1 << hd->minor_shift) - 1;
130
        int i;
131
 
132
        first_sector = hd->part[MINOR(dev)].start_sect;
133
        first_size = hd->part[MINOR(dev)].nr_sects;
134
        this_sector = first_sector;
135
 
136
        while (1) {
137
                if ((current_minor & mask) == 0)
138
                        return;
139
                if (!(bh = bread(dev,0,1024)))
140
                        return;
141
          /*
142
           * This block is from a device that we're about to stomp on.
143
           * So make sure nobody thinks this block is usable.
144
           */
145
                bh->b_state = 0;
146
 
147
                if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
148
                        goto done;
149
 
150
                p = (struct partition *) (0x1BE + bh->b_data);
151
 
152
                this_size = hd->part[MINOR(dev)].nr_sects;
153
 
154
                /*
155
                 * Usually, the first entry is the real data partition,
156
                 * the 2nd entry is the next extended partition, or empty,
157
                 * and the 3rd and 4th entries are unused.
158
                 * However, DRDOS sometimes has the extended partition as
159
                 * the first entry (when the data partition is empty),
160
                 * and OS/2 seems to use all four entries.
161
                 */
162
 
163
                /*
164
                 * First process the data partition(s)
165
                 */
166
                for (i=0; i<4; i++, p++) {
167
                    if (!NR_SECTS(p) || is_extended_partition(p))
168
                      continue;
169
 
170
                    /* Check the 3rd and 4th entries -
171
                       these sometimes contain random garbage */
172
                    if (i >= 2
173
                        && START_SECT(p) + NR_SECTS(p) > this_size
174
                        && (this_sector + START_SECT(p) < first_sector ||
175
                            this_sector + START_SECT(p) + NR_SECTS(p) >
176
                             first_sector + first_size))
177
                      continue;
178
 
179
                    add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p));
180
                    current_minor++;
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
                hd->part[current_minor].nr_sects = NR_SECTS(p);
202
                hd->part[current_minor].start_sect = first_sector + START_SECT(p);
203
                this_sector = first_sector + START_SECT(p);
204
                dev = MKDEV(hd->major, current_minor);
205
                brelse(bh);
206
        }
207
done:
208
        brelse(bh);
209
}
210
 
211
#ifdef CONFIG_BSD_DISKLABEL
212
/*
213
 * Create devices for BSD partitions listed in a disklabel, under a
214
 * dos-like partition. See extended_partition() for more information.
215
 */
216
static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
217
{
218
        struct buffer_head *bh;
219
        struct bsd_disklabel *l;
220
        struct bsd_partition *p;
221
        int mask = (1 << hd->minor_shift) - 1;
222
 
223
        if (!(bh = bread(dev,0,1024)))
224
                return;
225
        bh->b_state = 0;
226
        l = (struct bsd_disklabel *) (bh->b_data+512);
227
        if (l->d_magic != BSD_DISKMAGIC) {
228
                brelse(bh);
229
                return;
230
        }
231
 
232
        p = &l->d_partitions[0];
233
        while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) {
234
                if ((current_minor & mask) >= (4 + hd->max_p))
235
                        break;
236
 
237
                if (p->p_fstype != BSD_FS_UNUSED) {
238
                        add_partition(hd, current_minor, p->p_offset, p->p_size);
239
                        current_minor++;
240
                }
241
                p++;
242
        }
243
        brelse(bh);
244
 
245
}
246
#endif
247
 
248
static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
249
{
250
        int i, minor = current_minor;
251
        struct buffer_head *bh;
252
        struct partition *p;
253
        unsigned char *data;
254
        int mask = (1 << hd->minor_shift) - 1;
255
 
256
        if (!(bh = bread(dev,0,1024))) {
257
                printk(" unable to read partition table\n");
258
                return -1;
259
        }
260
        data = bh->b_data;
261
        /* In some cases we modify the geometry    */
262
        /*  of the drive (below), so ensure that   */
263
        /*  nobody else tries to re-use this data. */
264
        bh->b_state = 0;
265
 
266
        if (*(unsigned short *)  (0x1fe + data) != 0xAA55) {
267
                brelse(bh);
268
                return 0;
269
        }
270
        printk (" [DOS]");
271
        p = (struct partition *) (0x1be + data);
272
 
273
        current_minor += 4;  /* first "extra" minor (for extended partitions) */
274
        for (i=1 ; i<=4 ; minor++,i++,p++) {
275
                if (!NR_SECTS(p))
276
                        continue;
277
                add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
278
                if (is_extended_partition(p)) {
279
                        printk(" <");
280
                        /*
281
                         * If we are rereading the partition table, we need
282
                         * to set the size of the partition so that we will
283
                         * be able to bread the block containing the extended
284
                         * partition info.
285
                         */
286
                        hd->sizes[minor] = hd->part[minor].nr_sects
287
                                >> (BLOCK_SIZE_BITS - 9);
288
                        extended_partition(hd, MKDEV(hd->major, minor));
289
                        printk(" >");
290
                        /* prevent someone doing mkfs or mkswap on an
291
                           extended partition, but leave room for LILO */
292
                        if (hd->part[minor].nr_sects > 2)
293
                                hd->part[minor].nr_sects = 2;
294
                }
295
#ifdef CONFIG_BSD_DISKLABEL
296
                if (SYS_IND(p) == BSD_PARTITION) {
297
                        printk(" <");
298
                        bsd_disklabel_partition(hd, MKDEV(hd->major, minor));
299
                        printk(" >");
300
                }
301
#endif
302
        }
303
        /*
304
         *  Check for old-style Disk Manager partition table
305
         */
306
        if (*(unsigned short *) (data+0xfc) == 0x55AA) {
307
                p = (struct partition *) (0x1be + data);
308
                for (i = 4 ; i < 16 ; i++, current_minor++) {
309
                        p--;
310
                        if ((current_minor & mask) == 0)
311
                                break;
312
                        if (!(START_SECT(p) && NR_SECTS(p)))
313
                                continue;
314
                        add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
315
                }
316
        }
317
        printk("\n");
318
        brelse(bh);
319
        return 1;
320
}
321
 
322
#endif /* CONFIG_MSDOS_PARTITION */
323
 
324
extern int adfspart_initdev (struct gendisk *hd, kdev_t dev, int first_sector, int minor);
325
 
326
static void check_partition(struct gendisk *hd, kdev_t dev)
327
{
328
        static int first_time = 1;
329
        unsigned long first_sector;
330
        char buf[8];
331
 
332
        if (first_time)
333
                printk("Partition check:\n");
334
        first_time = 0;
335
        first_sector = hd->part[MINOR(dev)].start_sect;
336
 
337
        /*
338
         * This is a kludge to allow the partition check to be
339
         * skipped for specific drives (e.g. IDE cd-rom drives)
340
         */
341
        if ((int)first_sector == -1) {
342
                hd->part[MINOR(dev)].start_sect = 0;
343
                return;
344
        }
345
 
346
        printk(" %s:", disk_name(hd, MINOR(dev), buf));
347
#ifdef CONFIG_BLK_DEV_PART
348
        if (adfspart_initdev (hd, dev, first_sector, current_minor))
349
                return;
350
#endif
351
#ifdef CONFIG_MSDOS_PARTITION
352
        if (msdos_partition(hd, dev, first_sector))
353
                return;
354
#endif
355
        printk(" unknown partition table\n");
356
}
357
 
358
/*
359
 * This function is used to re-read partition tables for removable disks.
360
 * Much of the cleanup from the old partition tables should have already been
361
 * done
362
 */
363
 
364
/*
365
 * This function will re-read the partition tables for a given device,
366
 * and set things back up again.  There are some important caveats,
367
 * however.  You must ensure that no one is using the device, and no one
368
 * can start using the device while this function is being executed.
369
 */
370
void resetup_one_dev(struct gendisk *dev, int drive)
371
{
372
        int i;
373
        int first_minor = drive << dev->minor_shift;
374
        int end_minor   = first_minor + dev->max_p;
375
 
376
        blk_size[dev->major] = NULL;
377
        current_minor = 1 + first_minor;
378
        check_partition(dev, MKDEV(dev->major, first_minor));
379
 
380
        /*
381
         * We need to set the sizes array before we will be able to access
382
         * any of the partitions on this device.
383
         */
384
        if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
385
                for (i = first_minor; i < end_minor; i++)
386
                        dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
387
                blk_size[dev->major] = dev->sizes;
388
        }
389
}
390
 
391
static void setup_dev(struct gendisk *dev)
392
{
393
        int i, drive;
394
        int end_minor   = dev->max_nr * dev->max_p;
395
 
396
        blk_size[dev->major] = NULL;
397
        for (i = 0 ; i < end_minor; i++) {
398
                dev->part[i].start_sect = 0;
399
                dev->part[i].nr_sects = 0;
400
        }
401
        dev->init(dev);
402
        for (drive = 0 ; drive < dev->nr_real ; drive++) {
403
                int first_minor = drive << dev->minor_shift;
404
                current_minor = 1 + first_minor;
405
                check_partition(dev, MKDEV(dev->major, first_minor));
406
        }
407
        if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
408
                for (i = 0; i < end_minor; i++)
409
                        dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
410
                blk_size[dev->major] = dev->sizes;
411
        }
412
}
413
 
414
void device_setup(void)
415
{
416
        extern void console_map_init(void);
417
        extern void adfsimg_init (void);
418
        struct gendisk *p;
419
        int nr=0;
420
 
421
        chr_dev_init();
422
        blk_dev_init();
423
        sti();
424
#ifdef CONFIG_SCSI
425
        scsi_dev_init();
426
#endif
427
#ifdef CONFIG_INET
428
        net_dev_init();
429
#endif
430
        console_map_init();
431
#ifdef CONFIG_BLK_DEV_IMG
432
        adfsimg_init ();
433
#endif
434
        for (p = gendisk_head ; p ; p=p->next) {
435
                setup_dev(p);
436
                nr += p->nr_real;
437
        }
438
#ifdef CONFIG_BLK_DEV_RAM
439
#ifdef CONFIG_BLK_DEV_INITRD
440
        if (initrd_start && mount_initrd) initrd_load();
441
        else
442
#endif
443
        rd_load();
444
#endif
445
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.