xref: /openbsd-src/sys/kern/subr_disk.c (revision 94fd4554194a14f126fba33b837cc68a1df42468)
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