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

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