xref: /illumos-gate/usr/src/boot/i386/gptzfsboot/zfsboot.c (revision bbf215553c7233fbab8a0afdf1fac74c44781867)
1 /*
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15 
16 #include <sys/cdefs.h>
17 #include <stand.h>
18 
19 #include <sys/param.h>
20 #include <sys/errno.h>
21 #include <sys/diskmbr.h>
22 #include <sys/vtoc.h>
23 #include <sys/disk.h>
24 #include <sys/reboot.h>
25 #include <sys/queue.h>
26 #include <sys/multiboot.h>
27 #include <sys/zfs_bootenv.h>
28 
29 #include <machine/bootinfo.h>
30 #include <machine/elf.h>
31 #include <machine/pc/bios.h>
32 
33 #include <stdarg.h>
34 #include <stdbool.h>
35 #include <stddef.h>
36 
37 #include <a.out.h>
38 #include "bootstrap.h"
39 #include "libi386.h"
40 #include <btxv86.h>
41 
42 #include "lib.h"
43 #include "rbx.h"
44 #include "cons.h"
45 #include "bootargs.h"
46 #include "disk.h"
47 #include "part.h"
48 #include "paths.h"
49 
50 #include "libzfs.h"
51 
52 #define	ARGS		0x900
53 #define	NOPT		15
54 #define	NDEV		3
55 
56 #define	BIOS_NUMDRIVES	0x475
57 #define	DRV_HARD	0x80
58 #define	DRV_MASK	0x7f
59 
60 #define	TYPE_AD		0
61 #define	TYPE_DA		1
62 #define	TYPE_MAXHARD	TYPE_DA
63 #define	TYPE_FD		2
64 
65 extern uint32_t _end;
66 
67 /*
68  * Fake multiboot header to provide versioning and to pass
69  * partition start LBA. Partition is either GPT partition or
70  * VTOC slice.
71  */
72 extern const struct multiboot_header mb_header;
73 extern uint64_t start_sector;
74 
75 static const char optstr[NOPT] = "DhaCcdgmnpqrstv"; /* Also 'P', 'S' */
76 static const unsigned char flags[NOPT] = {
77     RBX_DUAL,
78     RBX_SERIAL,
79     RBX_ASKNAME,
80     RBX_CDROM,
81     RBX_CONFIG,
82     RBX_KDB,
83     RBX_GDB,
84     RBX_MUTE,
85     RBX_NOINTR,
86     RBX_PAUSE,
87     RBX_QUIET,
88     RBX_DFLTROOT,
89     RBX_SINGLE,
90     RBX_TEXT_MODE,
91     RBX_VERBOSE
92 };
93 uint32_t opts;
94 
95 /*
96  * Paths to try loading before falling back to the boot2 prompt.
97  */
98 #define	PATH_ZFSLOADER "/boot/zfsloader"
99 static const struct string {
100 	const char *p;
101 	size_t len;
102 } loadpath[] = {
103 	{ PATH_LOADER, sizeof (PATH_LOADER) },
104 	{ PATH_ZFSLOADER, sizeof (PATH_ZFSLOADER) }
105 };
106 
107 static const unsigned char dev_maj[NDEV] = {30, 4, 2};
108 
109 static struct i386_devdesc *bdev;
110 static char cmd[512];
111 static char cmddup[512];
112 static char kname[1024];
113 static int comspeed = SIOSPD;
114 static struct bootinfo bootinfo;
115 static uint32_t bootdev;
116 static struct zfs_boot_args zfsargs;
117 
118 extern vm_offset_t high_heap_base;
119 extern uint32_t	bios_basemem, bios_extmem, high_heap_size;
120 
121 static char *heap_top;
122 static char *heap_bottom;
123 
124 static void i386_zfs_probe(void);
125 static void load(void);
126 static int parse_cmd(void);
127 
128 struct arch_switch archsw;	/* MI/MD interface boundary */
129 static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */
130 
131 struct devsw *devsw[] = {
132 	&bioshd,
133 	&zfs_dev,
134 	NULL
135 };
136 
137 struct fs_ops *file_system[] = {
138 	&zfs_fsops,
139 	&ufs_fsops,
140 	&dosfs_fsops,
141 	NULL
142 };
143 
144 caddr_t
145 ptov(uintptr_t x)
146 {
147 	return (PTOV(x));
148 }
149 
150 int
151 main(void)
152 {
153 	unsigned i;
154 	int fd;
155 	bool auto_boot;
156 	bool nextboot = false;
157 	struct disk_devdesc devdesc;
158 
159 	bios_getmem();
160 
161 	if (high_heap_size > 0) {
162 		heap_top = PTOV(high_heap_base + high_heap_size);
163 		heap_bottom = PTOV(high_heap_base);
164 	} else {
165 		heap_bottom = (char *)
166 		    (roundup2(__base + (int32_t)&_end, 0x10000) - __base);
167 		heap_top = (char *)PTOV(bios_basemem);
168 	}
169 	setheap(heap_bottom, heap_top);
170 
171 	/*
172 	 * Initialise the block cache. Set the upper limit.
173 	 */
174 	bcache_init(32768, 512);
175 
176 	archsw.arch_autoload = NULL;
177 	archsw.arch_getdev = i386_getdev;
178 	archsw.arch_copyin = NULL;
179 	archsw.arch_copyout = NULL;
180 	archsw.arch_readin = NULL;
181 	archsw.arch_isainb = NULL;
182 	archsw.arch_isaoutb = NULL;
183 	archsw.arch_zfs_probe = i386_zfs_probe;
184 
185 	bootinfo.bi_version = BOOTINFO_VERSION;
186 	bootinfo.bi_size = sizeof (bootinfo);
187 	bootinfo.bi_basemem = bios_basemem / 1024;
188 	bootinfo.bi_extmem = bios_extmem / 1024;
189 	bootinfo.bi_memsizes_valid++;
190 	bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS);
191 
192 	/*
193 	 * Set up fall back device name. bd_bios2unit() is not available yet.
194 	 */
195 	if (bootinfo.bi_bios_dev < 0x80)
196 		snprintf(boot_devname, sizeof (boot_devname), "disk%d:",
197 		    bootinfo.bi_bios_dev);
198 	else
199 		snprintf(boot_devname, sizeof (boot_devname), "disk%d:",
200 		    bootinfo.bi_bios_dev - 0x80);
201 
202 	for (i = 0; devsw[i] != NULL; i++)
203 		if (devsw[i]->dv_init != NULL)
204 			(devsw[i]->dv_init)();
205 
206 	disk_parsedev(&devdesc, boot_devname + 4, NULL);
207 
208 	bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1,
209 	    devdesc.dd.d_unit,
210 	    devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff);
211 
212 	/*
213 	 * zfs_fmtdev() can be called only after dv_init
214 	 */
215 	if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) {
216 		/* set up proper device name string for ZFS */
217 		strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname));
218 		if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd,
219 		    sizeof (cmd)) == 0) {
220 			nvlist_t *benv;
221 
222 			nextboot = true;
223 			memcpy(cmddup, cmd, sizeof (cmd));
224 			if (parse_cmd()) {
225 				printf("failed to parse bootonce command\n");
226 				exit(0);
227 			}
228 			if (!OPT_CHECK(RBX_QUIET))
229 				printf("zfs bootonce: %s\n", cmddup);
230 
231 			if (zfs_get_bootenv(bdev, &benv) == 0) {
232 				nvlist_add_string(benv, OS_BOOTONCE_USED,
233 				    cmddup);
234 				zfs_set_bootenv(bdev, benv);
235 			}
236 			/* Do not process this command twice */
237 			*cmd = 0;
238 		}
239 	}
240 
241 	/* now make sure we have bdev on all cases */
242 	free(bdev);
243 	i386_getdev((void **)&bdev, boot_devname, NULL);
244 
245 	env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev,
246 	    env_nounset);
247 
248 	/* Process configuration file */
249 	setenv("screen-#rows", "24", 1);
250 	auto_boot = true;
251 
252 	fd = open(PATH_CONFIG, O_RDONLY);
253 	if (fd == -1)
254 		fd = open(PATH_DOTCONFIG, O_RDONLY);
255 
256 	if (fd != -1) {
257 		ssize_t cmdlen;
258 
259 		if ((cmdlen = read(fd, cmd, sizeof (cmd))) > 0)
260 			cmd[cmdlen] = '\0';
261 		else
262 			*cmd = '\0';
263 		close(fd);
264 	}
265 
266 	if (*cmd) {
267 		/*
268 		 * Note that parse_cmd() is destructive to cmd[] and we also
269 		 * want to honor RBX_QUIET option that could be present in
270 		 * cmd[].
271 		 */
272 		memcpy(cmddup, cmd, sizeof (cmd));
273 		if (parse_cmd())
274 			auto_boot = false;
275 		if (!OPT_CHECK(RBX_QUIET))
276 			printf("%s: %s\n", PATH_CONFIG, cmddup);
277 		/* Do not process this command twice */
278 		*cmd = 0;
279 	}
280 
281 	/* Do not risk waiting at the prompt forever. */
282 	if (nextboot && !auto_boot)
283 		exit(0);
284 
285 	if (auto_boot && !*kname) {
286 		/*
287 		 * Try to exec stage 3 boot loader. If interrupted by a
288 		 * keypress, or in case of failure, drop the user to the
289 		 * boot2 prompt..
290 		 */
291 		auto_boot = false;
292 		for (i = 0; i < nitems(loadpath); i++) {
293 			memcpy(kname, loadpath[i].p, loadpath[i].len);
294 			if (keyhit(3))
295 				break;
296 			load();
297 		}
298 	}
299 	/* Reset to default */
300 	memcpy(kname, loadpath[0].p, loadpath[0].len);
301 
302 	/* Present the user with the boot2 prompt. */
303 
304 	for (;;) {
305 		if (!auto_boot || !OPT_CHECK(RBX_QUIET)) {
306 			printf("\nillumos/x86 boot\n");
307 			printf("Default: %s%s\nboot: ", boot_devname, kname);
308 		}
309 		if (ioctrl & IO_SERIAL)
310 			sio_flush();
311 		if (!auto_boot || keyhit(5))
312 			getstr(cmd, sizeof (cmd));
313 		else if (!auto_boot || !OPT_CHECK(RBX_QUIET))
314 			putchar('\n');
315 		auto_boot = false;
316 		if (parse_cmd())
317 			putchar('\a');
318 		else
319 			load();
320 	}
321 }
322 
323 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
324 void
325 exit(int x)
326 {
327 	__exit(x);
328 }
329 
330 static void
331 load(void)
332 {
333 	union {
334 		struct exec ex;
335 		Elf32_Ehdr eh;
336 	} hdr;
337 	static Elf32_Phdr ep[2];
338 	static Elf32_Shdr es[2];
339 	caddr_t p;
340 	uint32_t addr, x;
341 	int fd, fmt, i, j;
342 
343 	if ((fd = open(kname, O_RDONLY)) == -1) {
344 		printf("\nCan't find %s\n", kname);
345 		return;
346 	}
347 	if (read(fd, &hdr, sizeof (hdr)) != sizeof (hdr)) {
348 		close(fd);
349 		return;
350 	}
351 	if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
352 		fmt = 0;
353 	} else if (IS_ELF(hdr.eh)) {
354 		fmt = 1;
355 	} else {
356 		printf("Invalid %s\n", "format");
357 		close(fd);
358 		return;
359 	}
360 	if (fmt == 0) {
361 		addr = hdr.ex.a_entry & 0xffffff;
362 		p = PTOV(addr);
363 		lseek(fd, PAGE_SIZE, SEEK_SET);
364 		if (read(fd, p, hdr.ex.a_text) != hdr.ex.a_text) {
365 			close(fd);
366 			return;
367 		}
368 		p += roundup2(hdr.ex.a_text, PAGE_SIZE);
369 		if (read(fd, p, hdr.ex.a_data) != hdr.ex.a_data) {
370 			close(fd);
371 			return;
372 		}
373 		p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
374 		bootinfo.bi_symtab = VTOP(p);
375 		memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms));
376 		p += sizeof (hdr.ex.a_syms);
377 		if (hdr.ex.a_syms) {
378 			if (read(fd, p, hdr.ex.a_syms) != hdr.ex.a_syms) {
379 				close(fd);
380 				return;
381 			}
382 			p += hdr.ex.a_syms;
383 			if (read(fd, p, sizeof (int)) != sizeof (int)) {
384 				close(fd);
385 				return;
386 			}
387 			x = *(uint32_t *)p;
388 			p += sizeof (int);
389 			x -= sizeof (int);
390 			if (read(fd, p, x) != x) {
391 				close(fd);
392 				return;
393 			}
394 			p += x;
395 		}
396 	} else {
397 		lseek(fd, hdr.eh.e_phoff, SEEK_SET);
398 		for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
399 			if (read(fd, ep + j, sizeof (ep[0])) !=
400 			    sizeof (ep[0])) {
401 				close(fd);
402 				return;
403 			}
404 			if (ep[j].p_type == PT_LOAD)
405 				j++;
406 		}
407 		for (i = 0; i < 2; i++) {
408 			p = PTOV(ep[i].p_paddr & 0xffffff);
409 			lseek(fd, ep[i].p_offset, SEEK_SET);
410 			if (read(fd, p, ep[i].p_filesz) != ep[i].p_filesz) {
411 				close(fd);
412 				return;
413 			}
414 		}
415 		p += roundup2(ep[1].p_memsz, PAGE_SIZE);
416 		bootinfo.bi_symtab = VTOP(p);
417 		if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
418 			lseek(fd, hdr.eh.e_shoff +
419 			    sizeof (es[0]) * (hdr.eh.e_shstrndx + 1),
420 			    SEEK_SET);
421 			if (read(fd, &es, sizeof (es)) != sizeof (es)) {
422 				close(fd);
423 				return;
424 			}
425 			for (i = 0; i < 2; i++) {
426 				memcpy(p, &es[i].sh_size,
427 				    sizeof (es[i].sh_size));
428 				p += sizeof (es[i].sh_size);
429 				lseek(fd, es[i].sh_offset, SEEK_SET);
430 				if (read(fd, p, es[i].sh_size) !=
431 				    es[i].sh_size) {
432 					close(fd);
433 					return;
434 				}
435 				p += es[i].sh_size;
436 			}
437 		}
438 		addr = hdr.eh.e_entry & 0xffffff;
439 	}
440 	close(fd);
441 
442 	bootinfo.bi_esymtab = VTOP(p);
443 	bootinfo.bi_kernelname = VTOP(kname);
444 
445 	if (bdev->dd.d_dev->dv_type == DEVT_ZFS) {
446 		zfsargs.size = sizeof (zfsargs);
447 		zfsargs.pool = bdev->d_kind.zfs.pool_guid;
448 		zfsargs.root = bdev->d_kind.zfs.root_guid;
449 		__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
450 		    bootdev,
451 		    KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG,
452 		    (uint32_t)bdev->d_kind.zfs.pool_guid,
453 		    (uint32_t)(bdev->d_kind.zfs.pool_guid >> 32),
454 		    VTOP(&bootinfo),
455 		    zfsargs);
456 	} else {
457 		__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
458 		    bootdev, 0, 0, 0, VTOP(&bootinfo));
459 	}
460 }
461 
462 static int
463 mount_root(char *arg)
464 {
465 	char *root;
466 	struct i386_devdesc *ddesc;
467 	uint8_t part;
468 
469 	if (asprintf(&root, "%s:", arg) < 0)
470 		return (1);
471 
472 	if (i386_getdev((void **)&ddesc, root, NULL)) {
473 		free(root);
474 		return (1);
475 	}
476 
477 	/* we should have new device descriptor, free old and replace it. */
478 	free(bdev);
479 	bdev = ddesc;
480 	if (bdev->dd.d_dev->dv_type == DEVT_DISK) {
481 		if (bdev->d_kind.biosdisk.partition == -1)
482 			part = 0xff;
483 		else
484 			part = bdev->d_kind.biosdisk.partition;
485 		bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type],
486 		    bdev->d_kind.biosdisk.slice + 1,
487 		    bdev->dd.d_unit, part);
488 		bootinfo.bi_bios_dev = bd_unit2bios(bdev);
489 	}
490 	strncpy(boot_devname, root, sizeof (boot_devname));
491 	setenv("currdev", root, 1);
492 	free(root);
493 	return (0);
494 }
495 
496 static void
497 fs_list(char *arg)
498 {
499 	int fd;
500 	struct dirent *d;
501 	char line[80];
502 
503 	fd = open(arg, O_RDONLY);
504 	if (fd < 0)
505 		return;
506 	pager_open();
507 	while ((d = readdirfd(fd)) != NULL) {
508 		sprintf(line, "%s\n", d->d_name);
509 		if (pager_output(line))
510 			break;
511 	}
512 	pager_close();
513 	close(fd);
514 }
515 
516 static int
517 parse_cmd(void)
518 {
519 	char *arg = cmd;
520 	char *ep, *p, *q;
521 	const char *cp;
522 	char line[80];
523 	int c, i;
524 
525 	while ((c = *arg++)) {
526 		if (isspace(c))
527 			continue;
528 
529 		for (p = arg; *p != '\0' && !isspace(*p); p++)
530 			;
531 		ep = p;
532 		if (*p != '\0')
533 			*p++ = '\0';
534 		if (c == '-') {
535 			while ((c = *arg++)) {
536 				if (isspace(c))
537 					break;
538 
539 				if (c == 'P') {
540 					if (*(uint8_t *)PTOV(0x496) & 0x10) {
541 						cp = "yes";
542 					} else {
543 						opts |= OPT_SET(RBX_DUAL);
544 						opts |= OPT_SET(RBX_SERIAL);
545 						cp = "no";
546 					}
547 					printf("Keyboard: %s\n", cp);
548 					continue;
549 				} else if (c == 'S') {
550 					char *end;
551 
552 					errno = 0;
553 					i = strtol(arg, &end, 10);
554 					if (errno == 0 &&
555 					    *arg != '\0' &&
556 					    *end == '\0' &&
557 					    i > 0 &&
558 					    i <= 115200) {
559 						comspeed = i;
560 						break;
561 					} else {
562 						printf("warning: bad value for "
563 						    "speed: %s\n", arg);
564 					}
565 					arg = end;
566 					/*
567 					 * Fall through to error below
568 					 * ('S' not in optstr[]).
569 					 */
570 				}
571 				for (i = 0; c != optstr[i]; i++)
572 					if (i == NOPT - 1)
573 						return (-1);
574 				opts ^= OPT_SET(flags[i]);
575 			}
576 			if (OPT_CHECK(RBX_DUAL))
577 				ioctrl = IO_SERIAL | IO_KEYBOARD;
578 			else if (OPT_CHECK(RBX_SERIAL))
579 				ioctrl = IO_SERIAL;
580 			else
581 				ioctrl = IO_KEYBOARD;
582 
583 			if (ioctrl & IO_SERIAL) {
584 				if (sio_init(115200 / comspeed) != 0)
585 					ioctrl &= ~IO_SERIAL;
586 			}
587 		} else if (c == '?') {
588 			printf("\n");
589 			fs_list(arg);
590 			zfs_list(arg);
591 			return (-1);
592 		} else {
593 			arg--;
594 
595 			/*
596 			 * Report pool status if the comment is 'status'. Lets
597 			 * hope no-one wants to load /status as a kernel.
598 			 */
599 			if (strcmp(arg, "status") == 0) {
600 				pager_open();
601 				for (i = 0; devsw[i] != NULL; i++) {
602 					if (devsw[i]->dv_print != NULL) {
603 						if (devsw[i]->dv_print(1))
604 							break;
605 					} else {
606 						sprintf(line,
607 						    "%s: (unknown)\n",
608 						    devsw[i]->dv_name);
609 						if (pager_output(line))
610 							break;
611 					}
612 				}
613 				pager_close();
614 				return (-1);
615 			}
616 
617 			/*
618 			 * If there is a colon, switch pools.
619 			 */
620 			if (strncmp(arg, "zfs:", 4) == 0)
621 				q = strrchr(arg + 4, ':');
622 			else
623 				q = strrchr(arg, ':');
624 
625 			if (q != NULL) {
626 				*q++ = '\0';
627 				if (mount_root(arg) != 0)
628 					return (-1);
629 				arg = q;
630 			}
631 			if ((i = ep - arg)) {
632 				if ((size_t)i >= sizeof (kname))
633 					return (-1);
634 				memcpy(kname, arg, i + 1);
635 			}
636 		}
637 		arg = p;
638 	}
639 	return (0);
640 }
641 
642 /*
643  * probe arguments for partition iterator (see below)
644  */
645 struct probe_args {
646 	int		fd;
647 	char		*devname;
648 	uint_t		secsz;
649 	uint64_t	offset;
650 };
651 
652 /*
653  * simple wrapper around read() to avoid using device specific
654  * strategy() directly.
655  */
656 static int
657 parttblread(void *arg, void *buf, size_t blocks, uint64_t offset)
658 {
659 	struct probe_args *ppa = arg;
660 	size_t size = ppa->secsz * blocks;
661 
662 	lseek(ppa->fd, offset * ppa->secsz, SEEK_SET);
663 	if (read(ppa->fd, buf, size) == size)
664 		return (0);
665 	return (EIO);
666 }
667 
668 /*
669  * scan partition entries to find boot partition starting at start_sector.
670  * in case of MBR partition type PART_SOLARIS2, read VTOC and recurse.
671  */
672 static int
673 probe_partition(void *arg, const char *partname,
674     const struct ptable_entry *part)
675 {
676 	struct probe_args pa, *ppa = arg;
677 	struct ptable *table;
678 	uint64_t *pool_guid_ptr = NULL;
679 	uint64_t pool_guid = 0;
680 	char devname[32];
681 	int len, ret = 0;
682 
683 	len = strlen(ppa->devname);
684 	if (len > sizeof (devname))
685 		len = sizeof (devname);
686 
687 	strncpy(devname, ppa->devname, len - 1);
688 	devname[len - 1] = '\0';
689 	snprintf(devname, sizeof (devname), "%s%s:", devname, partname);
690 
691 	/* filter out partitions *not* used by zfs */
692 	switch (part->type) {
693 	case PART_RESERVED:	/* efi reserverd */
694 	case PART_VTOC_BOOT:	/* vtoc boot area */
695 	case PART_VTOC_SWAP:
696 		return (ret);
697 	default:
698 		break;
699 	}
700 
701 	if (part->type == PART_SOLARIS2) {
702 		pa.offset = part->start;
703 		pa.fd = open(devname, O_RDONLY);
704 		if (pa.fd == -1)
705 			return (ret);
706 		pa.devname = devname;
707 		pa.secsz = ppa->secsz;
708 		table = ptable_open(&pa, part->end - part->start + 1,
709 		    ppa->secsz, parttblread);
710 		if (table != NULL) {
711 			enum ptable_type pt = ptable_gettype(table);
712 
713 			if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) {
714 				ret = ptable_iterate(table, &pa,
715 				    probe_partition);
716 				ptable_close(table);
717 				close(pa.fd);
718 				return (ret);
719 			}
720 			ptable_close(table);
721 		}
722 		close(pa.fd);
723 	}
724 
725 	if (ppa->offset + part->start == start_sector) {
726 		/* Ask zfs_probe_dev to provide guid. */
727 		pool_guid_ptr = &pool_guid;
728 		/* Set up boot device name for non-zfs case. */
729 		strncpy(boot_devname, devname, sizeof (boot_devname));
730 	}
731 
732 	ret = zfs_probe_dev(devname, pool_guid_ptr);
733 	if (pool_guid != 0 && bdev == NULL) {
734 		bdev = malloc(sizeof (struct i386_devdesc));
735 		bzero(bdev, sizeof (struct i386_devdesc));
736 		bdev->dd.d_dev = &zfs_dev;
737 		bdev->d_kind.zfs.pool_guid = pool_guid;
738 
739 		/*
740 		 * We can not set up zfs boot device name yet, as the
741 		 * zfs dv_init() is not completed. We will set boot_devname
742 		 * in main, after devsw setup.
743 		 */
744 	}
745 
746 	return (0);
747 }
748 
749 /*
750  * open partition table on disk and scan partition entries to find
751  * boot partition starting at start_sector (recorded by installboot).
752  */
753 static int
754 probe_disk(char *devname)
755 {
756 	struct ptable *table;
757 	struct probe_args pa;
758 	uint64_t mediasz;
759 	int ret;
760 
761 	pa.offset = 0;
762 	pa.devname = devname;
763 	pa.fd = open(devname, O_RDONLY);
764 	if (pa.fd == -1) {
765 		return (ENXIO);
766 	}
767 
768 	ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
769 	if (ret == 0)
770 		ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
771 	if (ret == 0) {
772 		table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
773 		    parttblread);
774 		if (table != NULL) {
775 			ret = ptable_iterate(table, &pa, probe_partition);
776 			ptable_close(table);
777 		}
778 	}
779 	close(pa.fd);
780 	return (ret);
781 }
782 
783 /*
784  * Probe all disks to discover ZFS pools. The idea is to walk all possible
785  * disk devices, however, we also need to identify possible boot pool.
786  * For boot pool detection we have boot disk passed us from BIOS, recorded
787  * in bootinfo.bi_bios_dev, and start_sector LBA recorded by installboot.
788  *
789  * To detect boot pool, we can not use generic zfs_probe_dev() on boot disk,
790  * but we need to walk partitions, as we have no way to pass start_sector
791  * to zfs_probe_dev(). Note we do need to detect the partition correcponding
792  * to non-zfs case, so here we can set boot_devname for both cases.
793  */
794 static void
795 i386_zfs_probe(void)
796 {
797 	char devname[32];
798 	int boot_unit;
799 	struct i386_devdesc dev;
800 
801 	dev.dd.d_dev = &bioshd;
802 	/* Translate bios dev to our unit number. */
803 	boot_unit = bd_bios2unit(bootinfo.bi_bios_dev);
804 
805 	/*
806 	 * Open all the disks we can find and see if we can reconstruct
807 	 * ZFS pools from them.
808 	 */
809 	for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) {
810 		snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name,
811 		    dev.dd.d_unit);
812 		/* If this is not boot disk, use generic probe. */
813 		if (dev.dd.d_unit != boot_unit)
814 			zfs_probe_dev(devname, NULL);
815 		else
816 			probe_disk(devname);
817 	}
818 }
819