root/drivers/block/genhd.c

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

DEFINITIONS

This source file includes following definitions.
  1. disk_name
  2. add_partition
  3. is_extended_partition
  4. extended_partition
  5. msdos_partition
  6. osf_partition
  7. sun_partition
  8. check_partition
  9. resetup_one_dev
  10. setup_dev
  11. device_setup

   1 /*
   2  *  Code extracted from
   3  *  linux/kernel/hd.c
   4  *
   5  *  Copyright (C) 1991, 1992  Linus Torvalds
   6  *
   7  *
   8  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
   9  *  in the early extended-partition checks and added DM partitions
  10  *
  11  *  Support for DiskManager v6.0x added by Mark Lord,
  12  *  with information provided by OnTrack.  This now works for linux fdisk
  13  *  and LILO, as well as loadlin and bootln.  Note that disks other than
  14  *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  15  *
  16  *  More flexible handling of extended partitions - aeb, 950831
  17  *
  18  *  Check partition table on IDE disks for common CHS translations
  19  */
  20 
  21 #include <linux/config.h>
  22 #include <linux/fs.h>
  23 #include <linux/genhd.h>
  24 #include <linux/kernel.h>
  25 #include <linux/major.h>
  26 #include <linux/string.h>
  27 
  28 #include <asm/system.h>
  29 
  30 #ifdef __alpha__
  31 /*
  32  * On the Alpha, we get unaligned access exceptions on
  33  *  p->nr_sects and p->start_sect, when the partition table
  34  *  is not on a 4-byte boundary, which is frequently the case.
  35  * This code uses unaligned load instructions to prevent
  36  *  such exceptions.
  37  */
  38 #include <asm/unaligned.h>
  39 #define NR_SECTS(p)     ldl_u(&p->nr_sects)
  40 #define START_SECT(p)   ldl_u(&p->start_sect)
  41 #else /* __alpha__ */
  42 #define NR_SECTS(p)     p->nr_sects
  43 #define START_SECT(p)   p->start_sect
  44 #endif /* __alpha__ */
  45 
  46 struct gendisk *gendisk_head = NULL;
  47 
  48 static int current_minor = 0;
  49 extern int *blk_size[];
  50 extern void rd_load(void);
  51 
  52 extern int chr_dev_init(void);
  53 extern int blk_dev_init(void);
  54 extern int scsi_dev_init(void);
  55 extern int net_dev_init(void);
  56 
  57 /*
  58  * disk_name() is used by genhd.c and md.c.
  59  * It formats the devicename of the indicated disk
  60  * into the supplied buffer, and returns a pointer
  61  * to that same buffer (for convenience).
  62  */
  63 char *disk_name (struct gendisk *hd, int minor, char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         unsigned int part;
  66         const char *maj = hd->major_name;
  67         char unit = (minor >> hd->minor_shift) + 'a';
  68 
  69 #ifdef CONFIG_BLK_DEV_IDE
  70         /*
  71          * IDE devices use multiple major numbers, but the drives
  72          * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
  73          * This requires special handling here.
  74          */
  75         switch (hd->major) {
  76                 case IDE3_MAJOR:
  77                         unit += 2;
  78                 case IDE2_MAJOR:
  79                         unit += 2;
  80                 case IDE1_MAJOR:
  81                         unit += 2;
  82                 case IDE0_MAJOR:
  83                         maj = "hd";
  84         }
  85 #endif
  86         part = minor & ((1 << hd->minor_shift) - 1);
  87         if (part)
  88                 sprintf(buf, "%s%c%d", maj, unit, part);
  89         else
  90                 sprintf(buf, "%s%c", maj, unit);
  91         return buf;
  92 }
  93 
  94 static void add_partition (struct gendisk *hd, int minor, int start, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         char buf[8];
  97         hd->part[minor].start_sect = start;
  98         hd->part[minor].nr_sects   = size;
  99         printk(" %s", disk_name(hd, minor, buf));
 100 }
 101 
 102 static inline int is_extended_partition(struct partition *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         return (p->sys_ind == DOS_EXTENDED_PARTITION ||
 105                 p->sys_ind == LINUX_EXTENDED_PARTITION);
 106 }
 107 
 108 #ifdef CONFIG_MSDOS_PARTITION
 109 /*
 110  * Create devices for each logical partition in an extended partition.
 111  * The logical partitions form a linked list, with each entry being
 112  * a partition table with two entries.  The first entry
 113  * is the real data partition (with a start relative to the partition
 114  * table start).  The second is a pointer to the next logical partition
 115  * (with a start relative to the entire extended partition).
 116  * We do not create a Linux partition for the partition tables, but
 117  * only for the actual data partitions.
 118  */
 119 
 120 static void extended_partition(struct gendisk *hd, kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         struct buffer_head *bh;
 123         struct partition *p;
 124         unsigned long first_sector, first_size, this_sector, this_size;
 125         int mask = (1 << hd->minor_shift) - 1;
 126         int i;
 127 
 128         first_sector = hd->part[MINOR(dev)].start_sect;
 129         first_size = hd->part[MINOR(dev)].nr_sects;
 130         this_sector = first_sector;
 131 
 132         while (1) {
 133                 if ((current_minor & mask) == 0)
 134                         return;
 135                 if (!(bh = bread(dev,0,1024)))
 136                         return;
 137           /*
 138            * This block is from a device that we're about to stomp on.
 139            * So make sure nobody thinks this block is usable.
 140            */
 141                 bh->b_state = 0;
 142 
 143                 if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
 144                         goto done;
 145 
 146                 p = (struct partition *) (0x1BE + bh->b_data);
 147 
 148                 this_size = hd->part[MINOR(dev)].nr_sects;
 149 
 150                 /*
 151                  * Usually, the first entry is the real data partition,
 152                  * the 2nd entry is the next extended partition, or empty,
 153                  * and the 3rd and 4th entries are unused.
 154                  * However, DRDOS sometimes has the extended partition as
 155                  * the first entry (when the data partition is empty),
 156                  * and OS/2 seems to use all four entries.
 157                  */
 158 
 159                 /* 
 160                  * First process the data partition(s)
 161                  */
 162                 for (i=0; i<4; i++, p++) {
 163                     if (!NR_SECTS(p) || is_extended_partition(p))
 164                       continue;
 165 
 166                     /* Check the 3rd and 4th entries -
 167                        these sometimes contain random garbage */
 168                     if (i >= 2
 169                         && START_SECT(p) + NR_SECTS(p) > this_size
 170                         && (this_sector + START_SECT(p) < first_sector ||
 171                             this_sector + START_SECT(p) + NR_SECTS(p) >
 172                              first_sector + first_size))
 173                       continue;
 174 
 175                     add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p));
 176                     current_minor++;
 177                     if ((current_minor & mask) == 0)
 178                       goto done;
 179                 }
 180                 /*
 181                  * Next, process the (first) extended partition, if present.
 182                  * (So far, there seems to be no reason to make
 183                  *  extended_partition()  recursive and allow a tree
 184                  *  of extended partitions.)
 185                  * It should be a link to the next logical partition.
 186                  * Create a minor for this just long enough to get the next
 187                  * partition table.  The minor will be reused for the next
 188                  * data partition.
 189                  */
 190                 p -= 4;
 191                 for (i=0; i<4; i++, p++)
 192                   if(NR_SECTS(p) && is_extended_partition(p))
 193                     break;
 194                 if (i == 4)
 195                   goto done;     /* nothing left to do */
 196 
 197                 hd->part[current_minor].nr_sects = NR_SECTS(p);
 198                 hd->part[current_minor].start_sect = first_sector + START_SECT(p);
 199                 this_sector = first_sector + START_SECT(p);
 200                 dev = MKDEV(hd->major, current_minor);
 201                 brelse(bh);
 202         }
 203 done:
 204         brelse(bh);
 205 }
 206 
 207 static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209         int i, minor = current_minor;
 210         struct buffer_head *bh;
 211         struct partition *p;
 212         unsigned char *data;
 213         int mask = (1 << hd->minor_shift) - 1;
 214 #ifdef CONFIG_BLK_DEV_IDE
 215         int tested_for_xlate = 0;
 216 
 217 read_mbr:
 218 #endif
 219         if (!(bh = bread(dev,0,1024))) {
 220                 printk(" unable to read partition table\n");
 221                 return -1;
 222         }
 223         data = bh->b_data;
 224         /* In some cases we modify the geometry    */
 225         /*  of the drive (below), so ensure that   */
 226         /*  nobody else tries to re-use this data. */
 227         bh->b_state = 0;
 228 #ifdef CONFIG_BLK_DEV_IDE
 229 check_table:
 230 #endif
 231         if (*(unsigned short *)  (0x1fe + data) != 0xAA55) {
 232                 brelse(bh);
 233                 return 0;
 234         }
 235         p = (struct partition *) (0x1be + data);
 236 
 237 #ifdef CONFIG_BLK_DEV_IDE
 238         if (!tested_for_xlate++) {      /* Do this only once per disk */
 239                 /*
 240                  * Look for various forms of IDE disk geometry translation
 241                  */
 242                 extern int ide_xlate_1024(kdev_t, int, const char *);
 243                 unsigned int sig = *(unsigned short *)(data + 2);
 244                 if (p->sys_ind == EZD_PARTITION) {
 245                         /*
 246                          * The remainder of the disk must be accessed using
 247                          * a translated geometry that reduces the number of 
 248                          * apparent cylinders to less than 1024 if possible.
 249                          *
 250                          * ide_xlate_1024() will take care of the necessary
 251                          * adjustments to fool fdisk/LILO and partition check.
 252                          */
 253                         if (ide_xlate_1024(dev, -1, " [EZD]")) {
 254                                 data += 512;
 255                                 goto check_table;
 256                         }
 257                 } else if (p->sys_ind == DM6_PARTITION) {
 258 
 259                         /*
 260                          * Everything on the disk is offset by 63 sectors,
 261                          * including a "new" MBR with its own partition table,
 262                          * and the remainder of the disk must be accessed using
 263                          * a translated geometry that reduces the number of 
 264                          * apparent cylinders to less than 1024 if possible.
 265                          *
 266                          * ide_xlate_1024() will take care of the necessary
 267                          * adjustments to fool fdisk/LILO and partition check.
 268                          */
 269                         if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
 270                                 brelse(bh);
 271                                 goto read_mbr;  /* start over with new MBR */
 272                         }
 273                 } else if (sig <= 0x1ae && *(unsigned short *)(data + sig) == 0x55AA
 274                          && (1 & *(unsigned char *)(data + sig + 2)) ) 
 275                 {
 276                         /*
 277                          * DM6 signature in MBR, courtesy of OnTrack
 278                          */
 279                         (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
 280                 } else if (p->sys_ind == DM6_AUX1PARTITION || p->sys_ind == DM6_AUX3PARTITION) {
 281                         /*
 282                          * DM6 on other than the first (boot) drive
 283                          */
 284                         (void) ide_xlate_1024(dev, 0, " [DM6:AUX]");
 285                 } else {
 286                         /*
 287                          * Examine the partition table for common translations.
 288                          * This is necessary for drives for situations where
 289                          * the translated geometry is unavailable from the BIOS.
 290                          */
 291                         for (i = 0; i < 4 ; i++) {
 292                                 struct partition *q = &p[i];
 293                                 if (NR_SECTS(q) && q->sector == 1 && q->end_sector == 63) {
 294                                         unsigned int heads = q->end_head + 1;
 295                                         if (heads == 32 || heads == 64 || heads == 128) {
 296 
 297                                                 (void) ide_xlate_1024(dev, heads, " [PTBL]");
 298                                                 break;
 299                                         }
 300                                 }
 301                         }
 302                 }
 303         }
 304 #endif  /* CONFIG_BLK_DEV_IDE */
 305 
 306         current_minor += 4;  /* first "extra" minor (for extended partitions) */
 307         for (i=1 ; i<=4 ; minor++,i++,p++) {
 308                 if (!NR_SECTS(p))
 309                         continue;
 310                 add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
 311                 if (is_extended_partition(p)) {
 312                         printk(" <");
 313                         /*
 314                          * If we are rereading the partition table, we need
 315                          * to set the size of the partition so that we will
 316                          * be able to bread the block containing the extended
 317                          * partition info.
 318                          */
 319                         hd->sizes[minor] = hd->part[minor].nr_sects 
 320                                 >> (BLOCK_SIZE_BITS - 9);
 321                         extended_partition(hd, MKDEV(hd->major, minor));
 322                         printk(" >");
 323                         /* prevent someone doing mkfs or mkswap on an
 324                            extended partition, but leave room for LILO */
 325                         if (hd->part[minor].nr_sects > 2)
 326                                 hd->part[minor].nr_sects = 2;
 327                 }
 328         }
 329         /*
 330          *  Check for old-style Disk Manager partition table
 331          */
 332         if (*(unsigned short *) (data+0xfc) == 0x55AA) {
 333                 p = (struct partition *) (0x1be + data);
 334                 for (i = 4 ; i < 16 ; i++, current_minor++) {
 335                         p--;
 336                         if ((current_minor & mask) == 0)
 337                                 break;
 338                         if (!(START_SECT(p) && NR_SECTS(p)))
 339                                 continue;
 340                         add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
 341                 }
 342         }
 343         printk("\n");
 344         brelse(bh);
 345         return 1;
 346 }
 347 
 348 #endif /* CONFIG_MSDOS_PARTITION */
 349 
 350 #ifdef CONFIG_OSF_PARTITION
 351 
 352 static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354         int i;
 355         int mask = (1 << hd->minor_shift) - 1;
 356         struct buffer_head *bh;
 357         struct disklabel {
 358                 u32 d_magic;
 359                 u16 d_type,d_subtype;
 360                 u8 d_typename[16];
 361                 u8 d_packname[16];
 362                 u32 d_secsize;
 363                 u32 d_nsectors;
 364                 u32 d_ntracks;
 365                 u32 d_ncylinders;
 366                 u32 d_secpercyl;
 367                 u32 d_secprtunit;
 368                 u16 d_sparespertrack;
 369                 u16 d_sparespercyl;
 370                 u32 d_acylinders;
 371                 u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
 372                 u32 d_headswitch, d_trkseek, d_flags;
 373                 u32 d_drivedata[5];
 374                 u32 d_spare[5];
 375                 u32 d_magic2;
 376                 u16 d_checksum;
 377                 u16 d_npartitions;
 378                 u32 d_bbsize, d_sbsize;
 379                 struct d_partition {
 380                         u32 p_size;
 381                         u32 p_offset;
 382                         u32 p_fsize;
 383                         u8  p_fstype;
 384                         u8  p_frag;
 385                         u16 p_cpg;
 386                 } d_partitions[8];
 387         } * label;
 388         struct d_partition * partition;
 389 #define DISKLABELMAGIC (0x82564557UL)
 390 
 391         if (!(bh = bread(dev,0,1024))) {
 392                 printk("unable to read partition table\n");
 393                 return -1;
 394         }
 395         label = (struct disklabel *) (bh->b_data+64);
 396         partition = label->d_partitions;
 397         if (label->d_magic != DISKLABELMAGIC) {
 398                 printk("magic: %08x\n", label->d_magic);
 399                 brelse(bh);
 400                 return 0;
 401         }
 402         if (label->d_magic2 != DISKLABELMAGIC) {
 403                 printk("magic2: %08x\n", label->d_magic2);
 404                 brelse(bh);
 405                 return 0;
 406         }
 407         for (i = 0 ; i < label->d_npartitions; i++, partition++) {
 408                 if ((current_minor & mask) == 0)
 409                         break;
 410                 if (partition->p_size)
 411                         add_partition(hd, current_minor,
 412                                 first_sector+partition->p_offset,
 413                                 partition->p_size);
 414                 current_minor++;
 415         }
 416         printk("\n");
 417         brelse(bh);
 418         return 1;
 419 }
 420 
 421 #endif /* CONFIG_OSF_PARTITION */
 422 
 423 #ifdef CONFIG_SUN_PARTITION
 424 
 425 static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         int i, csum;
 428         unsigned short *ush;
 429         struct buffer_head *bh;
 430         struct sun_disklabel {
 431                 unsigned char info[128];   /* Informative text string */
 432                 unsigned char spare[292];  /* Boot information etc. */
 433                 unsigned short rspeed;     /* Disk rotational speed */
 434                 unsigned short pcylcount;  /* Physical cylinder count */
 435                 unsigned short sparecyl;   /* extra sects per cylinder */
 436                 unsigned char spare2[4];   /* More magic... */
 437                 unsigned short ilfact;     /* Interleave factor */
 438                 unsigned short ncyl;       /* Data cylinder count */
 439                 unsigned short nacyl;      /* Alt. cylinder count */
 440                 unsigned short ntrks;      /* Tracks per cylinder */
 441                 unsigned short nsect;      /* Sectors per track */
 442                 unsigned char spare3[4];   /* Even more magic... */
 443                 struct sun_partition {
 444                         unsigned long start_cylinder;
 445                         unsigned long num_sectors;
 446                 } partitions[8];
 447                 unsigned short magic;      /* Magic number */
 448                 unsigned short csum;       /* Label xor'd checksum */
 449         } * label;              
 450         struct sun_partition *p;
 451         unsigned long spc;
 452 #define SUN_LABEL_MAGIC  0xDABE
 453 
 454         if(!(bh = bread(dev, 0, 1024))) {
 455                 printk("Dev %d: unable to read partition table\n", dev);
 456                 return -1;
 457         }
 458         label = (struct sun_disklabel *) bh->b_data;
 459         p = label->partitions;
 460         if(label->magic != SUN_LABEL_MAGIC) {
 461                 printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic);
 462                 brelse(bh);
 463                 return 0;
 464         }
 465         /* Look at the checksum */
 466         ush = ((unsigned short *) (label+1)) - 1;
 467         for(csum = 0; ush >= ((unsigned short *) label);)
 468                 csum ^= *ush--;
 469         if(csum) {
 470                 printk("Dev %d Sun disklabel: Csum bad, label corrupted\n", dev);
 471                 brelse(bh);
 472                 return 0;
 473         }
 474         /* All Sun disks have 8 partition entries */
 475         spc = (label->ntrks * label->nsect);
 476         for(i=0; i < 8; i++, p++) {
 477                 unsigned long st_sector;
 478 
 479                 /* We register all partitions, even if zero size, so that
 480                  * the minor numbers end up ok as per SunOS interpretation.
 481                  */
 482                 st_sector = first_sector + (p->start_cylinder * spc);
 483                 add_partition(hd, current_minor, st_sector, p->num_sectors);
 484                 current_minor++;
 485         }
 486         printk("\n");
 487         brelse(bh);
 488         return 1;
 489 }
 490 
 491 #endif /* CONFIG_SUN_PARTITION */
 492 
 493 static void check_partition(struct gendisk *hd, kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495         static int first_time = 1;
 496         unsigned long first_sector;
 497         char buf[8];
 498 
 499         if (first_time)
 500                 printk("Partition check:\n");
 501         first_time = 0;
 502         first_sector = hd->part[MINOR(dev)].start_sect;
 503 
 504         /*
 505          * This is a kludge to allow the partition check to be
 506          * skipped for specific drives (e.g. IDE cd-rom drives)
 507          */
 508         if ((int)first_sector == -1) {
 509                 hd->part[MINOR(dev)].start_sect = 0;
 510                 return;
 511         }
 512 
 513         printk(" %s:", disk_name(hd, MINOR(dev), buf));
 514 #ifdef CONFIG_MSDOS_PARTITION
 515         if (msdos_partition(hd, dev, first_sector))
 516                 return;
 517 #endif
 518 #ifdef CONFIG_OSF_PARTITION
 519         if (osf_partition(hd, dev, first_sector))
 520                 return;
 521 #endif
 522 #ifdef CONFIG_SUN_PARTITION
 523         if(sun_partition(hd, dev, first_sector))
 524                 return;
 525 #endif
 526         printk(" unknown partition table\n");
 527 }
 528 
 529 /* This function is used to re-read partition tables for removable disks.
 530    Much of the cleanup from the old partition tables should have already been
 531    done */
 532 
 533 /* This function will re-read the partition tables for a given device,
 534 and set things back up again.  There are some important caveats,
 535 however.  You must ensure that no one is using the device, and no one
 536 can start using the device while this function is being executed. */
 537 
 538 void resetup_one_dev(struct gendisk *dev, int drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 539 {
 540         int i;
 541         int first_minor = drive << dev->minor_shift;
 542         int end_minor   = first_minor + dev->max_p;
 543 
 544         blk_size[dev->major] = NULL;
 545         current_minor = 1 + first_minor;
 546         check_partition(dev, MKDEV(dev->major, first_minor));
 547 
 548         /*
 549          * We need to set the sizes array before we will be able to access
 550          * any of the partitions on this device.
 551          */
 552         if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
 553                 for (i = first_minor; i < end_minor; i++)
 554                         dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 555                 blk_size[dev->major] = dev->sizes;
 556         }
 557 }
 558 
 559 static void setup_dev(struct gendisk *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 560 {
 561         int i, drive;
 562         int end_minor   = dev->max_nr * dev->max_p;
 563 
 564         blk_size[dev->major] = NULL;
 565         for (i = 0 ; i < end_minor; i++) {
 566                 dev->part[i].start_sect = 0;
 567                 dev->part[i].nr_sects = 0;
 568         }
 569         dev->init(dev); 
 570         for (drive = 0 ; drive < dev->nr_real ; drive++) {
 571                 int first_minor = drive << dev->minor_shift;
 572                 current_minor = 1 + first_minor;
 573                 check_partition(dev, MKDEV(dev->major, first_minor));
 574         }
 575         if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
 576                 for (i = 0; i < end_minor; i++)
 577                         dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 578                 blk_size[dev->major] = dev->sizes;
 579         }
 580 }
 581 
 582 void device_setup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584         extern void console_map_init(void);
 585         struct gendisk *p;
 586         int nr=0;
 587 
 588         chr_dev_init();
 589         blk_dev_init();
 590         sti();
 591 #ifdef CONFIG_SCSI
 592         scsi_dev_init();
 593 #endif
 594 #ifdef CONFIG_INET
 595         net_dev_init();
 596 #endif
 597         console_map_init();
 598 
 599         for (p = gendisk_head ; p ; p=p->next) {
 600                 setup_dev(p);
 601                 nr += p->nr_real;
 602         }
 603 #ifdef CONFIG_BLK_DEV_RAM
 604         rd_load();
 605 #endif
 606 }

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