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

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