The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/diskslice_machdep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1994 Bruce D. Evans.
    3  * All rights reserved.
    4  *
    5  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      from: @(#)ufs_disksubr.c        7.16 (Berkeley) 5/4/91
   37  *      from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
   38  * $FreeBSD$
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/buf.h>
   43 #include <sys/conf.h>
   44 #include <sys/disklabel.h>
   45 #define DOSPTYP_EXTENDED        5
   46 #define DOSPTYP_EXTENDEDX       15
   47 #define DOSPTYP_ONTRACK         84
   48 #include <sys/diskslice.h>
   49 #include <sys/malloc.h>
   50 #include <sys/syslog.h>
   51 #include <sys/systm.h>
   52 
   53 #define TRACE(str)      do { if (dsi_debug) printf str; } while (0)
   54 
   55 static volatile u_char dsi_debug;
   56 
   57 static struct dos_partition historical_bogus_partition_table[NDOSPART] = {
   58         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
   59         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
   60         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
   61         { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, },
   62 };
   63 
   64 static int check_part __P((char *sname, struct dos_partition *dp,
   65                            u_long offset, int nsectors, int ntracks,
   66                            u_long mbr_offset));
   67 static void extended __P((char *dname, dev_t dev, d_strategy_t *strat,
   68                           struct disklabel *lp, struct diskslices *ssp,
   69                           u_long ext_offset, u_long ext_size,
   70                           u_long base_ext_offset, int nsectors, int ntracks,
   71                           u_long mbr_offset));
   72 
   73 static int
   74 check_part(sname, dp, offset, nsectors, ntracks, mbr_offset )
   75         char    *sname;
   76         struct dos_partition *dp;
   77         u_long  offset;
   78         int     nsectors;
   79         int     ntracks;
   80         u_long  mbr_offset;
   81 {
   82         int     chs_ecyl;
   83         int     chs_esect;
   84         int     chs_scyl;
   85         int     chs_ssect;
   86         int     error;
   87         u_long  esector;
   88         u_long  esector1;
   89         u_long  secpercyl;
   90         u_long  ssector;
   91         u_long  ssector1;
   92 
   93         secpercyl = (u_long)nsectors * ntracks;
   94         chs_scyl = DPCYL(dp->dp_scyl, dp->dp_ssect);
   95         chs_ssect = DPSECT(dp->dp_ssect);
   96         ssector = chs_ssect - 1 + dp->dp_shd * nsectors + chs_scyl * secpercyl
   97                   + mbr_offset;
   98         ssector1 = offset + dp->dp_start;
   99 
  100         /*
  101          * If ssector1 is on a cylinder >= 1024, then ssector can't be right.
  102          * Allow the C/H/S for it to be 1023/ntracks-1/nsectors, or correct
  103          * apart from the cylinder being reduced modulo 1024.  Always allow
  104          * 1023/255/63.
  105          */
  106         if (ssector < ssector1
  107             && ((chs_ssect == nsectors && dp->dp_shd == ntracks - 1
  108                  && chs_scyl == 1023)
  109                 || (secpercyl != 0
  110                     && (ssector1 - ssector) % (1024 * secpercyl) == 0))
  111             || (dp->dp_scyl == 255 && dp->dp_shd == 255
  112                 && dp->dp_ssect == 255)) {
  113                 TRACE(("%s: C/H/S start %d/%d/%d, start %lu: allow\n",
  114                        sname, chs_scyl, dp->dp_shd, chs_ssect, ssector1));
  115                 ssector = ssector1;
  116         }
  117 
  118         chs_ecyl = DPCYL(dp->dp_ecyl, dp->dp_esect);
  119         chs_esect = DPSECT(dp->dp_esect);
  120         esector = chs_esect - 1 + dp->dp_ehd * nsectors + chs_ecyl * secpercyl
  121                   + mbr_offset;
  122         esector1 = ssector1 + dp->dp_size - 1;
  123 
  124         /* Allow certain bogus C/H/S values for esector, as above. */
  125         if (esector < esector1
  126             && ((chs_esect == nsectors && dp->dp_ehd == ntracks - 1
  127                  && chs_ecyl == 1023)
  128                 || (secpercyl != 0
  129                     && (esector1 - esector) % (1024 * secpercyl) == 0))
  130             || (dp->dp_ecyl == 255 && dp->dp_ehd == 255
  131                 && dp->dp_esect == 255)) {
  132                 TRACE(("%s: C/H/S end %d/%d/%d, end %lu: allow\n",
  133                        sname, chs_ecyl, dp->dp_ehd, chs_esect, esector1));
  134                 esector = esector1;
  135         }
  136 
  137         error = (ssector == ssector1 && esector == esector1) ? 0 : EINVAL;
  138         if (bootverbose)
  139                 printf("%s: type 0x%x, start %lu, end = %lu, size %lu %s\n",
  140                        sname, dp->dp_typ, ssector1, esector1,
  141                        (u_long)dp->dp_size, error ? "" : ": OK");
  142         if (ssector != ssector1 && bootverbose)
  143                 printf("%s: C/H/S start %d/%d/%d (%lu) != start %lu: invalid\n",
  144                        sname, chs_scyl, dp->dp_shd, chs_ssect,
  145                        ssector, ssector1);
  146         if (esector != esector1 && bootverbose)
  147                 printf("%s: C/H/S end %d/%d/%d (%lu) != end %lu: invalid\n",
  148                        sname, chs_ecyl, dp->dp_ehd, chs_esect,
  149                        esector, esector1);
  150         return (error);
  151 }
  152 
  153 int
  154 dsinit(dname, dev, strat, lp, sspp)
  155         char    *dname;
  156         dev_t   dev;
  157         d_strategy_t *strat;
  158         struct disklabel *lp;
  159         struct diskslices **sspp;
  160 {
  161         struct buf *bp;
  162         u_char  *cp;
  163         int     dospart;
  164         struct dos_partition *dp;
  165         struct dos_partition *dp0;
  166         int     error;
  167         int     max_ncyls;
  168         int     max_nsectors;
  169         int     max_ntracks;
  170         u_long  mbr_offset;
  171         char    partname[2];
  172         u_long  secpercyl;
  173         char    *sname;
  174         struct diskslice *sp;
  175         struct diskslices *ssp;
  176 
  177         mbr_offset = DOSBBSECTOR;
  178 reread_mbr:
  179         /* Read master boot record. */
  180         bp = geteblk((int)lp->d_secsize);
  181         bp->b_dev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART);
  182         bp->b_blkno = mbr_offset;
  183         bp->b_bcount = lp->d_secsize;
  184         bp->b_flags |= B_BUSY | B_READ;
  185         (*strat)(bp);
  186         if (biowait(bp) != 0) {
  187                 diskerr(bp, dname, "error reading primary partition table",
  188                     LOG_PRINTF, 0, (struct disklabel *)NULL);
  189                 printf("\n");
  190                 error = EIO;
  191                 goto done;
  192         }
  193 
  194         /* Weakly verify it. */
  195         cp = bp->b_data;
  196         sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
  197                        partname);
  198         if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
  199                 if (bootverbose)
  200                         printf("%s: invalid primary partition table: no magic\n",
  201                                sname);
  202                 error = EINVAL;
  203                 goto done;
  204         }
  205         dp0 = (struct dos_partition *)(cp + DOSPARTOFF);
  206 
  207         /* Check for "Ontrack Diskmanager". */
  208         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
  209                 if (dp->dp_typ == DOSPTYP_ONTRACK) {
  210                         if (bootverbose)
  211                                 printf(
  212             "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname);
  213                         bp->b_flags |= B_INVAL | B_AGE;
  214                         brelse(bp);
  215                         mbr_offset = 63;
  216                         goto reread_mbr;
  217                 }
  218         }
  219 
  220         if (bcmp(dp0, historical_bogus_partition_table,
  221                  sizeof historical_bogus_partition_table) == 0) {
  222                 TRACE(("%s: invalid primary partition table: historical\n",
  223                        sname));
  224                 error = EINVAL;
  225                 goto done;
  226         }
  227 
  228         /* Guess the geometry. */
  229         /*
  230          * TODO:
  231          * Perhaps skip entries with 0 size.
  232          * Perhaps only look at entries of type DOSPTYP_386BSD.
  233          */
  234         max_ncyls = 0;
  235         max_nsectors = 0;
  236         max_ntracks = 0;
  237         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
  238                 int     ncyls;
  239                 int     nsectors;
  240                 int     ntracks;
  241 
  242                 ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1;
  243                 if (max_ncyls < ncyls)
  244                         max_ncyls = ncyls;
  245                 nsectors = DPSECT(dp->dp_esect);
  246                 if (max_nsectors < nsectors)
  247                         max_nsectors = nsectors;
  248                 ntracks = dp->dp_ehd + 1;
  249                 if (max_ntracks < ntracks)
  250                         max_ntracks = ntracks;
  251         }
  252 
  253         /*
  254          * Check that we have guessed the geometry right by checking the
  255          * partition entries.
  256          */
  257         /*
  258          * TODO:
  259          * As above.
  260          * Check for overlaps.
  261          * Check against d_secperunit if the latter is reliable.
  262          */
  263         error = 0;
  264         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) {
  265                 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
  266                     && dp->dp_start == 0 && dp->dp_size == 0)
  267                         continue;
  268                 sname = dsname(dname, dkunit(dev), BASE_SLICE + dospart,
  269                                RAW_PART, partname);
  270 
  271                 /*
  272                  * Temporarily ignore errors from this check.  We could
  273                  * simplify things by accepting the table eariler if we
  274                  * always ignore errors here.  Perhaps we should always
  275                  * accept the table if the magic is right but not let
  276                  * bad entries affect the geometry.
  277                  */
  278                 check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks,
  279                            mbr_offset);
  280         }
  281         if (error != 0)
  282                 goto done;
  283 
  284         /*
  285          * Accept the DOS partition table.
  286          * First adjust the label (we have been careful not to change it
  287          * before we can guarantee success).
  288          */
  289         secpercyl = (u_long)max_nsectors * max_ntracks;
  290         if (secpercyl != 0) {
  291                 u_long  secperunit;
  292 
  293                 lp->d_nsectors = max_nsectors;
  294                 lp->d_ntracks = max_ntracks;
  295                 lp->d_secpercyl = secpercyl;
  296                 secperunit = secpercyl * max_ncyls;
  297                 if (lp->d_secperunit < secperunit)
  298                         lp->d_secperunit = secperunit;
  299                 lp->d_ncylinders = lp->d_secperunit / secpercyl;
  300         }
  301 
  302         /*
  303          * We are passed a pointer to a suitably initialized minimal
  304          * slices "struct" with no dangling pointers in it.  Replace it
  305          * by a maximal one.  This usually oversizes the "struct", but
  306          * enlarging it while searching for logical drives would be
  307          * inconvenient.
  308          */
  309         free(*sspp, M_DEVBUF);
  310         ssp = dsmakeslicestruct(MAX_SLICES, lp);
  311         *sspp = ssp;
  312 
  313         /* Initialize normal slices. */
  314         sp = &ssp->dss_slices[BASE_SLICE];
  315         for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) {
  316                 sp->ds_offset = mbr_offset + dp->dp_start;
  317                 sp->ds_size = dp->dp_size;
  318                 sp->ds_type = dp->dp_typ;
  319 #if 0
  320                 lp->d_subtype |= (lp->d_subtype & 3) | dospart
  321                                  | DSTYPE_INDOSPART;
  322 #endif
  323         }
  324         ssp->dss_nslices = BASE_SLICE + NDOSPART;
  325 
  326         /* Handle extended partitions. */
  327         sp -= NDOSPART;
  328         for (dospart = 0; dospart < NDOSPART; dospart++, sp++)
  329                 if (sp->ds_type == DOSPTYP_EXTENDED || 
  330                     sp->ds_type == DOSPTYP_EXTENDEDX)
  331                         extended(dname, bp->b_dev, strat, lp, ssp,
  332                                  sp->ds_offset, sp->ds_size, sp->ds_offset,
  333                                  max_nsectors, max_ntracks, mbr_offset);
  334 
  335 done:
  336         bp->b_flags |= B_INVAL | B_AGE;
  337         brelse(bp);
  338         if (error == EINVAL)
  339                 error = 0;
  340         return (error);
  341 }
  342 
  343 void
  344 extended(dname, dev, strat, lp, ssp, ext_offset, ext_size, base_ext_offset,
  345          nsectors, ntracks, mbr_offset)
  346         char    *dname;
  347         dev_t   dev;
  348         struct disklabel *lp;
  349         d_strategy_t *strat;
  350         struct diskslices *ssp;
  351         u_long  ext_offset;
  352         u_long  ext_size;
  353         u_long  base_ext_offset;
  354         int     nsectors;
  355         int     ntracks;
  356         u_long  mbr_offset;
  357 {
  358         struct buf *bp;
  359         u_char  *cp;
  360         int     dospart;
  361         struct dos_partition *dp;
  362         u_long  ext_offsets[NDOSPART];
  363         u_long  ext_sizes[NDOSPART];
  364         char    partname[2];
  365         int     slice;
  366         char    *sname;
  367         struct diskslice *sp;
  368 
  369         /* Read extended boot record. */
  370         bp = geteblk((int)lp->d_secsize);
  371         bp->b_dev = dev;
  372         bp->b_blkno = ext_offset;
  373         bp->b_bcount = lp->d_secsize;
  374         bp->b_flags |= B_BUSY | B_READ;
  375         (*strat)(bp);
  376         if (biowait(bp) != 0) {
  377                 diskerr(bp, dname, "error reading extended partition table",
  378                     LOG_PRINTF, 0, (struct disklabel *)NULL);
  379                 printf("\n");
  380                 goto done;
  381         }
  382 
  383         /* Weakly verify it. */
  384         cp = bp->b_data;
  385         if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
  386                 sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, RAW_PART,
  387                                partname);
  388                 if (bootverbose)
  389                         printf("%s: invalid extended partition table: no magic\n",
  390                                sname);
  391                 goto done;
  392         }
  393 
  394         for (dospart = 0,
  395              dp = (struct dos_partition *)(bp->b_data + DOSPARTOFF),
  396              slice = ssp->dss_nslices, sp = &ssp->dss_slices[slice];
  397              dospart < NDOSPART; dospart++, dp++) {
  398                 ext_sizes[dospart] = 0;
  399                 if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0
  400                     && dp->dp_start == 0 && dp->dp_size == 0)
  401                         continue;
  402                 if (dp->dp_typ == DOSPTYP_EXTENDED || 
  403                     dp->dp_typ == DOSPTYP_EXTENDEDX) {
  404                         char buf[32];
  405 
  406                         sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE,
  407                                        RAW_PART, partname);
  408                         snprintf(buf, sizeof(buf), "%s", sname);
  409                         if (strlen(buf) < sizeof buf - 11)
  410                                 strcat(buf, "<extended>");
  411                         check_part(buf, dp, base_ext_offset, nsectors,
  412                                    ntracks, mbr_offset);
  413                         ext_offsets[dospart] = base_ext_offset + dp->dp_start;
  414                         ext_sizes[dospart] = dp->dp_size;
  415                 } else {
  416                         sname = dsname(dname, dkunit(dev), slice, RAW_PART,
  417                                        partname);
  418                         check_part(sname, dp, ext_offset, nsectors, ntracks,
  419                                    mbr_offset);
  420                         if (slice >= MAX_SLICES) {
  421                                 printf("%s: too many slices\n", sname);
  422                                 slice++;
  423                                 continue;
  424                         }
  425                         sp->ds_offset = ext_offset + dp->dp_start;
  426                         sp->ds_size = dp->dp_size;
  427                         sp->ds_type = dp->dp_typ;
  428                         ssp->dss_nslices++;
  429                         slice++;
  430                         sp++;
  431                 }
  432         }
  433 
  434         /* If we found any more slices, recursively find all the subslices. */
  435         for (dospart = 0; dospart < NDOSPART; dospart++)
  436                 if (ext_sizes[dospart] != 0)
  437                         extended(dname, dev, strat, lp, ssp,
  438                                  ext_offsets[dospart], ext_sizes[dospart],
  439                                  base_ext_offset, nsectors, ntracks,
  440                                  mbr_offset);
  441 
  442 done:
  443         bp->b_flags |= B_INVAL | B_AGE;
  444         brelse(bp);
  445 }

Cache object: 1688bfdd32f7565b3dff7b808c43fd6e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.