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

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