root/drivers/block/genhd.c

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

DEFINITIONS

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

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