Annotation of sys/arch/i386/stand/libsa/diskprobe.c, Revision 1.1
1.1 ! nbrk 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: }
CVSweb