root/arch/i386/stand/libsa/diskprobe.c

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

DEFINITIONS

This source file includes following definitions.
  1. floppyprobe
  2. hardprobe
  3. diskprobe
  4. cdprobe
  5. dklookup
  6. dump_diskinfo
  7. bios_dklookup
  8. disksum

    1 /*      $OpenBSD: diskprobe.c,v 1.29 2007/06/18 22:11:20 krw Exp $      */
    2 
    3 /*
    4  * Copyright (c) 1997 Tobias Weingartner
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 /* We want the disk type names from disklabel.h */
   31 #undef DKTYPENAMES
   32 
   33 #include <sys/param.h>
   34 #include <sys/queue.h>
   35 #include <sys/reboot.h>
   36 #include <sys/disklabel.h>
   37 #include <stand/boot/bootarg.h>
   38 #include <machine/biosvar.h>
   39 #include <lib/libz/zlib.h>
   40 #include "disk.h"
   41 #include "biosdev.h"
   42 #include "libsa.h"
   43 
   44 #define MAX_CKSUMLEN MAXBSIZE / DEV_BSIZE       /* Max # of blks to cksum */
   45 
   46 /* Local Prototypes */
   47 static int disksum(int);
   48 
   49 /* List of disk devices we found/probed */
   50 struct disklist_lh disklist;
   51 
   52 /* Pointer to boot device */
   53 struct diskinfo *bootdev_dip;
   54 
   55 extern int debug;
   56 extern int bios_bootdev;
   57 extern int bios_cddev;
   58 
   59 /* Probe for all BIOS floppies */
   60 static void
   61 floppyprobe(void)
   62 {
   63         struct diskinfo *dip;
   64         int i;
   65 
   66         /* Floppies */
   67         for (i = 0; i < 4; i++) {
   68                 dip = alloc(sizeof(struct diskinfo));
   69                 bzero(dip, sizeof(*dip));
   70 
   71                 if (bios_getdiskinfo(i, &dip->bios_info)) {
   72 #ifdef BIOS_DEBUG
   73                         if (debug)
   74                                 printf(" <!fd%u>", i);
   75 #endif
   76                         free(dip, 0);
   77                         break;
   78                 }
   79 
   80                 printf(" fd%u", i);
   81 
   82                 /* Fill out best we can - (fd?) */
   83                 dip->bios_info.bsd_dev = MAKEBOOTDEV(2, 0, 0, i, RAW_PART);
   84 
   85                 /*
   86                  * Delay reading the disklabel until we're sure we want
   87                  * to boot from the floppy. Doing this avoids a delay
   88                  * (sometimes very long) when trying to read the label
   89                  * and the drive is unplugged.
   90                  */
   91                 dip->bios_info.flags |= BDI_BADLABEL;
   92 
   93                 /* Add to queue of disks */
   94                 TAILQ_INSERT_TAIL(&disklist, dip, list);
   95         }
   96 }
   97 
   98 
   99 /* Probe for all BIOS hard disks */
  100 static void
  101 hardprobe(void)
  102 {
  103         struct diskinfo *dip;
  104         int i;
  105         u_int bsdunit, type;
  106         u_int scsi = 0, ide = 0;
  107         const char *dc = (const char *)((0x40 << 4) + 0x75);
  108 
  109         /* Hard disks */
  110         for (i = 0x80; i < (0x80 + *dc); i++) {
  111                 dip = alloc(sizeof(struct diskinfo));
  112                 bzero(dip, sizeof(*dip));
  113 
  114                 if (bios_getdiskinfo(i, &dip->bios_info)) {
  115 #ifdef BIOS_DEBUG
  116                         if (debug)
  117                                 printf(" <!hd%u>", i&0x7f);
  118 #endif
  119                         free(dip, 0);
  120                         break;
  121                 }
  122 
  123                 printf(" hd%u%s", i&0x7f, (dip->bios_info.bios_edd > 0?"+":""));
  124 
  125                 /* Try to find the label, to figure out device type */
  126                 if ((bios_getdisklabel(&dip->bios_info, &dip->disklabel)) ) {
  127                         printf("*");
  128                         bsdunit = ide++;
  129                         type = 0;       /* XXX let it be IDE */
  130                 } else {
  131                         /* Best guess */
  132                         switch (dip->disklabel.d_type) {
  133                         case DTYPE_SCSI:
  134                                 type = 4;
  135                                 bsdunit = scsi++;
  136                                 dip->bios_info.flags |= BDI_GOODLABEL;
  137                                 break;
  138 
  139                         case DTYPE_ESDI:
  140                         case DTYPE_ST506:
  141                                 type = 0;
  142                                 bsdunit = ide++;
  143                                 dip->bios_info.flags |= BDI_GOODLABEL;
  144                                 break;
  145 
  146                         default:
  147                                 dip->bios_info.flags |= BDI_BADLABEL;
  148                                 type = 0;       /* XXX Suggest IDE */
  149                                 bsdunit = ide++;
  150                         }
  151                 }
  152 
  153                 dip->bios_info.checksum = 0; /* just in case */
  154                 /* Fill out best we can */
  155                 dip->bios_info.bsd_dev =
  156                     MAKEBOOTDEV(type, 0, 0, bsdunit, RAW_PART);
  157 
  158                 /* Add to queue of disks */
  159                 TAILQ_INSERT_TAIL(&disklist, dip, list);
  160         }
  161 }
  162 
  163 
  164 /* Probe for all BIOS supported disks */
  165 u_int32_t bios_cksumlen;
  166 void
  167 diskprobe(void)
  168 {
  169         struct diskinfo *dip;
  170         int i;
  171 
  172         /* These get passed to kernel */
  173         bios_diskinfo_t *bios_diskinfo;
  174 
  175         /* Init stuff */
  176         TAILQ_INIT(&disklist);
  177 
  178         /* Do probes */
  179         floppyprobe();
  180 #ifdef BIOS_DEBUG
  181         if (debug)
  182                 printf(";");
  183 #endif
  184         hardprobe();
  185 
  186         /* Checksumming of hard disks */
  187         for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; )
  188                 ;
  189         bios_cksumlen = i;
  190 
  191         /* Get space for passing bios_diskinfo stuff to kernel */
  192         for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
  193             dip = TAILQ_NEXT(dip, list))
  194                 i++;
  195         bios_diskinfo = alloc(++i * sizeof(bios_diskinfo_t));
  196 
  197         /* Copy out the bios_diskinfo stuff */
  198         for (i = 0, dip = TAILQ_FIRST(&disklist); dip;
  199             dip = TAILQ_NEXT(dip, list))
  200                 bios_diskinfo[i++] = dip->bios_info;
  201 
  202         bios_diskinfo[i++].bios_number = -1;
  203         /* Register for kernel use */
  204         addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
  205         addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t),
  206             bios_diskinfo);
  207 }
  208 
  209 
  210 void
  211 cdprobe(void)
  212 {
  213         struct diskinfo *dip;
  214         int cddev = bios_cddev & 0xff;
  215 
  216         /* Another BIOS boot device... */
  217 
  218         if (bios_cddev == -1)                   /* Not been set, so don't use */
  219                 return;
  220 
  221         dip = alloc(sizeof(struct diskinfo));
  222         bzero(dip, sizeof(*dip));
  223 
  224 #if 0
  225         if (bios_getdiskinfo(cddev, &dip->bios_info)) {
  226                 printf(" <!cd0>");      /* XXX */
  227                 free(dip, 0);
  228                 return;
  229         }
  230 #endif
  231 
  232         printf(" cd0");
  233 
  234         dip->bios_info.bios_number = cddev;
  235         dip->bios_info.bios_edd = 1;            /* Use the LBA calls */
  236         dip->bios_info.flags |= BDI_GOODLABEL | BDI_EL_TORITO;
  237         dip->bios_info.checksum = 0;             /* just in case */
  238         dip->bios_info.bsd_dev =
  239             MAKEBOOTDEV(0, 0, 0, 0xff, RAW_PART);
  240 
  241         /* Create an imaginary disk label */
  242         dip->disklabel.d_secsize = 2048;
  243         dip->disklabel.d_ntracks = 1;
  244         dip->disklabel.d_nsectors = 100;
  245         dip->disklabel.d_ncylinders = 1;
  246         dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
  247             dip->disklabel.d_nsectors;
  248         if (dip->disklabel.d_secpercyl == 0) {
  249                 dip->disklabel.d_secpercyl = 100;
  250                 /* as long as it's not 0, since readdisklabel divides by it */
  251         }
  252 
  253         strncpy(dip->disklabel.d_typename, "ATAPI CD-ROM",
  254             sizeof(dip->disklabel.d_typename));
  255         dip->disklabel.d_type = DTYPE_ATAPI;
  256 
  257         strncpy(dip->disklabel.d_packname, "fictitious",
  258             sizeof(dip->disklabel.d_packname));
  259         dip->disklabel.d_secperunit = 100;
  260         dip->disklabel.d_rpm = 300;
  261         dip->disklabel.d_interleave = 1;
  262 
  263         dip->disklabel.d_bbsize = 2048;
  264         dip->disklabel.d_sbsize = 2048;
  265 
  266         /* 'a' partition covering the "whole" disk */
  267         dip->disklabel.d_partitions[0].p_offset = 0;
  268         dip->disklabel.d_partitions[0].p_size = 100;
  269         dip->disklabel.d_partitions[0].p_fstype = FS_UNUSED;
  270 
  271         /* The raw partition is special */
  272         dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
  273         dip->disklabel.d_partitions[RAW_PART].p_size = 100;
  274         dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
  275 
  276         dip->disklabel.d_npartitions = RAW_PART + 1;
  277 
  278         dip->disklabel.d_magic = DISKMAGIC;
  279         dip->disklabel.d_magic2 = DISKMAGIC;
  280         dip->disklabel.d_checksum = dkcksum(&dip->disklabel);
  281 
  282         /* Add to queue of disks */
  283         TAILQ_INSERT_TAIL(&disklist, dip, list);
  284 }
  285 
  286 
  287 /* Find info on given BIOS disk */
  288 struct diskinfo *
  289 dklookup(int dev)
  290 {
  291         struct diskinfo *dip;
  292 
  293         for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
  294                 if (dip->bios_info.bios_number == dev)
  295                         return dip;
  296 
  297         return NULL;
  298 }
  299 
  300 void
  301 dump_diskinfo(void)
  302 {
  303         struct diskinfo *dip;
  304 
  305         printf("Disk\tBIOS#\tType\tCyls\tHeads\tSecs\tFlags\tChecksum\n");
  306         for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
  307                 bios_diskinfo_t *bdi = &dip->bios_info;
  308                 int d = bdi->bios_number;
  309                 int u = d & 0x7f;
  310                 char c;
  311 
  312                 if (bdi->flags & BDI_EL_TORITO) {
  313                         c = 'c';
  314                         u = 0;
  315                 } else {
  316                         c = (d & 0x80) ? 'h' : 'f';
  317                 }
  318 
  319                 printf("%cd%d\t0x%x\t%s\t%d\t%d\t%d\t0x%x\t0x%x\n",
  320                     c, u, d,
  321                     (bdi->flags & BDI_BADLABEL)?"*none*":"label",
  322                     bdi->bios_cylinders, bdi->bios_heads, bdi->bios_sectors,
  323                     bdi->flags, bdi->checksum);
  324         }
  325 }
  326 
  327 /* Find BIOS portion on given BIOS disk
  328  * XXX - Use dklookup() instead.
  329  */
  330 bios_diskinfo_t *
  331 bios_dklookup(int dev)
  332 {
  333         struct diskinfo *dip;
  334 
  335         dip = dklookup(dev);
  336         if (dip)
  337                 return &dip->bios_info;
  338 
  339         return NULL;
  340 }
  341 
  342 /*
  343  * Checksum one more block on all harddrives
  344  *
  345  * Use the adler32() function from libz,
  346  * as it is quick, small, and available.
  347  */
  348 int
  349 disksum(int blk)
  350 {
  351         struct diskinfo *dip, *dip2;
  352         int st, reprobe = 0;
  353         char *buf;
  354 
  355         buf = alloca(DEV_BSIZE);
  356         for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)) {
  357                 bios_diskinfo_t *bdi = &dip->bios_info;
  358 
  359                 /* Skip this disk if it is not a HD or has had an I/O error */
  360                 if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
  361                         continue;
  362 
  363                 /* Adler32 checksum */
  364                 st = biosd_io(F_READ, bdi, blk, 1, buf);
  365                 if (st) {
  366                         bdi->flags |= BDI_INVALID;
  367                         continue;
  368                 }
  369                 bdi->checksum = adler32(bdi->checksum, buf, DEV_BSIZE);
  370 
  371                 for (dip2 = TAILQ_FIRST(&disklist); dip2 != dip;
  372                                 dip2 = TAILQ_NEXT(dip2, list)) {
  373                         bios_diskinfo_t *bd = &dip2->bios_info;
  374                         if ((bd->bios_number & 0x80) &&
  375                             !(bd->flags & BDI_INVALID) &&
  376                             bdi->checksum == bd->checksum)
  377                                 reprobe = 1;
  378                 }
  379         }
  380 
  381         return reprobe;
  382 }

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