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, tested_for_dm6 = 0;
 117         struct buffer_head *bh;
 118         struct partition *p;
 119         int mask = (1 << hd->minor_shift) - 1;
 120 
 121 read_mbr:
 122         if (!(bh = bread(dev,0,1024))) {
 123                 printk(" unable to read partition table\n");
 124                 return -1;
 125         }
 126         if (*(unsigned short *)  (0x1fe + bh->b_data) != 0xAA55) {
 127                 brelse(bh);
 128                 return 0;
 129         }
 130         p = (struct partition *) (0x1be + bh->b_data);
 131 
 132 #ifdef CONFIG_BLK_DEV_IDE
 133         /*
 134          *  Check for Disk Manager v6.0x with geometry translation
 135          */
 136         if (!tested_for_dm6++) {        /* only check for DM6 *once* */
 137                 extern int ide_xlate_1024(dev_t, int, const char *);
 138                 /* check for DM6 with Dynamic Drive Overlay (DDO) */
 139                 if (p->sys_ind == DM6_PARTITION) {
 140                         /*
 141                          * Everything on the disk is offset by 63 sectors,
 142                          * including a "new" MBR with its own partition table,
 143                          * and the remainder of the disk must be accessed using
 144                          * a translated geometry that reduces the number of 
 145                          * apparent cylinders to less than 1024 if possible.
 146                          *
 147                          * ide_xlate_1024() will take care of the necessary
 148                          * adjustments to fool fdisk/LILO and partition check.
 149                          */
 150                         if (ide_xlate_1024(dev,1," [DM6:DDO]")) {
 151                                 bh->b_dirt = 0; /* force re-read of MBR block */
 152                                 bh->b_uptodate = 0;
 153                                 bh->b_req = 0;
 154                                 brelse(bh);
 155                                 goto read_mbr;  /* start over with new MBR */
 156                         }
 157                 } else {
 158                         /* look for DM6 signature in MBR, courtesy of OnTrack */
 159                         unsigned int sig = *(unsigned short *)(bh->b_data + 2);
 160                         if (sig <= 0x1ae
 161                          && *(unsigned short *)(bh->b_data + sig) == 0x55AA
 162                          && (1 & *(unsigned char *)(bh->b_data + sig + 2)) ) 
 163                         {
 164                                 (void)ide_xlate_1024(dev,0," [DM6:MBR]");
 165                         } else {
 166                                 /* look for DM6 AUX partition type in slot 1 */
 167                                 if (p->sys_ind == DM6_AUX1PARTITION
 168                                  || p->sys_ind == DM6_AUX3PARTITION)
 169                                 {
 170                                         (void)ide_xlate_1024(dev,0," [DM6:AUX]");
 171                                 }
 172                         }
 173                 }
 174         }
 175 #endif  /* CONFIG_BLK_DEV_IDE */
 176 
 177         current_minor += 4;  /* first "extra" minor (for extended partitions) */
 178         for (i=1 ; i<=4 ; minor++,i++,p++) {
 179                 if (!p->nr_sects)
 180                         continue;
 181                 add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects);
 182                 if ((current_minor & 0x3f) >= 60)
 183                         continue;
 184                 if (p->sys_ind == EXTENDED_PARTITION) {
 185                         printk(" <");
 186                         extended_partition(hd, (hd->major << 8) | minor);
 187                         printk(" >");
 188                 }
 189         }
 190         /*
 191          *  Check for old-style Disk Manager partition table
 192          */
 193         if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
 194                 p = (struct partition *) (0x1be + bh->b_data);
 195                 for (i = 4 ; i < 16 ; i++, current_minor++) {
 196                         p--;
 197                         if ((current_minor & mask) >= mask-2)
 198                                 break;
 199                         if (!(p->start_sect && p->nr_sects))
 200                                 continue;
 201                         add_partition(hd, current_minor, p->start_sect, p->nr_sects);
 202                 }
 203         }
 204         printk("\n");
 205         brelse(bh);
 206         return 1;
 207 }
 208 
 209 #endif /* CONFIG_MSDOS_PARTITION */
 210 
 211 #ifdef CONFIG_OSF_PARTITION
 212 
 213 static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         int i;
 216         struct buffer_head *bh;
 217         struct disklabel {
 218                 u32 d_magic;
 219                 u16 d_type,d_subtype;
 220                 u8 d_typename[16];
 221                 u8 d_packname[16];
 222                 u32 d_secsize;
 223                 u32 d_nsectors;
 224                 u32 d_ntracks;
 225                 u32 d_ncylinders;
 226                 u32 d_secpercyl;
 227                 u32 d_secprtunit;
 228                 u16 d_sparespertrack;
 229                 u16 d_sparespercyl;
 230                 u32 d_acylinders;
 231                 u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
 232                 u32 d_headswitch, d_trkseek, d_flags;
 233                 u32 d_drivedata[5];
 234                 u32 d_spare[5];
 235                 u32 d_magic2;
 236                 u16 d_checksum;
 237                 u16 d_npartitions;
 238                 u32 d_bbsize, d_sbsize;
 239                 struct d_partition {
 240                         u32 p_size;
 241                         u32 p_offset;
 242                         u32 p_fsize;
 243                         u8  p_fstype;
 244                         u8  p_frag;
 245                         u16 p_cpg;
 246                 } d_partitions[8];
 247         } * label;
 248         struct d_partition * partition;
 249 #define DISKLABELMAGIC (0x82564557UL)
 250 
 251         if (!(bh = bread(dev,0,1024))) {
 252                 printk("unable to read partition table\n");
 253                 return -1;
 254         }
 255         label = (struct disklabel *) (bh->b_data+64);
 256         partition = label->d_partitions;
 257         if (label->d_magic != DISKLABELMAGIC) {
 258                 printk("magic: %08x\n", label->d_magic);
 259                 brelse(bh);
 260                 return 0;
 261         }
 262         if (label->d_magic2 != DISKLABELMAGIC) {
 263                 printk("magic2: %08x\n", label->d_magic2);
 264                 brelse(bh);
 265                 return 0;
 266         }
 267         for (i = 0 ; i < label->d_npartitions; i++, partition++) {
 268                 if (partition->p_size)
 269                         add_partition(hd, current_minor,
 270                                 first_sector+partition->p_offset,
 271                                 partition->p_size);
 272                 current_minor++;
 273         }
 274         printk("\n");
 275         brelse(bh);
 276         return 1;
 277 }
 278 
 279 #endif /* CONFIG_OSF_PARTITION */
 280 
 281 static void check_partition(struct gendisk *hd, unsigned int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         static int first_time = 1;
 284         unsigned long first_sector;
 285 
 286         if (first_time)
 287                 printk("Partition check:\n");
 288         first_time = 0;
 289         first_sector = hd->part[MINOR(dev)].start_sect;
 290 
 291         /*
 292          * This is a kludge to allow the partition check to be
 293          * skipped for specific drives (ie. IDE cd-rom drives)
 294          */
 295         if ((int)first_sector == -1) {
 296                 hd->part[MINOR(dev)].start_sect = 0;
 297                 return;
 298         }
 299 
 300         printk("  %s%c:", hd->major_name, minor_name(hd, MINOR(dev)));
 301 #ifdef CONFIG_MSDOS_PARTITION
 302         if (msdos_partition(hd, dev, first_sector))
 303                 return;
 304 #endif
 305 #ifdef CONFIG_OSF_PARTITION
 306         if (osf_partition(hd, dev, first_sector))
 307                 return;
 308 #endif
 309         printk(" unknown partition table\n");
 310 }
 311 
 312 /* This function is used to re-read partition tables for removable disks.
 313    Much of the cleanup from the old partition tables should have already been
 314    done */
 315 
 316 /* This function will re-read the partition tables for a given device,
 317 and set things back up again.  There are some important caveats,
 318 however.  You must ensure that no one is using the device, and no one
 319 can start using the device while this function is being executed. */
 320 
 321 void resetup_one_dev(struct gendisk *dev, int drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 322 {
 323         int i;
 324         int start = drive<<dev->minor_shift;
 325         int j = start + dev->max_p;
 326         int major = dev->major << 8;
 327 
 328         current_minor = 1+(drive<<dev->minor_shift);
 329         check_partition(dev, major+(drive<<dev->minor_shift));
 330 
 331         for (i=start ; i < j ; i++)
 332                 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 333 }
 334 
 335 static void setup_dev(struct gendisk *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         int i;
 338         int j = dev->max_nr * dev->max_p;
 339         int major = dev->major << 8;
 340         int drive;
 341         
 342 
 343         for (i = 0 ; i < j; i++)  {
 344                 dev->part[i].start_sect = 0;
 345                 dev->part[i].nr_sects = 0;
 346         }
 347         dev->init();    
 348         for (drive=0 ; drive<dev->nr_real ; drive++) {
 349                 current_minor = 1+(drive<<dev->minor_shift);
 350                 check_partition(dev, major+(drive<<dev->minor_shift));
 351         }
 352         for (i=0 ; i < j ; i++)
 353                 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 354         blk_size[dev->major] = dev->sizes;
 355 }
 356         
 357 void device_setup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359         struct gendisk *p;
 360         int nr=0;
 361 
 362         for (p = gendisk_head ; p ; p=p->next) {
 363                 setup_dev(p);
 364                 nr += p->nr_real;
 365         }
 366                 
 367         if (ramdisk_size)
 368                 rd_load();
 369 }

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