1 /**	$MirOS: src/sys/arch/i386/stand/libsa/biosdev.c,v 1.47 2012/12/23 19:19:48 tg Exp $ */
2 /*	$OpenBSD: biosdev.c,v 1.74 2008/06/25 15:32:18 reyk Exp $	*/
3 
4 /*
5  * Copyright (c) 1996 Michael Shalayeff
6  * Copyright (c) 2003 Tobias Weingartner
7  * Copyright (c) 2002, 2003, 2004, 2005, 2008, 2009, 2012
8  *	Thorsten "mirabilos" Glaser <tg@mirbsd.org>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/param.h>
35 #include <sys/reboot.h>
36 #include <sys/disklabel.h>
37 #include <machine/tss.h>
38 #include <machine/biosvar.h>
39 #include <lib/libsa/saerrno.h>
40 #include <lib/libsa/ustar.h>
41 #include <isofs/cd9660/iso.h>
42 #include "disk.h"
43 #include "debug.h"
44 #include "libsa.h"
45 #include "biosdev.h"
46 
47 const char *biosdisk_err(u_int);
48 int biosdisk_errno(u_int);
49 
50 extern int biosdev_lbaprobe(int drive);
51 extern int biosdev_CHS(int ah, int dev, int cyl, int head, int sec, int nsec);
52 extern int biosdev_LBA(int ah, int dev, u_int blk_lo, u_int blk_hi, int nsec);
53 
54 extern int debug;
55 int i386_flag_oldbios = 0;
56 
57 /*
58  * reset disk system
59  */
60 int
biosdreset(int dev)61 biosdreset(int dev)
62 {
63 	int rv;
64 
65 	__asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
66 	    : "0" (0), "d" (dev) : "%ecx", "cc");
67 
68 	return ((rv & 0xff)? rv >> 8 : 0);
69 }
70 
71 /*
72  * Fill out a bios_diskinfo_t for this device.
73  * Return 0 if all ok.
74  * Return 1 if not ok.
75  */
76 int
bios_getdiskinfo(int dev,bios_diskinfo_t * pdi)77 bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
78 {
79 	u_int rv;
80 	int lback;
81 
82 	/* kernel interface, binary compatibility */
83 	pdi->old_bios_edd = -1;
84 
85 	pdi->flags &= ~(BDI_LBA | BDI_EL_TORITO);
86 	lback = biosdev_lbaprobe(dev);
87 
88 	/* Just reset, don't check return code */
89 	rv = biosdreset(dev);
90 
91 	if (lback & 0x10) {
92 		pdi->bios_number = dev;
93 		/* CD-ROM, we don’t care what the BIOS says for CHS or LBA */
94 		pdi->bios_heads = 16;
95 		pdi->bios_cylinders = 16;
96 		pdi->bios_sectors = 32;
97 		/* https://www.mirbsd.org/permalinks/news_e20090126-tg.htm */
98 		pdi->flags |= BDI_LBA | BDI_EL_TORITO;
99 		pdi->old_bios_edd = (lback | 9) & 7;
100 		return (0);
101 	}
102 
103 #ifdef BIOS_DEBUG
104 	if (debug)
105 		printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
106 #endif
107 	__asm __volatile (DOINT(0x13) "\n\t"
108 	    "setc %b0; movzbl %h1, %1\n\t"
109 	    "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
110 	    "xchgb %%cl, %%ch; rolb $2, %%ch"
111 	    : "=a" (rv), "=d" (pdi->bios_heads),
112 	      "=c" (pdi->bios_cylinders),
113 	      "=b" (pdi->bios_sectors)
114 	    : "0" (0x0800), "1" (dev) : "cc");
115 
116 #ifdef BIOS_DEBUG
117 	if (debug) {
118 		printf("getinfo: got #8\n");
119 		printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
120 		    pdi->bios_heads, pdi->bios_sectors);
121 	}
122 #endif
123 
124 	if (rv & 0xFF) {
125 		if ((lback & 0x09) != 0x09)
126 			return (1);
127 		printf("bios_getdiskinfo(%X): LBA but no CHS: %X\n", dev, lback);
128 		pdi->bios_heads = 15;
129 		pdi->bios_cylinders = 15;
130 		pdi->bios_sectors = 63;
131 	}
132 
133 	/* Fix up info */
134 	pdi->bios_number = dev;
135 	pdi->bios_heads++;
136 	pdi->bios_cylinders &= 0x3ff;
137 	pdi->bios_cylinders++;
138 
139 	if ((lback & 0x09) == 0x09) {
140 		pdi->flags |= BDI_LBA;
141 		pdi->old_bios_edd = lback & 7;
142 	} else if (pdi->bios_cylinders < 2 || pdi->bios_heads < 2 ||
143 	    pdi->bios_sectors < 1) {
144 #ifdef BIOS_DEBUG
145 		printf("sanity: c/h/s values insane: %d/%d/%d\n",
146 		    pdi->bios_cylinders, pdi->bios_heads, pdi->bios_sectors);
147 #endif
148 		return (1);
149 	}
150 
151 	return (0);
152 }
153 
154 /*
155  * Read given sector, handling retry/errors/etc.
156  */
157 int
biosd_io(int rw,bios_diskinfo_t * bd,daddr_t off,int nsect,void * buf)158 biosd_io(int rw, bios_diskinfo_t *bd, daddr_t off, int nsect, void *buf)
159 {
160 	int rv, n, ssh = 0, i, spre = 0;
161 	volatile int c, h, s; /* fsck gcc, uninitialised it is not */
162 
163 #ifndef SMALL_BOOT
164 	/* we do all I/O in 512 byte sectors, the El Torito BIOS doesn't */
165 	if (bd->flags & BDI_EL_TORITO) {
166 		ssh = 2;	/* sector shift */
167 		/* read only part of a CD sector */
168 		if (off & 3) {
169 			spre = off & 3;
170 			off -= spre;
171 			nsect += spre;
172 		}
173 		/* odd nsect does not matter, we read CDs one by one */
174 	}
175 #endif
176 
177  loop:
178 	n = (ssh || i386_flag_oldbios) ? 1 << ssh : MIN(nsect, 4096/512);
179 	if (!(bd->flags & BDI_LBA)) {
180 		/* note: BDI_EL_TORITO implies BDI_LBA, d/w about ssh here */
181 		btochs(off, c, h, s, bd->bios_heads, bd->bios_sectors);
182 		if (s + n >= bd->bios_sectors)
183 			n = bd->bios_sectors - s;
184 	}
185 	if ((buf || spre) && rw != F_READ)
186 		memmove(bounce_buf + spre * 512, buf ? buf : bounce_buf,
187 		    MIN(n - spre, nsect) * 512);
188 	/* try operation up to 5 times */
189 	rv = 1;
190 	i = 5;
191 	while (rv && i--) {
192 		if (bd->flags & BDI_LBA) {
193 #if 0
194 			printf(" trying biosdev_LBA(%X, %X, %d, %d, %d)",
195 			    rw == F_READ ? 0x42 : 0x43, bd->bios_number,
196 			    (int)((off >> ssh) & 0xFFFFFFFF),
197 			    (int)(sizeof (daddr_t) > 4 ?
198 			    (off >> ssh) >> 32 : 0), n >> ssh);
199 #endif
200 			rv = biosdev_LBA(rw == F_READ ? 0x42 : 0x43,
201 			    bd->bios_number, (off >> ssh) & 0xFFFFFFFF,
202 			    sizeof (daddr_t) > 4 ? (off >> ssh) >> 32 : 0,
203 			    n >> ssh);
204 		} else {
205 #if 0
206 			printf(" trying biosdev_CHS(%X, %X, %d, %d, %d, %d)",
207 			    rw == F_READ ? 0x02 : 0x03, bd->bios_number,
208 			    c, h, s, n);
209 #endif
210 			rv = biosdev_CHS(rw == F_READ ? 0x02 : 0x03,
211 			    bd->bios_number, c, h, s, n);
212 		}
213 /*		printf(" => %X\n", rv);	*/
214 		switch (rv) {
215 		case 0x11:	/* ECC corrected */
216 			rv = 0;
217 		case 0x00:	/* no errors */
218 			break;
219 		default:	/* all other errors */
220 #ifdef BIOS_DEBUG
221 			if (debug)
222 				printf("\nBIOS error 0x%X (%s)\n",
223 				    rv, biosdisk_err(rv));
224 #endif
225 			biosdreset(bd->bios_number);
226 			break;
227 		}
228 	}
229 #ifdef BIOS_DEBUG
230 	if (debug) {
231 		if (rv != 0)
232 			printf("=0x%x(%s)", rv, biosdisk_err(rv));
233 		putchar('\n');
234 	}
235 #endif
236 	if (rv)
237 		return (rv);
238 	if ((buf || spre) && rw == F_READ)
239 		memmove(buf ? buf : bounce_buf, bounce_buf + spre * 512,
240 		    MIN(n - spre, nsect) * 512);
241 	if ((nsect -= n) <= 0)
242 		return (0);
243 	if (!buf) {
244 #ifndef SMALL_BOOT
245 		printf("panic: cannot loop biosd_io on bounce_buf\n");
246 #endif
247 		return (0);
248 	}
249 	buf += (n - spre) * 512;
250 	off += n;
251 	spre = 0;
252 	goto loop;
253 }
254 
255 /*
256  * Try to read the bsd label on the given BIOS device
257  */
258 const char *
bios_getdisklabel(bios_diskinfo_t * bd,struct disklabel * label)259 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
260 {
261 	daddr_t off = 0;
262 	struct dos_mbr *mbr = (struct dos_mbr *)bounce_buf;
263 	int error, i;
264 	long mbrofs;
265 
266 	/* Sanity check */
267 	if (bd->bios_heads == 0 || bd->bios_sectors == 0)
268 		return ("failed to read disklabel");
269 
270 	/* MBR is a harddisk thing */
271 	if (bd->bios_number & 0x80) {
272 		/* Read MBR */
273 		mbrofs = DOSBBSECTOR;
274  loop:
275 		error = biosd_io(F_READ, bd, mbrofs, 1, NULL);
276 		if (error)
277 			return (biosdisk_err(error));
278 
279 		if (!memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
280 		    ustar_magic_version, sizeof(ustar_magic_version)))
281 			return "found ustar magic\n";
282 
283 		/* check mbr signature */
284 		if (mbr->dmbr_sign != DOSMBR_SIGNATURE)
285 			return "bad MBR signature\n";
286 
287 		/* extend all start offsets by mbrofs */
288 		for (i = 0; i < NDOSPART; i++)
289 			mbr->dmbr_parts[i].dp_start += mbrofs;
290 
291 		/* Search for MirBSD partition */
292 		if (i386_userpt) for (i = 0; off == 0 && i < NDOSPART; i++)
293 			if (mbr->dmbr_parts[i].dp_typ == i386_userpt)
294 				off = i + 1;
295 		if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
296 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_MIRBSD)
297 				off = i + 1;
298 
299 		/* just in case */
300 		if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
301 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_OPENBSD)
302 				off = i + 1;
303 
304 		/* just in case */
305 		if (!off) for (i = 0; off == 0 && i < NDOSPART; i++)
306 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_NETBSD)
307 				off = i + 1;
308 
309 		/* just in case */
310 		if (!off) {
311 		    for (i = 0; off == 0 && i < NDOSPART; i++)
312 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTEND) {
313 				mbrofs = mbr->dmbr_parts[i].dp_start;
314 				goto loop;
315 			}
316 		    for (i = 0; off == 0 && i < NDOSPART; i++)
317 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTENDL) {
318 				mbrofs = mbr->dmbr_parts[i].dp_start;
319 				goto loop;
320 			}
321 		    for (i = 0; off == 0 && i < NDOSPART; i++)
322 			if (mbr->dmbr_parts[i].dp_typ == DOSPTYP_EXTENDLX) {
323 				mbrofs = mbr->dmbr_parts[i].dp_start;
324 				goto loop;
325 			}
326 		}
327 	}
328 	if (off) {
329 		off = mbr->dmbr_parts[off - 1].dp_start + LABELSECTOR;
330 	} else
331 		off = LABELSECTOR;
332 
333 	/* Load BSD disklabel */
334 #ifdef BIOS_DEBUG
335 	if (debug)
336 		printf("loading disklabel @ %u\n", off);
337 #endif
338 	/* read disklabel */
339 	error = biosd_io(F_READ, bd, off, 1, NULL);
340 
341 	if (error)
342 		return ("failed to read disklabel");
343 
344 	/* Fill in disklabel */
345 	return (getdisklabel(bounce_buf, label));
346 }
347 
348 int
biosopen(struct open_file * f,...)349 biosopen(struct open_file *f, ...)
350 {
351 	va_list ap;
352 	register char *cp, **file;
353 	dev_t unit, part;
354 	struct diskinfo *dip;
355 	int i;
356 
357 	va_start(ap, f);
358 	file = va_arg(ap, char **);
359 	va_end(ap);
360 
361 	if (file == NULL || (cp = *file) == NULL)
362 		return (EINVAL);
363 
364 #ifdef BIOS_DEBUG
365 	if (debug)
366 		printf("biosopen(%s)\n", cp);
367 #endif
368 
369 	f->f_devdata = NULL;
370 
371 	/* search for device specification */
372 	while (*cp != ':' && *cp)
373 		++cp;
374 	if (*cp == '\0' || cp - *file < 2) {
375 		cp = *file;
376 		goto nodevspec;
377 	}
378 
379 	for (dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
380 		if (!strncmp(*file, dip->name, cp - *file - 1))
381 			break;
382 	if (!dip) {
383 		cp = *file;
384 		goto nodevspec;
385 	}
386 
387 	/* get partition */
388 	unit = cp[-2] - '0';
389 	part = cp[-1] - 'a';
390 	++cp;
391 
392 	bootdev_dip = dip;
393 
394 	/* Fix up bootdev */
395 	{ dev_t bsd_dev;
396 		bsd_dev = dip->bios_info.bsd_dev;
397 		dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
398 		    B_CONTROLLER(bsd_dev), unit, part);
399 		dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
400 		    B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
401 	}
402 
403  nodevspec:
404 	if ((dip = bootdev_dip) == NULL)
405 		if ((dip = bootdev_dip = start_dip) == NULL)
406 			return (EADAPT);
407 
408 #ifdef BIOS_DEBUG
409 	if (debug) {
410 		printf("BIOS geometry: heads=%u, s/t=%u; EDD=%s\n",
411 		    dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
412 		    dip->bios_info.flags & BDI_LBA ? "on" : "off");
413 	}
414 #endif
415 
416 	/* Try for disklabel again (might be removable media) */
417 	if ((i = disk_trylabel(dip)))
418 		return (i);
419 
420 	f->f_devdata = dip;
421 
422 	if (*cp != 0)
423 		*file = cp;
424 	else
425 		f->f_flags |= F_RAW;
426 
427 	return 0;
428 }
429 
430 const u_char bidos_errs[] =
431 #ifndef SMALL_BOOT
432 /* ignored	"\x00" "successful completion\0" */
433 		"\x01" "invalid function/parameter\0"
434 		"\x02" "address mark not found\0"
435 		"\x03" "write-protected\0"
436 		"\x04" "sector not found\0"
437 		"\x05" "reset failed\0"
438 		"\x06" "disk changed\0"
439 		"\x07" "drive parameter activity failed\0"
440 		"\x08" "DMA overrun\0"
441 		"\x09" "data boundary error\0"
442 		"\x0A" "bad sector detected\0"
443 		"\x0B" "bad track detected\0"
444 		"\x0C" "invalid media\0"
445 		"\x0E" "control data address mark detected\0"
446 		"\x0F" "DMA arbitration level out of range\0"
447 		"\x10" "uncorrectable CRC or ECC error on read\0"
448 /* ignored	"\x11" "data ECC corrected\0" */
449 		"\x20" "controller failure\0"
450 		"\x31" "no media in drive\0"
451 		"\x32" "incorrect drive type in CMOS\0"
452 		"\x40" "seek failed\0"
453 		"\x80" "operation timed out\0"
454 		"\xAA" "drive not ready\0"
455 		"\xB0" "volume not locked in drive\0"
456 		"\xB1" "volume locked in drive\0"
457 		"\xB2" "volume not removable\0"
458 		"\xB3" "volume in use\0"
459 		"\xB4" "lock count exceeded\0"
460 		"\xB5" "valid eject request failed\0"
461 		"\xBB" "undefined error\0"
462 		"\xCC" "write fault\0"
463 		"\xE0" "status register error\0"
464 		"\xFF" "sense operation failed\0"
465 #endif
466 		"\x00" "\0";
467 
468 const char *
biosdisk_err(u_int error)469 biosdisk_err(u_int error)
470 {
471 	register const u_char *p = bidos_errs;
472 
473 	while (*p && *p != error)
474 		while (*p++);
475 
476 	return ++p;
477 }
478 
479 const struct biosdisk_errors {
480 	u_char error;
481 	u_char errno;
482 } tab[] = {
483 	{ 0x01, EINVAL },
484 	{ 0x03, EROFS },
485 	{ 0x08, EINVAL },
486 	{ 0x09, EINVAL },
487 	{ 0x0A, EBSE },
488 	{ 0x0B, EBSE },
489 	{ 0x0C, ENXIO },
490 	{ 0x0D, EINVAL },
491 	{ 0x10, EECC },
492 	{ 0x20, EHER },
493 	{ 0x31, ENXIO },
494 	{ 0x32, ENXIO },
495 	{ 0x00, EIO }
496 };
497 
498 int
biosdisk_errno(u_int error)499 biosdisk_errno(u_int error)
500 {
501 	register const struct biosdisk_errors *p;
502 
503 	if (error == 0)
504 		return 0;
505 
506 	for (p = tab; p->error && p->error != error; p++);
507 
508 	return p->errno;
509 }
510 
511 int
biosstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)512 biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
513     size_t *rsize)
514 {
515 	struct diskinfo *dip = (struct diskinfo *)devdata;
516 	bios_diskinfo_t *bd = &dip->bios_info;
517 	u_int8_t error = 0;
518 	size_t nsect;
519 
520 	nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
521 	if (rsize != NULL)
522 		blk += dip->disklabel.
523 			d_partitions[B_PARTITION(dip->bsddev)].p_offset;
524 
525 	/* Read all, sub-functions handle track boundaries */
526 	error = biosd_io(rw, bd, blk, nsect, buf);
527 
528 #ifdef BIOS_DEBUG
529 	if (debug) {
530 		if (error != 0)
531 			printf("=0x%x(%s)", error, biosdisk_err(error));
532 		putchar('\n');
533 	}
534 #endif
535 
536 	if (rsize != NULL)
537 		*rsize = nsect * DEV_BSIZE;
538 
539 	return (biosdisk_errno(error));
540 }
541 
542 int
biosclose(struct open_file * f)543 biosclose(struct open_file *f)
544 {
545 	f->f_devdata = NULL;
546 
547 	return 0;
548 }
549 
550 int
biosioctl(struct open_file * f,u_long cmd,void * data)551 biosioctl(struct open_file *f, u_long cmd, void *data)
552 {
553 	return 0;
554 }
555 
556 int
disk_trylabel(struct diskinfo * dip)557 disk_trylabel(struct diskinfo *dip)
558 {
559 	const char *st = NULL;
560 	bios_diskinfo_t *bd = &dip->bios_info;
561 	struct dos_mbr *mbr = (struct dos_mbr *)bounce_buf;
562 	int i, totsiz;
563 
564 	if (dip->bios_info.flags & BDI_GOODLABEL)
565 		return (0);
566 
567 	if (dip->bios_info.flags & BDI_BADLABEL) {
568 		st = bios_getdisklabel(&dip->bios_info, &dip->disklabel);
569 		if (st == NULL)
570 			dip->bios_info.flags &= ~BDI_BADLABEL;
571 	}
572 
573 	if (dip->bios_info.flags & BDI_BADLABEL ||
574 	    !(dip->bios_info.flags & BDI_GOODLABEL)) {
575 #ifndef SMALL_BOOT
576 		int maybe_sun = 0;
577 
578 		/* create an imaginary disk label */
579 
580 		st = "failed to read disklabel";
581 		if (bd->bios_heads == 0 || bd->bios_sectors == 0)
582 			goto out;
583 
584 		totsiz = 2880;
585 
586 		if (!(bd->bios_number & 0x80) || bd->flags & BDI_EL_TORITO ||
587 		    (bios_bootpte.active & 0x7F) /* || !bios_bootpte.partyp */)
588 			bios_bootpte.partyp = 0;
589 		if (bd->bios_number & 0x80) {
590 			/* read MBR */
591 			i = biosd_io(F_READ, bd, DOSBBSECTOR, 1, NULL);
592 			if (i)
593 				goto nombr;
594 			if (!memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
595 			    ustar_magic_version, sizeof(ustar_magic_version)))
596 				goto nombr;
597 			if (mbr->dmbr_sign != DOSMBR_SIGNATURE)
598 				goto nombr;
599 			if (bounce_buf[0x1FC] == 0xDA &&
600 			    bounce_buf[0x1FD] == 0xBE) {
601 				for (i = 0x080; i < 0x088; ++i)
602 					if (bounce_buf[i])
603 						break;
604 				if (i == 0x088) {
605 					maybe_sun = 1;
606 					bios_bootpte.partyp = 0;
607 				}
608 			}
609 			for (i = 0; i < NDOSPART; i++)
610 				if (mbr->dmbr_parts[i].dp_typ &&
611 				    (mbr->dmbr_parts[i].dp_start +
612 				    mbr->dmbr_parts[i].dp_size > totsiz))
613 					totsiz = mbr->dmbr_parts[i].dp_start +
614 					    mbr->dmbr_parts[i].dp_size;
615 			goto mbrok;
616 		}
617  nombr:
618 		for (i = 0; i < NDOSPART; i++)
619 			mbr->dmbr_parts[i].dp_typ = 0;
620  mbrok:
621 
622 		dip->disklabel.d_secsize = 512;
623 		dip->disklabel.d_ntracks = bd->bios_heads;
624 		dip->disklabel.d_nsectors = bd->bios_sectors;
625 		dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
626 		    dip->disklabel.d_nsectors;
627 		totsiz += dip->disklabel.d_secpercyl - 1;
628 		dip->disklabel.d_ncylinders = totsiz /
629 		    dip->disklabel.d_secpercyl;
630 		memcpy(dip->disklabel.d_typename, "FAKE", 5);
631 		dip->disklabel.d_type = DTYPE_VND;
632 		strncpy(dip->disklabel.d_packname, "fictitious",
633 		    sizeof (dip->disklabel.d_packname));
634 		dip->disklabel.d_secperunit = dip->disklabel.d_ncylinders *
635 		    dip->disklabel.d_secpercyl;
636 		totsiz = dip->disklabel.d_secperunit;
637 		dip->disklabel.d_rpm = 3600;
638 		dip->disklabel.d_interleave = 1;
639 
640 		dip->disklabel.d_bbsize = 8192;
641 		dip->disklabel.d_sbsize = 65536;
642 
643 		bzero(dip->disklabel.d_partitions,
644 		    sizeof (dip->disklabel.d_partitions));
645 
646 		if (bios_bootpte.partyp &&
647 		    (bios_bootpte.p_ofs || bios_bootpte.p_siz)) {
648 			/* 'a' partition passed from MBR/SYSLINUX */
649 			dip->disklabel.d_partitions[0].p_offset = bios_bootpte.p_ofs;
650 			dip->disklabel.d_partitions[0].p_size = bios_bootpte.p_siz;
651 			dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
652 		} else {
653 			/* 'a' partition covering the "whole" disk */
654 			dip->disklabel.d_partitions[0].p_offset = 0;
655 			dip->disklabel.d_partitions[0].p_size = totsiz;
656 			dip->disklabel.d_partitions[0].p_fstype =
657 			    maybe_sun ? FS_MANUAL : FS_OTHER;
658 		}
659 
660 		/* The raw partition is special */
661 		dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
662 		dip->disklabel.d_partitions[RAW_PART].p_size = totsiz;
663 		dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
664 
665 		for (i = 0; i < NDOSPART; i++) {
666 			if (!mbr->dmbr_parts[i].dp_typ)
667 				continue;
668 			dip->disklabel.d_partitions[RAW_PART+i+1].p_offset =
669 			    mbr->dmbr_parts[i].dp_start;
670 			dip->disklabel.d_partitions[RAW_PART+i+1].p_size =
671 			    mbr->dmbr_parts[i].dp_size;
672 			dip->disklabel.d_partitions[RAW_PART+i+1].p_fstype =
673 			    FS_MANUAL;
674 			if (dip->disklabel.d_partitions[0].p_fstype ==
675 			    FS_MANUAL)
676 				continue;
677 			/* a GUID Partition Table cannot become 'a' slice */
678 			if (mbr->dmbr_parts[i].dp_typ == 0xEE)
679 				continue;
680 			/* 'a' partition covering the first partition */
681 			dip->disklabel.d_partitions[0].p_offset =
682 			    mbr->dmbr_parts[i].dp_start;
683 			dip->disklabel.d_partitions[0].p_size =
684 			    mbr->dmbr_parts[i].dp_size;
685 			dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
686 		}
687 #else /* SMALL_BOOT */
688 		/* check if ustar, if so fake a disklabel */
689 
690 		st = "failed to read disklabel";
691 		if (bd->bios_heads == 0 || bd->bios_sectors == 0)
692 			goto out;
693 
694 		totsiz = 2880;
695 
696 		i = biosd_io(F_READ, bd, DOSBBSECTOR, 1, NULL);
697 		if (i)
698 			goto out;
699 		if (memcmp((char *)mbr + offsetof(ustar_hdr_t, magic),
700 		    ustar_magic_version, sizeof(ustar_magic_version)))
701 			goto out;
702 
703 		dip->disklabel.d_secsize = 512;
704 		dip->disklabel.d_ntracks = bd->bios_heads;
705 		dip->disklabel.d_nsectors = bd->bios_sectors;
706 		dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks *
707 		    dip->disklabel.d_nsectors;
708 		totsiz += dip->disklabel.d_secpercyl - 1;
709 		dip->disklabel.d_ncylinders = totsiz /
710 		    dip->disklabel.d_secpercyl;
711 		memcpy(dip->disklabel.d_typename, "FAKE", 5);
712 		dip->disklabel.d_type = DTYPE_VND;
713 		strncpy(dip->disklabel.d_packname, "fictitious",
714 		    sizeof (dip->disklabel.d_packname));
715 		dip->disklabel.d_secperunit = dip->disklabel.d_ncylinders *
716 		    dip->disklabel.d_secpercyl;
717 		totsiz = dip->disklabel.d_secperunit;
718 		dip->disklabel.d_rpm = 300;
719 		dip->disklabel.d_interleave = 1;
720 
721 		dip->disklabel.d_bbsize = 8192;
722 		dip->disklabel.d_sbsize = 65536;
723 
724 		bzero(dip->disklabel.d_partitions,
725 		    sizeof (dip->disklabel.d_partitions));
726 
727 		/* 'a' partition covering the "whole" disk */
728 		dip->disklabel.d_partitions[0].p_offset = 0;
729 		dip->disklabel.d_partitions[0].p_size = totsiz;
730 		dip->disklabel.d_partitions[0].p_fstype = FS_MANUAL;
731 
732 		/* The raw partition is special */
733 		dip->disklabel.d_partitions[RAW_PART].p_offset = 0;
734 		dip->disklabel.d_partitions[RAW_PART].p_size = totsiz;
735 		dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED;
736 #endif
737 		dip->disklabel.d_npartitions = MAXPARTITIONS;
738 
739 		dip->disklabel.d_magic = DISKMAGIC;
740 		dip->disklabel.d_magic2 = DISKMAGIC;
741 		dip->disklabel.d_checksum = dkcksum(&dip->disklabel);
742 
743 		dip->bios_info.flags &= ~BDI_BADLABEL;
744 		dip->bios_info.flags |= BDI_GOODLABEL;
745 		st = NULL;
746 	}
747  out:
748 	if ((dip->bios_info.flags & BDI_BADLABEL) && st == NULL)
749 		st = "*none*";
750 	if (st != NULL) {
751 		printf("%s\n", st);
752 		return ERDLAB;
753 	}
754 
755 	return (0);
756 }
757