1 /* $OpenBSD: subr_disk.c,v 1.40 2007/05/15 01:58:06 deraadt Exp $ */ 2 /* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1995 Jason R. Thorpe. All rights reserved. 6 * Copyright (c) 1982, 1986, 1988, 1993 7 * The Regents of the University of California. All rights reserved. 8 * (c) UNIX System Laboratories, Inc. 9 * All or some portions of this file are derived from material licensed 10 * to the University of California by American Telephone and Telegraph 11 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 12 * the permission of UNIX System Laboratories, Inc. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/fcntl.h> 46 #include <sys/buf.h> 47 #include <sys/stat.h> 48 #include <sys/syslog.h> 49 #include <sys/device.h> 50 #include <sys/time.h> 51 #include <sys/disklabel.h> 52 #include <sys/conf.h> 53 #include <sys/lock.h> 54 #include <sys/disk.h> 55 #include <sys/reboot.h> 56 #include <sys/dkio.h> 57 #include <sys/dkstat.h> /* XXX */ 58 #include <sys/proc.h> 59 #include <uvm/uvm_extern.h> 60 61 #include <dev/rndvar.h> 62 #include <dev/cons.h> 63 64 /* 65 * A global list of all disks attached to the system. May grow or 66 * shrink over time. 67 */ 68 struct disklist_head disklist; /* TAILQ_HEAD */ 69 int disk_count; /* number of drives in global disklist */ 70 int disk_change; /* set if a disk has been attached/detached 71 * since last we looked at this variable. This 72 * is reset by hw_sysctl() 73 */ 74 75 /* 76 * Seek sort for disks. We depend on the driver which calls us using b_resid 77 * as the current cylinder number. 78 * 79 * The argument ap structure holds a b_actf activity chain pointer on which we 80 * keep two queues, sorted in ascending cylinder order. The first queue holds 81 * those requests which are positioned after the current cylinder (in the first 82 * request); the second holds requests which came in after their cylinder number 83 * was passed. Thus we implement a one way scan, retracting after reaching the 84 * end of the drive to the first request on the second queue, at which time it 85 * becomes the first queue. 86 * 87 * A one-way scan is natural because of the way UNIX read-ahead blocks are 88 * allocated. 89 */ 90 91 void 92 disksort(struct buf *ap, struct buf *bp) 93 { 94 struct buf *bq; 95 96 /* If the queue is empty, then it's easy. */ 97 if (ap->b_actf == NULL) { 98 bp->b_actf = NULL; 99 ap->b_actf = bp; 100 return; 101 } 102 103 /* 104 * If we lie after the first (currently active) request, then we 105 * must locate the second request list and add ourselves to it. 106 */ 107 bq = ap->b_actf; 108 if (bp->b_cylinder < bq->b_cylinder) { 109 while (bq->b_actf) { 110 /* 111 * Check for an ``inversion'' in the normally ascending 112 * cylinder numbers, indicating the start of the second 113 * request list. 114 */ 115 if (bq->b_actf->b_cylinder < bq->b_cylinder) { 116 /* 117 * Search the second request list for the first 118 * request at a larger cylinder number. We go 119 * before that; if there is no such request, we 120 * go at end. 121 */ 122 do { 123 if (bp->b_cylinder < 124 bq->b_actf->b_cylinder) 125 goto insert; 126 if (bp->b_cylinder == 127 bq->b_actf->b_cylinder && 128 bp->b_blkno < bq->b_actf->b_blkno) 129 goto insert; 130 bq = bq->b_actf; 131 } while (bq->b_actf); 132 goto insert; /* after last */ 133 } 134 bq = bq->b_actf; 135 } 136 /* 137 * No inversions... we will go after the last, and 138 * be the first request in the second request list. 139 */ 140 goto insert; 141 } 142 /* 143 * Request is at/after the current request... 144 * sort in the first request list. 145 */ 146 while (bq->b_actf) { 147 /* 148 * We want to go after the current request if there is an 149 * inversion after it (i.e. it is the end of the first 150 * request list), or if the next request is a larger cylinder 151 * than our request. 152 */ 153 if (bq->b_actf->b_cylinder < bq->b_cylinder || 154 bp->b_cylinder < bq->b_actf->b_cylinder || 155 (bp->b_cylinder == bq->b_actf->b_cylinder && 156 bp->b_blkno < bq->b_actf->b_blkno)) 157 goto insert; 158 bq = bq->b_actf; 159 } 160 /* 161 * Neither a second list nor a larger request... we go at the end of 162 * the first list, which is the same as the end of the whole schebang. 163 */ 164 insert: bp->b_actf = bq->b_actf; 165 bq->b_actf = bp; 166 } 167 168 /* 169 * Compute checksum for disk label. 170 */ 171 u_int 172 dkcksum(struct disklabel *lp) 173 { 174 u_int16_t *start, *end; 175 u_int16_t sum = 0; 176 177 start = (u_int16_t *)lp; 178 end = (u_int16_t *)&lp->d_partitions[lp->d_npartitions]; 179 while (start < end) 180 sum ^= *start++; 181 return (sum); 182 } 183 184 /* 185 * Disk error is the preface to plaintive error messages 186 * about failing disk transfers. It prints messages of the form 187 188 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) 189 190 * if the offset of the error in the transfer and a disk label 191 * are both available. blkdone should be -1 if the position of the error 192 * is unknown; the disklabel pointer may be null from drivers that have not 193 * been converted to use them. The message is printed with printf 194 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. 195 * The message should be completed (with at least a newline) with printf 196 * or addlog, respectively. There is no trailing space. 197 */ 198 void 199 diskerr(struct buf *bp, char *dname, char *what, int pri, int blkdone, 200 struct disklabel *lp) 201 { 202 int unit = DISKUNIT(bp->b_dev), part = DISKPART(bp->b_dev); 203 int (*pr)(const char *, ...); 204 char partname = 'a' + part; 205 int sn; 206 207 if (pri != LOG_PRINTF) { 208 static const char fmt[] = ""; 209 log(pri, fmt); 210 pr = addlog; 211 } else 212 pr = printf; 213 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what, 214 bp->b_flags & B_READ ? "read" : "writ"); 215 sn = bp->b_blkno; 216 if (bp->b_bcount <= DEV_BSIZE) 217 (*pr)("%d", sn); 218 else { 219 if (blkdone >= 0) { 220 sn += blkdone; 221 (*pr)("%d of ", sn); 222 } 223 (*pr)("%d-%d", bp->b_blkno, 224 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); 225 } 226 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { 227 sn += lp->d_partitions[part].p_offset; 228 (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn, 229 sn / lp->d_secpercyl); 230 sn %= lp->d_secpercyl; 231 (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); 232 } 233 } 234 235 /* 236 * Initialize the disklist. Called by main() before autoconfiguration. 237 */ 238 void 239 disk_init(void) 240 { 241 242 TAILQ_INIT(&disklist); 243 disk_count = disk_change = 0; 244 } 245 246 int 247 disk_construct(struct disk *diskp, char *lockname) 248 { 249 rw_init(&diskp->dk_lock, lockname); 250 251 diskp->dk_flags |= DKF_CONSTRUCTED; 252 253 return (0); 254 } 255 256 /* 257 * Attach a disk. 258 */ 259 void 260 disk_attach(struct disk *diskp) 261 { 262 263 if (!ISSET(diskp->dk_flags, DKF_CONSTRUCTED)) 264 disk_construct(diskp, diskp->dk_name); 265 266 /* 267 * Allocate and initialize the disklabel structures. Note that 268 * it's not safe to sleep here, since we're probably going to be 269 * called during autoconfiguration. 270 */ 271 diskp->dk_label = malloc(sizeof(struct disklabel), M_DEVBUF, M_NOWAIT); 272 diskp->dk_cpulabel = malloc(sizeof(struct cpu_disklabel), M_DEVBUF, 273 M_NOWAIT); 274 if ((diskp->dk_label == NULL) || (diskp->dk_cpulabel == NULL)) 275 panic("disk_attach: can't allocate storage for disklabel"); 276 277 bzero(diskp->dk_label, sizeof(struct disklabel)); 278 bzero(diskp->dk_cpulabel, sizeof(struct cpu_disklabel)); 279 280 /* 281 * Set the attached timestamp. 282 */ 283 microuptime(&diskp->dk_attachtime); 284 285 /* 286 * Link into the disklist. 287 */ 288 TAILQ_INSERT_TAIL(&disklist, diskp, dk_link); 289 ++disk_count; 290 disk_change = 1; 291 } 292 293 /* 294 * Detach a disk. 295 */ 296 void 297 disk_detach(struct disk *diskp) 298 { 299 300 /* 301 * Free the space used by the disklabel structures. 302 */ 303 free(diskp->dk_label, M_DEVBUF); 304 free(diskp->dk_cpulabel, M_DEVBUF); 305 306 /* 307 * Remove from the disklist. 308 */ 309 TAILQ_REMOVE(&disklist, diskp, dk_link); 310 disk_change = 1; 311 if (--disk_count < 0) 312 panic("disk_detach: disk_count < 0"); 313 } 314 315 /* 316 * Increment a disk's busy counter. If the counter is going from 317 * 0 to 1, set the timestamp. 318 */ 319 void 320 disk_busy(struct disk *diskp) 321 { 322 323 /* 324 * XXX We'd like to use something as accurate as microtime(), 325 * but that doesn't depend on the system TOD clock. 326 */ 327 if (diskp->dk_busy++ == 0) { 328 microuptime(&diskp->dk_timestamp); 329 } 330 } 331 332 /* 333 * Decrement a disk's busy counter, increment the byte count, total busy 334 * time, and reset the timestamp. 335 */ 336 void 337 disk_unbusy(struct disk *diskp, long bcount, int read) 338 { 339 struct timeval dv_time, diff_time; 340 341 if (diskp->dk_busy-- == 0) 342 printf("disk_unbusy: %s: dk_busy < 0\n", diskp->dk_name); 343 344 microuptime(&dv_time); 345 346 timersub(&dv_time, &diskp->dk_timestamp, &diff_time); 347 timeradd(&diskp->dk_time, &diff_time, &diskp->dk_time); 348 349 diskp->dk_timestamp = dv_time; 350 if (bcount > 0) { 351 if (read) { 352 diskp->dk_rbytes += bcount; 353 diskp->dk_rxfer++; 354 } else { 355 diskp->dk_wbytes += bcount; 356 diskp->dk_wxfer++; 357 } 358 } else 359 diskp->dk_seek++; 360 361 add_disk_randomness(bcount ^ diff_time.tv_usec); 362 } 363 364 int 365 disk_lock(struct disk *dk) 366 { 367 int error; 368 369 error = rw_enter(&dk->dk_lock, RW_WRITE|RW_INTR); 370 371 return (error); 372 } 373 374 void 375 disk_unlock(struct disk *dk) 376 { 377 rw_exit(&dk->dk_lock); 378 } 379 380 int 381 dk_mountroot(void) 382 { 383 dev_t rawdev, rrootdev; 384 int part = DISKPART(rootdev); 385 int (*mountrootfn)(void); 386 struct disklabel dl; 387 int error; 388 389 rrootdev = blktochr(rootdev); 390 rawdev = MAKEDISKDEV(major(rrootdev), DISKUNIT(rootdev), RAW_PART); 391 #ifdef DEBUG 392 printf("rootdev=0x%x rrootdev=0x%x rawdev=0x%x\n", rootdev, 393 rrootdev, rawdev); 394 #endif 395 396 /* 397 * open device, ioctl for the disklabel, and close it. 398 */ 399 error = (cdevsw[major(rrootdev)].d_open)(rawdev, FREAD, 400 S_IFCHR, curproc); 401 if (error) 402 panic("cannot open disk, 0x%x/0x%x, error %d", 403 rootdev, rrootdev, error); 404 error = (cdevsw[major(rrootdev)].d_ioctl)(rawdev, DIOCGDINFO, 405 (caddr_t)&dl, FREAD, curproc); 406 if (error) 407 panic("cannot read disk label, 0x%x/0x%x, error %d", 408 rootdev, rrootdev, error); 409 (void) (cdevsw[major(rrootdev)].d_close)(rawdev, FREAD, 410 S_IFCHR, curproc); 411 412 if (dl.d_partitions[part].p_size == 0) 413 panic("root filesystem has size 0"); 414 switch (dl.d_partitions[part].p_fstype) { 415 #ifdef EXT2FS 416 case FS_EXT2FS: 417 { 418 extern int ext2fs_mountroot(void); 419 mountrootfn = ext2fs_mountroot; 420 } 421 break; 422 #endif 423 #ifdef FFS 424 case FS_BSDFFS: 425 { 426 extern int ffs_mountroot(void); 427 mountrootfn = ffs_mountroot; 428 } 429 break; 430 #endif 431 #ifdef CD9660 432 case FS_ISO9660: 433 { 434 extern int cd9660_mountroot(void); 435 mountrootfn = cd9660_mountroot; 436 } 437 break; 438 #endif 439 default: 440 #ifdef FFS 441 { 442 extern int ffs_mountroot(void); 443 444 printf("filesystem type %d not known.. assuming ffs\n", 445 dl.d_partitions[part].p_fstype); 446 mountrootfn = ffs_mountroot; 447 } 448 #else 449 panic("disk 0x%x/0x%x filesystem type %d not known", 450 rootdev, rrootdev, dl.d_partitions[part].p_fstype); 451 #endif 452 } 453 return (*mountrootfn)(); 454 } 455 456 struct bufq * 457 bufq_default_alloc(void) 458 { 459 struct bufq_default *bq; 460 461 bq = malloc(sizeof(*bq), M_DEVBUF, M_NOWAIT); 462 if (bq == NULL) 463 panic("bufq_default_alloc: no memory"); 464 465 memset(bq, 0, sizeof(*bq)); 466 bq->bufq.bufq_free = bufq_default_free; 467 bq->bufq.bufq_add = bufq_default_add; 468 bq->bufq.bufq_get = bufq_default_get; 469 470 return ((struct bufq *)bq); 471 } 472 473 void 474 bufq_default_free(struct bufq *bq) 475 { 476 free(bq, M_DEVBUF); 477 } 478 479 void 480 bufq_default_add(struct bufq *bq, struct buf *bp) 481 { 482 struct bufq_default *bufq = (struct bufq_default *)bq; 483 struct proc *p = bp->b_proc; 484 struct buf *head; 485 486 if (p == NULL || p->p_nice < NZERO) 487 head = &bufq->bufq_head[0]; 488 else if (p->p_nice == NZERO) 489 head = &bufq->bufq_head[1]; 490 else 491 head = &bufq->bufq_head[2]; 492 493 disksort(head, bp); 494 } 495 496 struct buf * 497 bufq_default_get(struct bufq *bq) 498 { 499 struct bufq_default *bufq = (struct bufq_default *)bq; 500 struct buf *bp, *head; 501 int i; 502 503 for (i = 0; i < 3; i++) { 504 head = &bufq->bufq_head[i]; 505 if ((bp = head->b_actf)) 506 break; 507 } 508 if (bp == NULL) 509 return (NULL); 510 head->b_actf = bp->b_actf; 511 return (bp); 512 } 513 514 #ifdef RAMDISK_HOOKS 515 static struct device fakerdrootdev = { DV_DISK, {}, NULL, 0, "rd0", NULL }; 516 #endif 517 518 struct device * 519 getdisk(char *str, int len, int defpart, dev_t *devp) 520 { 521 struct device *dv; 522 523 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 524 printf("use one of: exit"); 525 #ifdef RAMDISK_HOOKS 526 printf(" %s[a-p]", fakerdrootdev.dv_xname); 527 #endif 528 TAILQ_FOREACH(dv, &alldevs, dv_list) { 529 if (dv->dv_class == DV_DISK) 530 printf(" %s[a-p]", dv->dv_xname); 531 #if defined(NFSCLIENT) 532 if (dv->dv_class == DV_IFNET) 533 printf(" %s", dv->dv_xname); 534 #endif 535 } 536 printf("\n"); 537 } 538 return (dv); 539 } 540 541 struct device * 542 parsedisk(char *str, int len, int defpart, dev_t *devp) 543 { 544 struct device *dv; 545 char *cp, c; 546 int majdev, part; 547 548 if (len == 0) 549 return (NULL); 550 cp = str + len - 1; 551 c = *cp; 552 if (c >= 'a' && (c - 'a') < MAXPARTITIONS) { 553 part = c - 'a'; 554 *cp = '\0'; 555 } else 556 part = defpart; 557 558 #ifdef RAMDISK_HOOKS 559 if (strcmp(str, fakerdrootdev.dv_xname) == 0) { 560 dv = &fakerdrootdev; 561 goto gotdisk; 562 } 563 #endif 564 565 TAILQ_FOREACH(dv, &alldevs, dv_list) { 566 if (dv->dv_class == DV_DISK && 567 strcmp(str, dv->dv_xname) == 0) { 568 #ifdef RAMDISK_HOOKS 569 gotdisk: 570 #endif 571 majdev = findblkmajor(dv); 572 if (majdev < 0) 573 panic("parsedisk"); 574 *devp = MAKEDISKDEV(majdev, dv->dv_unit, part); 575 break; 576 } 577 #if defined(NFSCLIENT) 578 if (dv->dv_class == DV_IFNET && 579 strcmp(str, dv->dv_xname) == 0) { 580 *devp = NODEV; 581 break; 582 } 583 #endif 584 } 585 586 *cp = c; 587 return (dv); 588 } 589 590 void 591 setroot(struct device *bootdv, int part, int exitflags) 592 { 593 int majdev, unit, len, s; 594 struct swdevt *swp; 595 struct device *rootdv, *dv; 596 dev_t nrootdev, nswapdev = NODEV, temp = NODEV; 597 char buf[128]; 598 #if defined(NFSCLIENT) 599 extern char *nfsbootdevname; 600 #endif 601 602 if (boothowto & RB_DFLTROOT) 603 return; 604 605 #ifdef RAMDISK_HOOKS 606 bootdv = &fakerdrootdev; 607 mountroot = NULL; 608 part = 0; 609 #endif 610 611 /* 612 * If `swap generic' and we couldn't determine boot device, 613 * ask the user. 614 */ 615 if (mountroot == NULL && bootdv == NULL) 616 boothowto |= RB_ASKNAME; 617 if (boothowto & RB_ASKNAME) { 618 while (1) { 619 printf("root device"); 620 if (bootdv != NULL) { 621 printf(" (default %s", bootdv->dv_xname); 622 if (bootdv->dv_class == DV_DISK) 623 printf("%c", 'a' + part); 624 printf(")"); 625 } 626 printf(": "); 627 s = splhigh(); 628 cnpollc(TRUE); 629 len = getsn(buf, sizeof(buf)); 630 cnpollc(FALSE); 631 splx(s); 632 if (strcmp(buf, "exit") == 0) 633 boot(exitflags); 634 if (len == 0 && bootdv != NULL) { 635 strlcpy(buf, bootdv->dv_xname, sizeof buf); 636 len = strlen(buf); 637 } 638 if (len > 0 && buf[len - 1] == '*') { 639 buf[--len] = '\0'; 640 dv = getdisk(buf, len, part, &nrootdev); 641 if (dv != NULL) { 642 rootdv = dv; 643 nswapdev = nrootdev; 644 goto gotswap; 645 } 646 } 647 dv = getdisk(buf, len, part, &nrootdev); 648 if (dv != NULL) { 649 rootdv = dv; 650 break; 651 } 652 } 653 654 if (rootdv->dv_class == DV_IFNET) 655 goto gotswap; 656 657 /* try to build swap device out of new root device */ 658 while (1) { 659 printf("swap device"); 660 if (rootdv != NULL) 661 printf(" (default %s%s)", rootdv->dv_xname, 662 rootdv->dv_class == DV_DISK ? "b" : ""); 663 printf(": "); 664 s = splhigh(); 665 cnpollc(TRUE); 666 len = getsn(buf, sizeof(buf)); 667 cnpollc(FALSE); 668 splx(s); 669 if (strcmp(buf, "exit") == 0) 670 boot(exitflags); 671 if (len == 0 && rootdv != NULL) { 672 switch (rootdv->dv_class) { 673 case DV_IFNET: 674 nswapdev = NODEV; 675 break; 676 case DV_DISK: 677 nswapdev = MAKEDISKDEV(major(nrootdev), 678 DISKUNIT(nrootdev), 1); 679 if (nswapdev == nrootdev) 680 continue; 681 break; 682 default: 683 break; 684 } 685 break; 686 } 687 dv = getdisk(buf, len, 1, &nswapdev); 688 if (dv) { 689 if (dv->dv_class == DV_IFNET) 690 nswapdev = NODEV; 691 if (nswapdev == nrootdev) 692 continue; 693 break; 694 } 695 } 696 gotswap: 697 rootdev = nrootdev; 698 dumpdev = nswapdev; 699 swdevt[0].sw_dev = nswapdev; 700 swdevt[1].sw_dev = NODEV; 701 #if defined(NFSCLIENT) 702 } else if (mountroot == nfs_mountroot) { 703 rootdev = dumpdev = swapdev = NODEV; 704 #endif 705 } else if (mountroot == NULL) { 706 /* `swap generic': Use the device the ROM told us to use */ 707 rootdv = bootdv; 708 majdev = findblkmajor(rootdv); 709 if (majdev >= 0) { 710 /* 711 * Root and swap are on the disk. 712 * Assume swap is on partition b. 713 */ 714 rootdev = MAKEDISKDEV(majdev, rootdv->dv_unit, part); 715 nswapdev = MAKEDISKDEV(majdev, rootdv->dv_unit, 1); 716 } else { 717 /* 718 * Root and swap are on a net. 719 */ 720 nswapdev = NODEV; 721 } 722 dumpdev = nswapdev; 723 swdevt[0].sw_dev = nswapdev; 724 /* swdevt[1].sw_dev = NODEV; */ 725 } else { 726 /* Completely pre-configured, but we want rootdv .. */ 727 majdev = major(rootdev); 728 if (findblkname(majdev) == NULL) 729 return; 730 unit = DISKUNIT(rootdev); 731 part = DISKPART(rootdev); 732 snprintf(buf, sizeof buf, "%s%d%c", 733 findblkname(majdev), unit, 'a' + part); 734 rootdv = parsedisk(buf, strlen(buf), 0, &nrootdev); 735 } 736 737 switch (rootdv->dv_class) { 738 #if defined(NFSCLIENT) 739 case DV_IFNET: 740 mountroot = nfs_mountroot; 741 nfsbootdevname = rootdv->dv_xname; 742 return; 743 #endif 744 case DV_DISK: 745 mountroot = dk_mountroot; 746 part = DISKPART(rootdev); 747 break; 748 default: 749 printf("can't figure root, hope your kernel is right\n"); 750 return; 751 } 752 753 printf("root on %s%c", rootdv->dv_xname, 'a' + part); 754 755 /* 756 * Make the swap partition on the root drive the primary swap. 757 */ 758 for (swp = swdevt; swp->sw_dev != NODEV; swp++) { 759 if (major(rootdev) == major(swp->sw_dev) && 760 DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) { 761 temp = swdevt[0].sw_dev; 762 swdevt[0].sw_dev = swp->sw_dev; 763 swp->sw_dev = temp; 764 break; 765 } 766 } 767 if (swp->sw_dev != NODEV) { 768 /* 769 * If dumpdev was the same as the old primary swap device, 770 * move it to the new primary swap device. 771 */ 772 if (temp == dumpdev) 773 dumpdev = swdevt[0].sw_dev; 774 } 775 if (swdevt[0].sw_dev != NODEV) 776 printf(" swap on %s%d%c", findblkname(major(swdevt[0].sw_dev)), 777 DISKUNIT(swdevt[0].sw_dev), 778 'a' + DISKPART(swdevt[0].sw_dev)); 779 if (dumpdev != NODEV) 780 printf(" dump on %s%d%c", findblkname(major(dumpdev)), 781 DISKUNIT(dumpdev), 'a' + DISKPART(dumpdev)); 782 printf("\n"); 783 } 784 785 extern struct nam2blk nam2blk[]; 786 787 int 788 findblkmajor(struct device *dv) 789 { 790 char *name = dv->dv_xname; 791 int i; 792 793 for (i = 0; nam2blk[i].name; i++) 794 if (!strncmp(name, nam2blk[i].name, strlen(nam2blk[i].name))) 795 return (nam2blk[i].maj); 796 return (-1); 797 } 798 799 char * 800 findblkname(int maj) 801 { 802 int i; 803 804 for (i = 0; nam2blk[i].name; i++) 805 if (nam2blk[i].maj == maj) 806 return (nam2blk[i].name); 807 return (NULL); 808 } 809