root/drivers/block/genhd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_minor_name
  2. add_partition
  3. extended_partition
  4. msdos_partition
  5. osf_partition
  6. check_partition
  7. resetup_one_dev
  8. setup_dev
  9. device_setup

   1 /*
   2  *  Code extracted from
   3  *  linux/kernel/hd.c
   4  *
   5  *  Copyright (C) 1991, 1992  Linus Torvalds
   6  */
   7 
   8 /*
   9  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  10  *  in the early extended-partition checks and added DM partitions
  11  */
  12 
  13 /*
  14  *  Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
  15  *  with information provided by OnTrack.  This now works for linux fdisk
  16  *  and LILO, as well as loadlin and bootln.  Note that disks other than
  17  *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  18  */
  19 
  20 #include <linux/config.h>
  21 #include <linux/fs.h>
  22 #include <linux/genhd.h>
  23 #include <linux/kernel.h>
  24 #include <linux/major.h>
  25 #include <linux/string.h>
  26 
  27 struct gendisk *gendisk_head = NULL;
  28 
  29 static int current_minor = 0;
  30 extern int *blk_size[];
  31 extern void rd_load(void);
  32 extern int ramdisk_size;
  33 
  34 static void print_minor_name (struct gendisk *hd, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         unsigned int unit = minor >> hd->minor_shift;
  37         unsigned int part = minor & ((1 << hd->minor_shift) - 1);
  38 
  39 #ifdef CONFIG_BLK_DEV_IDE
  40         /*
  41          * IDE devices use multiple major numbers, but the drives
  42          * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
  43          * This requires some creative handling here to find the
  44          * correct name to use, with some help from ide.c
  45          */
  46         if (!strcmp(hd->major_name,"ide")) {
  47                 char name[16];          /* more than large enough */
  48                 strcpy(name, hd->real_devices); /* courtesy ide.c */
  49                 name[strlen(name)-1] += unit;
  50                 printk(" %s", name);
  51         } else
  52 #endif
  53                 printk(" %s%c", hd->major_name, 'a' + unit);
  54         if (part)
  55                 printk("%d", part);
  56         else
  57                 printk(":");
  58 }
  59 
  60 static void add_partition (struct gendisk *hd, int minor, int start, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         hd->part[minor].start_sect = start;
  63         hd->part[minor].nr_sects   = size;
  64         print_minor_name(hd, minor);
  65 }
  66 
  67 #ifdef CONFIG_MSDOS_PARTITION
  68 /*
  69  * Create devices for each logical partition in an extended partition.
  70  * The logical partitions form a linked list, with each entry being
  71  * a partition table with two entries.  The first entry
  72  * is the real data partition (with a start relative to the partition
  73  * table start).  The second is a pointer to the next logical partition
  74  * (with a start relative to the entire extended partition).
  75  * We do not create a Linux partition for the partition tables, but
  76  * only for the actual data partitions.
  77  */
  78 
  79 static void extended_partition(struct gendisk *hd, int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81         struct buffer_head *bh;
  82         struct partition *p;
  83         unsigned long first_sector, this_sector;
  84         int mask = (1 << hd->minor_shift) - 1;
  85 
  86         first_sector = hd->part[MINOR(dev)].start_sect;
  87         this_sector = first_sector;
  88 
  89         while (1) {
  90                 if ((current_minor & mask) >= (4 + 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                 if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
 102                         p = (struct partition *) (0x1BE + bh->b_data);
 103                 /*
 104                  * Process the first entry, which should be the real
 105                  * data partition.
 106                  */
 107                         if (p->sys_ind == EXTENDED_PARTITION || !p->nr_sects)
 108                                 goto done;  /* shouldn't happen */
 109                         add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
 110                         current_minor++;
 111                         p++;
 112                 /*
 113                  * Process the second entry, which should be a link
 114                  * to the next logical partition.  Create a minor
 115                  * for this just long enough to get the next partition
 116                  * table.  The minor will be reused for the real
 117                  * data partition.
 118                  */
 119                         if (p->sys_ind != EXTENDED_PARTITION ||
 120                             !(hd->part[current_minor].nr_sects = p->nr_sects))
 121                                 goto done;  /* no more logicals in this partition */
 122                         hd->part[current_minor].start_sect = first_sector + p->start_sect;
 123                         this_sector = first_sector + p->start_sect;
 124                         dev = ((hd->major) << 8) | current_minor;
 125                         brelse(bh);
 126                 } else
 127                         goto done;
 128         }
 129 done:
 130         brelse(bh);
 131 }
 132 
 133 static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         int i, minor = current_minor;
 136         struct buffer_head *bh;
 137         struct partition *p;
 138         int mask = (1 << hd->minor_shift) - 1;
 139 #ifdef CONFIG_BLK_DEV_IDE
 140         int tested_for_dm6 = 0;
 141 
 142 read_mbr:
 143 #endif
 144         if (!(bh = bread(dev,0,1024))) {
 145                 printk(" unable to read partition table\n");
 146                 return -1;
 147         }
 148         if (*(unsigned short *)  (0x1fe + bh->b_data) != 0xAA55) {
 149                 brelse(bh);
 150                 return 0;
 151         }
 152         p = (struct partition *) (0x1be + bh->b_data);
 153 
 154 #ifdef CONFIG_BLK_DEV_IDE
 155         /*
 156          *  Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
 157          */
 158         if (!tested_for_dm6++) {        /* only check for DM6 *once* */
 159                 extern int ide_xlate_1024(dev_t, int, const char *);
 160                 /* check for DM6 with Dynamic Drive Overlay (DDO) */
 161                 if (p->sys_ind == DM6_PARTITION || p->sys_ind == EZD_PARTITION) {
 162                         const char *label = (p->sys_ind == DM6_PARTITION)?" [DM6:DDO]":" [EZDRIVE]";
 163 
 164                         /*
 165                          * Everything on the disk is offset by 63 sectors,
 166                          * including a "new" MBR with its own partition table,
 167                          * and the remainder of the disk must be accessed using
 168                          * a translated geometry that reduces the number of 
 169                          * apparent cylinders to less than 1024 if possible.
 170                          *
 171                          * ide_xlate_1024() will take care of the necessary
 172                          * adjustments to fool fdisk/LILO and partition check.
 173                          */
 174                         if (ide_xlate_1024(dev, 1, label)) {
 175                                 bh->b_dirt = 0; /* force re-read of MBR block */
 176                                 bh->b_uptodate = 0;
 177                                 bh->b_req = 0;
 178                                 brelse(bh);
 179                                 goto read_mbr;  /* start over with new MBR */
 180                         }
 181                 } else {
 182                         /* look for DM6 signature in MBR, courtesy of OnTrack */
 183                         unsigned int sig = *(unsigned short *)(bh->b_data + 2);
 184                         if (sig <= 0x1ae
 185                          && *(unsigned short *)(bh->b_data + sig) == 0x55AA
 186                          && (1 & *(unsigned char *)(bh->b_data + sig + 2)) ) 
 187                         {
 188                                 (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
 189                         } else {
 190                                 /* look for DM6 AUX partition type in slot 1 */
 191                                 if (p->sys_ind == DM6_AUX1PARTITION
 192                                  || p->sys_ind == DM6_AUX3PARTITION)
 193                                 {
 194                                         (void)ide_xlate_1024(dev,0," [DM6:AUX]");
 195                                 }
 196                         }
 197                 }
 198         }
 199 #endif  /* CONFIG_BLK_DEV_IDE */
 200 
 201         current_minor += 4;  /* first "extra" minor (for extended partitions) */
 202         for (i=1 ; i<=4 ; minor++,i++,p++) {
 203                 if (!p->nr_sects)
 204                         continue;
 205                 add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects);
 206                 if ((current_minor & 0x3f) >= 60)
 207                         continue;
 208                 if (p->sys_ind == EXTENDED_PARTITION) {
 209                         printk(" <");
 210                         extended_partition(hd, (hd->major << 8) | minor);
 211                         printk(" >");
 212                 }
 213         }
 214         /*
 215          *  Check for old-style Disk Manager partition table
 216          */
 217         if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
 218                 p = (struct partition *) (0x1be + bh->b_data);
 219                 for (i = 4 ; i < 16 ; i++, current_minor++) {
 220                         p--;
 221                         if ((current_minor & mask) >= mask-2)
 222                                 break;
 223                         if (!(p->start_sect && p->nr_sects))
 224                                 continue;
 225                         add_partition(hd, current_minor, p->start_sect, p->nr_sects);
 226                 }
 227         }
 228         printk("\n");
 229         brelse(bh);
 230         return 1;
 231 }
 232 
 233 #endif /* CONFIG_MSDOS_PARTITION */
 234 
 235 #ifdef CONFIG_OSF_PARTITION
 236 
 237 static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239         int i;
 240         struct buffer_head *bh;
 241         struct disklabel {
 242                 u32 d_magic;
 243                 u16 d_type,d_subtype;
 244                 u8 d_typename[16];
 245                 u8 d_packname[16];
 246                 u32 d_secsize;
 247                 u32 d_nsectors;
 248                 u32 d_ntracks;
 249                 u32 d_ncylinders;
 250                 u32 d_secpercyl;
 251                 u32 d_secprtunit;
 252                 u16 d_sparespertrack;
 253                 u16 d_sparespercyl;
 254                 u32 d_acylinders;
 255                 u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
 256                 u32 d_headswitch, d_trkseek, d_flags;
 257                 u32 d_drivedata[5];
 258                 u32 d_spare[5];
 259                 u32 d_magic2;
 260                 u16 d_checksum;
 261                 u16 d_npartitions;
 262                 u32 d_bbsize, d_sbsize;
 263                 struct d_partition {
 264                         u32 p_size;
 265                         u32 p_offset;
 266                         u32 p_fsize;
 267                         u8  p_fstype;
 268                         u8  p_frag;
 269                         u16 p_cpg;
 270                 } d_partitions[8];
 271         } * label;
 272         struct d_partition * partition;
 273 #define DISKLABELMAGIC (0x82564557UL)
 274 
 275         if (!(bh = bread(dev,0,1024))) {
 276                 printk("unable to read partition table\n");
 277                 return -1;
 278         }
 279         label = (struct disklabel *) (bh->b_data+64);
 280         partition = label->d_partitions;
 281         if (label->d_magic != DISKLABELMAGIC) {
 282                 printk("magic: %08x\n", label->d_magic);
 283                 brelse(bh);
 284                 return 0;
 285         }
 286         if (label->d_magic2 != DISKLABELMAGIC) {
 287                 printk("magic2: %08x\n", label->d_magic2);
 288                 brelse(bh);
 289                 return 0;
 290         }
 291         for (i = 0 ; i < label->d_npartitions; i++, partition++) {
 292                 if (partition->p_size)
 293                         add_partition(hd, current_minor,
 294                                 first_sector+partition->p_offset,
 295                                 partition->p_size);
 296                 current_minor++;
 297         }
 298         printk("\n");
 299         brelse(bh);
 300         return 1;
 301 }
 302 
 303 #endif /* CONFIG_OSF_PARTITION */
 304 
 305 static void check_partition(struct gendisk *hd, unsigned int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         static int first_time = 1;
 308         unsigned long first_sector;
 309 
 310         if (first_time)
 311                 printk("Partition check:\n");
 312         first_time = 0;
 313         first_sector = hd->part[MINOR(dev)].start_sect;
 314 
 315         /*
 316          * This is a kludge to allow the partition check to be
 317          * skipped for specific drives (ie. IDE cd-rom drives)
 318          */
 319         if ((int)first_sector == -1) {
 320                 hd->part[MINOR(dev)].start_sect = 0;
 321                 return;
 322         }
 323 
 324         printk(" ");
 325         print_minor_name(hd, MINOR(dev));
 326 #ifdef CONFIG_MSDOS_PARTITION
 327         if (msdos_partition(hd, dev, first_sector))
 328                 return;
 329 #endif
 330 #ifdef CONFIG_OSF_PARTITION
 331         if (osf_partition(hd, dev, first_sector))
 332                 return;
 333 #endif
 334         printk(" unknown partition table\n");
 335 }
 336 
 337 /* This function is used to re-read partition tables for removable disks.
 338    Much of the cleanup from the old partition tables should have already been
 339    done */
 340 
 341 /* This function will re-read the partition tables for a given device,
 342 and set things back up again.  There are some important caveats,
 343 however.  You must ensure that no one is using the device, and no one
 344 can start using the device while this function is being executed. */
 345 
 346 void resetup_one_dev(struct gendisk *dev, int drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 347 {
 348         int i;
 349         int major       = dev->major << 8;
 350         int first_minor = drive << dev->minor_shift;
 351         int end_minor   = first_minor + dev->max_p;
 352 
 353         blk_size[dev->major] = NULL;
 354         current_minor = 1 + first_minor;
 355         check_partition(dev, major + first_minor);
 356 
 357         if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
 358                 for (i = first_minor; i < end_minor; i++)
 359                         dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 360                 blk_size[dev->major] = dev->sizes;
 361         }
 362 }
 363 
 364 static void setup_dev(struct gendisk *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366         int i, drive;
 367         int major       = dev->major << 8;
 368         int end_minor   = dev->max_nr * dev->max_p;
 369 
 370         blk_size[dev->major] = NULL;
 371         for (i = 0 ; i < end_minor; i++) {
 372                 dev->part[i].start_sect = 0;
 373                 dev->part[i].nr_sects = 0;
 374         }
 375         dev->init(dev); 
 376         for (drive = 0 ; drive < dev->nr_real ; drive++) {
 377                 int first_minor = drive << dev->minor_shift;
 378                 current_minor = 1 + first_minor;
 379                 check_partition(dev, major + first_minor);
 380         }
 381         if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
 382                 for (i = 0; i < end_minor; i++)
 383                         dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 384                 blk_size[dev->major] = dev->sizes;
 385         }
 386 }
 387         
 388 void device_setup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390         struct gendisk *p;
 391         int nr=0;
 392 
 393         for (p = gendisk_head ; p ; p=p->next) {
 394                 setup_dev(p);
 395                 nr += p->nr_real;
 396         }
 397                 
 398         if (ramdisk_size)
 399                 rd_load();
 400 }

/* [previous][next][first][last][top][bottom][index][help] */