root/arch/i386/i386/dkcsum.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dkcsumattach

    1 /*      $OpenBSD: dkcsum.c,v 1.21 2006/05/11 13:21:11 mickey Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1997 Niklas Hallqvist.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * A checksumming pseudo device used to get unique labels of each disk
   29  * that needs to be matched to BIOS disks.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/buf.h>
   34 #include <sys/conf.h>
   35 #include <sys/device.h>
   36 #include <sys/disklabel.h>
   37 #include <sys/fcntl.h>
   38 #include <sys/proc.h>
   39 #include <sys/reboot.h>
   40 #include <sys/stat.h>
   41 #include <sys/systm.h>
   42 
   43 #include <machine/biosvar.h>
   44 
   45 #include <lib/libz/zlib.h>
   46 
   47 dev_t dev_rawpart(struct device *);     /* XXX */
   48 
   49 extern u_int32_t bios_cksumlen;
   50 extern bios_diskinfo_t *bios_diskinfo;
   51 extern dev_t bootdev;
   52 
   53 void
   54 dkcsumattach(void)
   55 {
   56         struct device *dv;
   57         struct buf *bp;
   58         struct bdevsw *bdsw;
   59         dev_t dev, pribootdev, altbootdev;
   60         int error, picked;
   61         u_int32_t csum;
   62         bios_diskinfo_t *bdi, *hit;
   63 
   64         /* do nothing if no diskinfo passed from /boot, or a bad length */
   65         if (bios_diskinfo == NULL || bios_cksumlen * DEV_BSIZE > MAXBSIZE)
   66                 return;
   67 
   68 #ifdef DEBUG
   69         printf("dkcsum: bootdev=%#x\n", bootdev);
   70         for (bdi = bios_diskinfo; bdi->bios_number != -1; bdi++)
   71                 if (bdi->bios_number & 0x80)
   72                         printf("dkcsum: BIOS drive %#x checksum is %#x\n",
   73                             bdi->bios_number, bdi->checksum);
   74 #endif
   75         pribootdev = altbootdev = 0;
   76 
   77         /*
   78          * XXX What if DEV_BSIZE is changed to something else than the BIOS
   79          * blocksize?  Today, /boot doesn't cover that case so neither need
   80          * I care here.
   81          */
   82         bp = geteblk(bios_cksumlen * DEV_BSIZE);        /* XXX error check?  */
   83 
   84         TAILQ_FOREACH(dv, &alldevs, dv_list) {
   85                 if (dv->dv_class != DV_DISK)
   86                         continue;
   87                 bp->b_dev = dev = dev_rawpart(dv);
   88                 if (dev == NODEV)
   89                         continue;
   90                 bdsw = &bdevsw[major(dev)];
   91 
   92                 /*
   93                  * This open operation guarantees a proper initialization
   94                  * of the device, for future strategy calls.
   95                  */
   96                 error = (*bdsw->d_open)(dev, FREAD, S_IFCHR, curproc);
   97                 if (error) {
   98                         /* XXX What to do here? */
   99 #ifdef DEBUG
  100                         printf("dkcsum: %s open failed (%d)\n",
  101                             dv->dv_xname, error);
  102 #endif
  103                         continue;
  104                 }
  105 
  106                 /* Read blocks to cksum.  XXX maybe a d_read should be used. */
  107                 bp->b_blkno = 0;
  108                 bp->b_bcount = bios_cksumlen * DEV_BSIZE;
  109                 bp->b_flags = B_BUSY | B_READ;
  110                 bp->b_cylinder = 0;
  111                 (*bdsw->d_strategy)(bp);
  112                 if ((error = biowait(bp))) {
  113                         /* XXX What to do here? */
  114 #ifdef DEBUG
  115                         printf("dkcsum: %s read failed (%d)\n",
  116                             dv->dv_xname, error);
  117 #endif
  118                         error = (*bdsw->d_close)(dev, 0, S_IFCHR, curproc);
  119 #ifdef DEBUG
  120                         if (error)
  121                                 printf("dkcsum: %s close failed (%d)\n",
  122                                     dv->dv_xname, error);
  123 #endif
  124                         continue;
  125                 }
  126                 error = (*bdsw->d_close)(dev, FREAD, S_IFCHR, curproc);
  127                 if (error) {
  128                         /* XXX What to do here? */
  129 #ifdef DEBUG
  130                         printf("dkcsum: %s closed failed (%d)\n",
  131                             dv->dv_xname, error);
  132 #endif
  133                         continue;
  134                 }
  135 
  136                 csum = adler32(0, bp->b_data, bios_cksumlen * DEV_BSIZE);
  137 #ifdef DEBUG
  138                 printf("dkcsum: %s checksum is %#x\n", dv->dv_xname, csum);
  139 #endif
  140 
  141                 /* Find the BIOS device */
  142                 hit = 0;
  143                 for (bdi = bios_diskinfo; bdi->bios_number != -1; bdi++) {
  144                         /* Skip non-harddrives */
  145                         if (!(bdi->bios_number & 0x80))
  146                                 continue;
  147                         if (bdi->checksum != csum)
  148                                 continue;
  149                         picked = hit || (bdi->flags & BDI_PICKED);
  150                         if (!picked)
  151                                 hit = bdi;
  152                         printf("dkcsum: %s matches BIOS drive %#x%s\n",
  153                             dv->dv_xname, bdi->bios_number,
  154                             (picked ? " IGNORED" : ""));
  155                 }
  156 
  157                 /*
  158                  * If we have no hit, that's OK, we can see a lot more devices
  159                  * than the BIOS can, so this case is pretty normal.
  160                  */
  161                 if (!hit) {
  162 #ifdef DEBUG
  163                         printf("dkcsum: %s has no matching BIOS drive\n",
  164                             dv->dv_xname);
  165 #endif  
  166                         continue;
  167                 }
  168 
  169                 /*
  170                  * Fixup bootdev if units match.  This means that all of
  171                  * hd*, sd*, wd*, will be interpreted the same.  Not 100%
  172                  * backwards compatible, but sd* and wd* should be phased-
  173                  * out in the bootblocks.
  174                  */
  175 
  176                 /* B_TYPE dependent hd unit counting bootblocks */
  177                 if ((B_TYPE(bootdev) == B_TYPE(hit->bsd_dev)) &&
  178                     (B_UNIT(bootdev) == B_UNIT(hit->bsd_dev))) {
  179                         int type, ctrl, adap, part, unit;
  180 
  181                         type = major(bp->b_dev);
  182                         adap = B_ADAPTOR(bootdev);
  183                         ctrl = B_CONTROLLER(bootdev);
  184                         unit = DISKUNIT(bp->b_dev);
  185                         part = B_PARTITION(bootdev);
  186 
  187                         pribootdev = MAKEBOOTDEV(type, ctrl, adap, unit, part);
  188 #ifdef DEBUG
  189                         printf("dkcsum: %s is primary boot disk\n",
  190                             dv->dv_xname);
  191 #endif
  192                 }
  193                 /* B_TYPE independent hd unit counting bootblocks */
  194                 if (B_UNIT(bootdev) == (hit->bios_number & 0x7F)) {
  195                         int type, ctrl, adap, part, unit;
  196 
  197                         type = major(bp->b_dev);
  198                         adap = B_ADAPTOR(bootdev);
  199                         ctrl = B_CONTROLLER(bootdev);
  200                         unit = DISKUNIT(bp->b_dev);
  201                         part = B_PARTITION(bootdev);
  202 
  203                         altbootdev = MAKEBOOTDEV(type, ctrl, adap, unit, part);
  204 #ifdef DEBUG
  205                         printf("dkcsum: %s is alternate boot disk\n",
  206                             dv->dv_xname);
  207 #endif
  208                 }
  209 
  210                 /* This will overwrite /boot's guess, just so you remember */
  211                 hit->bsd_dev = MAKEBOOTDEV(major(bp->b_dev), 0, 0,
  212                     DISKUNIT(bp->b_dev), RAW_PART);
  213                 hit->flags |= BDI_PICKED;
  214         }
  215         bootdev = pribootdev ? pribootdev : altbootdev ? altbootdev : bootdev;
  216 
  217         bp->b_flags |= B_INVAL;
  218         brelse(bp);
  219 }

/* [<][>][^][v][top][bottom][index][help] */