xref: /freebsd/stand/i386/libi386/biosdisk.c (revision a6578a04e440f79f3b913660221caa9cde3e722c)
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 /*
32  * BIOS disk device handling.
33  *
34  * Ideas and algorithms from:
35  *
36  * - NetBSD libi386/biosdisk.c
37  * - FreeBSD biosboot/disk.c
38  *
39  */
40 
41 #include <sys/disk.h>
42 #include <sys/limits.h>
43 #include <sys/queue.h>
44 #include <stand.h>
45 #include <machine/bootinfo.h>
46 #include <stdarg.h>
47 #include <stdbool.h>
48 
49 #include <bootstrap.h>
50 #include <btxv86.h>
51 #include <edd.h>
52 #include "disk.h"
53 #include "libi386.h"
54 
55 #define	BIOS_NUMDRIVES		0x475
56 #define	BIOSDISK_SECSIZE	512
57 #define	BUFSIZE			(1 * BIOSDISK_SECSIZE)
58 
59 #define	DT_ATAPI	0x10	/* disk type for ATAPI floppies */
60 #define	WDMAJOR		0	/* major numbers for devices we frontend for */
61 #define	WFDMAJOR	1
62 #define	FDMAJOR		2
63 #define	DAMAJOR		4
64 #define	ACDMAJOR	117
65 #define	CDMAJOR		15
66 
67 #ifdef DISK_DEBUG
68 #define	DEBUG(fmt, args...)	printf("%s: " fmt "\n", __func__, ## args)
69 #else
70 #define	DEBUG(fmt, args...)
71 #endif
72 
73 struct specification_packet {
74 	uint8_t		sp_size;
75 	uint8_t		sp_bootmedia;
76 	uint8_t		sp_drive;
77 	uint8_t		sp_controller;
78 	uint32_t	sp_lba;
79 	uint16_t	sp_devicespec;
80 	uint16_t	sp_buffersegment;
81 	uint16_t	sp_loadsegment;
82 	uint16_t	sp_sectorcount;
83 	uint16_t	sp_cylsec;
84 	uint8_t		sp_head;
85 };
86 
87 /*
88  * List of BIOS devices, translation from disk unit number to
89  * BIOS unit number.
90  */
91 typedef struct bdinfo
92 {
93 	STAILQ_ENTRY(bdinfo)	bd_link;	/* link in device list */
94 	int		bd_unit;	/* BIOS unit number */
95 	int		bd_cyl;		/* BIOS geometry */
96 	int		bd_hds;
97 	int		bd_sec;
98 	int		bd_flags;
99 #define	BD_MODEINT13	0x0000
100 #define	BD_MODEEDD1	0x0001
101 #define	BD_MODEEDD3	0x0002
102 #define	BD_MODEEDD	(BD_MODEEDD1 | BD_MODEEDD3)
103 #define	BD_MODEMASK	0x0003
104 #define	BD_FLOPPY	0x0004
105 #define	BD_CDROM	0x0008
106 #define	BD_NO_MEDIA	0x0010
107 	int		bd_type;	/* BIOS 'drive type' (floppy only) */
108 	uint16_t	bd_sectorsize;	/* Sector size */
109 	uint64_t	bd_sectors;	/* Disk size */
110 	int		bd_open;	/* reference counter */
111 	void		*bd_bcache;	/* buffer cache data */
112 } bdinfo_t;
113 
114 #define	BD_RD		0
115 #define	BD_WR		1
116 
117 typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t;
118 static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
119 static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
120 static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
121 
122 static void bd_io_workaround(bdinfo_t *);
123 static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int);
124 static bool bd_int13probe(bdinfo_t *);
125 
126 static int bd_init(void);
127 static int cd_init(void);
128 static int fd_init(void);
129 static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
130     char *buf, size_t *rsize);
131 static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
132     char *buf, size_t *rsize);
133 static int bd_open(struct open_file *f, ...);
134 static int bd_close(struct open_file *f);
135 static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
136 static int bd_print(int verbose);
137 static int cd_print(int verbose);
138 static int fd_print(int verbose);
139 
140 struct devsw biosfd = {
141 	.dv_name = "fd",
142 	.dv_type = DEVT_FD,
143 	.dv_init = fd_init,
144 	.dv_strategy = bd_strategy,
145 	.dv_open = bd_open,
146 	.dv_close = bd_close,
147 	.dv_ioctl = bd_ioctl,
148 	.dv_print = fd_print,
149 	.dv_cleanup = NULL
150 };
151 
152 struct devsw bioscd = {
153 	.dv_name = "cd",
154 	.dv_type = DEVT_CD,
155 	.dv_init = cd_init,
156 	.dv_strategy = bd_strategy,
157 	.dv_open = bd_open,
158 	.dv_close = bd_close,
159 	.dv_ioctl = bd_ioctl,
160 	.dv_print = cd_print,
161 	.dv_cleanup = NULL
162 };
163 
164 struct devsw bioshd = {
165 	.dv_name = "disk",
166 	.dv_type = DEVT_DISK,
167 	.dv_init = bd_init,
168 	.dv_strategy = bd_strategy,
169 	.dv_open = bd_open,
170 	.dv_close = bd_close,
171 	.dv_ioctl = bd_ioctl,
172 	.dv_print = bd_print,
173 	.dv_cleanup = NULL
174 };
175 
176 static bdinfo_list_t *
177 bd_get_bdinfo_list(struct devsw *dev)
178 {
179 	if (dev->dv_type == DEVT_DISK)
180 		return (&hdinfo);
181 	if (dev->dv_type == DEVT_CD)
182 		return (&cdinfo);
183 	if (dev->dv_type == DEVT_FD)
184 		return (&fdinfo);
185 	return (NULL);
186 }
187 
188 /* XXX this gets called way way too often, investigate */
189 static bdinfo_t *
190 bd_get_bdinfo(struct devdesc *dev)
191 {
192 	bdinfo_list_t *bdi;
193 	bdinfo_t *bd = NULL;
194 	int unit;
195 
196 	bdi = bd_get_bdinfo_list(dev->d_dev);
197 	if (bdi == NULL)
198 		return (bd);
199 
200 	unit = 0;
201 	STAILQ_FOREACH(bd, bdi, bd_link) {
202 		if (unit == dev->d_unit)
203 			return (bd);
204 		unit++;
205 	}
206 	return (bd);
207 }
208 
209 /*
210  * Translate between BIOS device numbers and our private unit numbers.
211  */
212 int
213 bd_bios2unit(int biosdev)
214 {
215 	bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL };
216 	bdinfo_t *bd;
217 	int i, unit;
218 
219 	DEBUG("looking for bios device 0x%x", biosdev);
220 	for (i = 0; bdi[i] != NULL; i++) {
221 		unit = 0;
222 		STAILQ_FOREACH(bd, bdi[i], bd_link) {
223 			if (bd->bd_unit == biosdev) {
224 				DEBUG("bd unit %d is BIOS device 0x%x", unit,
225 				    bd->bd_unit);
226 				return (unit);
227 			}
228 			unit++;
229 		}
230 	}
231 	return (-1);
232 }
233 
234 int
235 bd_unit2bios(struct i386_devdesc *dev)
236 {
237 	bdinfo_list_t *bdi;
238 	bdinfo_t *bd;
239 	int unit;
240 
241 	bdi = bd_get_bdinfo_list(dev->dd.d_dev);
242 	if (bdi == NULL)
243 		return (-1);
244 
245 	unit = 0;
246 	STAILQ_FOREACH(bd, bdi, bd_link) {
247 		if (unit == dev->dd.d_unit)
248 			return (bd->bd_unit);
249 		unit++;
250 	}
251 	return (-1);
252 }
253 
254 /*
255  * Quiz the BIOS for disk devices, save a little info about them.
256  */
257 static int
258 fd_init(void)
259 {
260 	int unit;
261 	bdinfo_t *bd;
262 
263 	for (unit = 0; unit < MAXBDDEV; unit++) {
264 		if ((bd = calloc(1, sizeof(*bd))) == NULL)
265 			break;
266 		bd->bd_flags = BD_FLOPPY;
267 		bd->bd_unit = unit;
268 		if (!bd_int13probe(bd)) {
269 			free(bd);
270 			break;
271 		}
272 		if (bd->bd_sectors == 0)
273 			bd->bd_flags |= BD_NO_MEDIA;
274 
275 		printf("BIOS drive %c: is %s%d\n", ('A' + unit),
276 		    biosfd.dv_name, unit);
277 
278 		STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link);
279 	}
280 
281 	bcache_add_dev(unit);
282 	return (0);
283 }
284 
285 static int
286 bd_init(void)
287 {
288 	int base, unit;
289 	bdinfo_t *bd;
290 
291 	base = 0x80;
292 	for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) {
293 		/*
294 		 * Check the BIOS equipment list for number of fixed disks.
295 		 */
296 		if ((bd = calloc(1, sizeof(*bd))) == NULL)
297 			break;
298 		bd->bd_unit = base + unit;
299 		if (!bd_int13probe(bd)) {
300 			free(bd);
301 			break;
302 		}
303 
304 		printf("BIOS drive %c: is %s%d\n", ('C' + unit),
305 		    bioshd.dv_name, unit);
306 
307 		STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link);
308 	}
309 	bcache_add_dev(unit);
310 	return (0);
311 }
312 
313 /*
314  * We can't quiz, we have to be told what device to use, so this function
315  * doesn't do anything.  Instead, the loader calls bc_add() with the BIOS
316  * device number to add.
317  */
318 static int
319 cd_init(void)
320 {
321 
322 	return (0);
323 }
324 
325 int
326 bc_add(int biosdev)
327 {
328 	bdinfo_t *bd;
329 	struct specification_packet bc_sp;
330 	int nbcinfo = 0;
331 
332 	if (!STAILQ_EMPTY(&cdinfo))
333                 return (-1);
334 
335         v86.ctl = V86_FLAGS;
336         v86.addr = 0x13;
337         v86.eax = 0x4b01;
338         v86.edx = biosdev;
339         v86.ds = VTOPSEG(&bc_sp);
340         v86.esi = VTOPOFF(&bc_sp);
341         v86int();
342         if ((v86.eax & 0xff00) != 0)
343                 return (-1);
344 
345 	if ((bd = calloc(1, sizeof(*bd))) == NULL)
346 		return (-1);
347 
348 	bd->bd_flags = BD_CDROM;
349         bd->bd_unit = biosdev;
350 
351 	/*
352 	 * Ignore result from bd_int13probe(), we will use local
353 	 * workaround below.
354 	 */
355 	(void)bd_int13probe(bd);
356 
357 	if (bd->bd_cyl == 0) {
358 		bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
359 		    ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1;
360 	}
361 	if (bd->bd_hds == 0)
362 		bd->bd_hds = bc_sp.sp_head + 1;
363 	if (bd->bd_sec == 0)
364 		bd->bd_sec = bc_sp.sp_cylsec & 0x3f;
365 	if (bd->bd_sectors == 0)
366 		bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
367 
368 	/* Still no size? use 7.961GB */
369 	if (bd->bd_sectors == 0)
370 		bd->bd_sectors = 4173824;
371 
372 	STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
373         printf("BIOS CD is cd%d\n", nbcinfo);
374         nbcinfo++;
375         bcache_add_dev(nbcinfo);        /* register cd device in bcache */
376         return(0);
377 }
378 
379 /*
380  * Return EDD version or 0 if EDD is not supported on this drive.
381  */
382 static int
383 bd_check_extensions(int unit)
384 {
385 	/* Determine if we can use EDD with this device. */
386 	v86.ctl = V86_FLAGS;
387 	v86.addr = 0x13;
388 	v86.eax = 0x4100;
389 	v86.edx = unit;
390 	v86.ebx = 0x55aa;
391 	v86int();
392 
393 	if (V86_CY(v86.efl) ||			/* carry set */
394 	    (v86.ebx & 0xffff) != 0xaa55)	/* signature */
395 		return (0);
396 
397 	/* extended disk access functions (AH=42h-44h,47h,48h) supported */
398 	if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
399 		return (0);
400 
401 	return ((v86.eax >> 8) & 0xff);
402 }
403 
404 static void
405 bd_reset_disk(int unit)
406 {
407 	/* reset disk */
408 	v86.ctl = V86_FLAGS;
409 	v86.addr = 0x13;
410 	v86.eax = 0;
411 	v86.edx = unit;
412 	v86int();
413 }
414 
415 /*
416  * Read CHS info. Return 0 on success, error otherwise.
417  */
418 static int
419 bd_get_diskinfo_std(struct bdinfo *bd)
420 {
421 	bzero(&v86, sizeof(v86));
422 	v86.ctl = V86_FLAGS;
423 	v86.addr = 0x13;
424 	v86.eax = 0x800;
425 	v86.edx = bd->bd_unit;
426 	v86int();
427 
428 	if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
429 		return ((v86.eax & 0xff00) >> 8);
430 
431 	/* return custom error on absurd sector number */
432 	if ((v86.ecx & 0x3f) == 0)
433 		return (0x60);
434 
435 	bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
436 	/* Convert max head # -> # of heads */
437 	bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
438 	bd->bd_sec = v86.ecx & 0x3f;
439 	bd->bd_type = v86.ebx;
440 	bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
441 
442 	return (0);
443 }
444 
445 /*
446  * Read EDD info. Return 0 on success, error otherwise.
447  */
448 static int
449 bd_get_diskinfo_ext(struct bdinfo *bd)
450 {
451 	struct edd_params params;
452 	uint64_t total;
453 
454 	/* Get disk params */
455 	bzero(&params, sizeof(params));
456 	params.len = sizeof(params);
457 	v86.ctl = V86_FLAGS;
458 	v86.addr = 0x13;
459 	v86.eax = 0x4800;
460 	v86.edx = bd->bd_unit;
461 	v86.ds = VTOPSEG(&params);
462 	v86.esi = VTOPOFF(&params);
463 	v86int();
464 
465 	if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
466 		return ((v86.eax & 0xff00) >> 8);
467 
468 	/*
469 	 * Sector size must be a multiple of 512 bytes.
470 	 * An alternate test would be to check power of 2,
471 	 * powerof2(params.sector_size).
472 	 * 4K is largest read buffer we can use at this time.
473 	 */
474 	if (params.sector_size >= 512 &&
475 	    params.sector_size <= 4096 &&
476 	    (params.sector_size % BIOSDISK_SECSIZE) == 0)
477 		bd->bd_sectorsize = params.sector_size;
478 
479 	bd->bd_cyl = params.cylinders;
480 	bd->bd_hds = params.heads;
481 	bd->bd_sec = params.sectors_per_track;
482 
483 	if (params.sectors != 0) {
484 		total = params.sectors;
485 	} else {
486 		total = (uint64_t)params.cylinders *
487 		    params.heads * params.sectors_per_track;
488 	}
489 	bd->bd_sectors = total;
490 
491 	return (0);
492 }
493 
494 /*
495  * Try to detect a device supported by the legacy int13 BIOS
496  */
497 static bool
498 bd_int13probe(bdinfo_t *bd)
499 {
500 	int edd, ret;
501 
502 	bd->bd_flags &= ~BD_NO_MEDIA;
503 
504 	edd = bd_check_extensions(bd->bd_unit);
505 	if (edd == 0)
506 		bd->bd_flags |= BD_MODEINT13;
507 	else if (edd < 0x30)
508 		bd->bd_flags |= BD_MODEEDD1;
509 	else
510 		bd->bd_flags |= BD_MODEEDD3;
511 
512 	/* Default sector size */
513 	bd->bd_sectorsize = BIOSDISK_SECSIZE;
514 
515 	/*
516 	 * Test if the floppy device is present, so we can avoid receiving
517 	 * bogus information from bd_get_diskinfo_std().
518 	 */
519 	if (bd->bd_unit < 0x80) {
520 		/* reset disk */
521 		bd_reset_disk(bd->bd_unit);
522 
523 		/* Get disk type */
524 		v86.ctl = V86_FLAGS;
525 		v86.addr = 0x13;
526 		v86.eax = 0x1500;
527 		v86.edx = bd->bd_unit;
528 		v86int();
529 		if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0)
530 			return (false);
531 	}
532 
533 	ret = 1;
534 	if (edd != 0)
535 		ret = bd_get_diskinfo_ext(bd);
536 	if (ret != 0 || bd->bd_sectors == 0)
537 		ret = bd_get_diskinfo_std(bd);
538 
539 	if (ret != 0 && bd->bd_unit < 0x80) {
540 		/* Set defaults for 1.44 floppy */
541 		bd->bd_cyl = 80;
542 		bd->bd_hds = 2;
543 		bd->bd_sec = 18;
544 		bd->bd_sectors = 2880;
545 		/* Since we are there, there most likely is no media */
546 		bd->bd_flags |= BD_NO_MEDIA;
547 		ret = 0;
548 	}
549 
550 	if (ret != 0) {
551 		/* CD is special case, bc_add() has its own fallback. */
552 		if ((bd->bd_flags & BD_CDROM) != 0)
553 			return (true);
554 
555 		if (bd->bd_sectors != 0 && edd != 0) {
556 			bd->bd_sec = 63;
557 			bd->bd_hds = 255;
558 			bd->bd_cyl =
559 			    (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) /
560 			    bd->bd_sec * bd->bd_hds;
561 		} else {
562 			const char *dv_name;
563 
564 			if ((bd->bd_flags & BD_FLOPPY) != 0)
565 				dv_name = biosfd.dv_name;
566 			else if ((bd->bd_flags & BD_CDROM) != 0)
567 				dv_name = bioscd.dv_name;
568 			else
569 				dv_name = bioshd.dv_name;
570 
571 			printf("Can not get information about %s unit %#x\n",
572 			    dv_name, bd->bd_unit);
573 			return (false);
574 		}
575 	}
576 
577 	if (bd->bd_sec == 0)
578 		bd->bd_sec = 63;
579 	if (bd->bd_hds == 0)
580 		bd->bd_hds = 255;
581 
582 	if (bd->bd_sectors == 0)
583 		bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
584 
585 	DEBUG("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl,
586 	    bd->bd_hds, bd->bd_sec);
587 
588 	return (true);
589 }
590 
591 static int
592 bd_count(bdinfo_list_t *bdi)
593 {
594 	bdinfo_t *bd;
595 	int i;
596 
597 	i = 0;
598 	STAILQ_FOREACH(bd, bdi, bd_link)
599 		i++;
600 	return (i);
601 }
602 
603 /*
604  * Print information about disks
605  */
606 static int
607 bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose)
608 {
609 	char line[80];
610 	struct disk_devdesc devd;
611 	bdinfo_t *bd;
612 	int i, ret = 0;
613 	char drive;
614 
615 	if (STAILQ_EMPTY(bdi))
616 		return (0);
617 
618 	printf("%s devices:", dev->dv_name);
619 	if ((ret = pager_output("\n")) != 0)
620 		return (ret);
621 
622 	i = -1;
623 	STAILQ_FOREACH(bd, bdi, bd_link) {
624 		i++;
625 
626 		switch (dev->dv_type) {
627 		case DEVT_FD:
628 			drive = 'A';
629 			break;
630 		case DEVT_CD:
631 			drive = 'C' + bd_count(&hdinfo);
632 			break;
633 		default:
634 			drive = 'C';
635 			break;
636 		}
637 
638 		snprintf(line, sizeof(line),
639 		    "    %s%d:   BIOS drive %c (%s%ju X %u):\n",
640 		    dev->dv_name, i, drive + i,
641 		    (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
642 		    "no media, " : "",
643 		    (uintmax_t)bd->bd_sectors,
644 		    bd->bd_sectorsize);
645 		if ((ret = pager_output(line)) != 0)
646 			break;
647 
648 		if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
649 			continue;
650 
651 		if (dev->dv_type != DEVT_DISK)
652 			continue;
653 
654 		devd.dd.d_dev = dev;
655 		devd.dd.d_unit = i;
656 		devd.d_slice = -1;
657 		devd.d_partition = -1;
658 		if (disk_open(&devd,
659 		    bd->bd_sectorsize * bd->bd_sectors,
660 		    bd->bd_sectorsize) == 0) {
661 			snprintf(line, sizeof(line), "    %s%d",
662 			    dev->dv_name, i);
663 			ret = disk_print(&devd, line, verbose);
664 			disk_close(&devd);
665 			if (ret != 0)
666 				break;
667 		}
668 	}
669 	return (ret);
670 }
671 
672 static int
673 fd_print(int verbose)
674 {
675 	return (bd_print_common(&biosfd, &fdinfo, verbose));
676 }
677 
678 static int
679 bd_print(int verbose)
680 {
681 	return (bd_print_common(&bioshd, &hdinfo, verbose));
682 }
683 
684 static int
685 cd_print(int verbose)
686 {
687 	return (bd_print_common(&bioscd, &cdinfo, verbose));
688 }
689 
690 /*
691  * Read disk size from partition.
692  * This is needed to work around buggy BIOS systems returning
693  * wrong (truncated) disk media size.
694  * During bd_probe() we tested if the multiplication of bd_sectors
695  * would overflow so it should be safe to perform here.
696  */
697 static uint64_t
698 bd_disk_get_sectors(struct disk_devdesc *dev)
699 {
700 	bdinfo_t *bd;
701 	struct disk_devdesc disk;
702 	uint64_t size;
703 
704 	bd = bd_get_bdinfo(&dev->dd);
705 	if (bd == NULL)
706 		return (0);
707 
708 	disk.dd.d_dev = dev->dd.d_dev;
709 	disk.dd.d_unit = dev->dd.d_unit;
710 	disk.d_slice = -1;
711 	disk.d_partition = -1;
712 	disk.d_offset = 0;
713 
714 	size = bd->bd_sectors * bd->bd_sectorsize;
715 	if (disk_open(&disk, size, bd->bd_sectorsize) == 0) {
716 		(void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size);
717 		disk_close(&disk);
718 	}
719 	return (size / bd->bd_sectorsize);
720 }
721 
722 /*
723  * Attempt to open the disk described by (dev) for use by (f).
724  *
725  * Note that the philosophy here is "give them exactly what
726  * they ask for".  This is necessary because being too "smart"
727  * about what the user might want leads to complications.
728  * (eg. given no slice or partition value, with a disk that is
729  *  sliced - are they after the first BSD slice, or the DOS
730  *  slice before it?)
731  */
732 static int
733 bd_open(struct open_file *f, ...)
734 {
735 	bdinfo_t *bd;
736 	struct disk_devdesc *dev;
737 	va_list ap;
738 	int rc;
739 
740 	va_start(ap, f);
741 	dev = va_arg(ap, struct disk_devdesc *);
742 	va_end(ap);
743 
744 	bd = bd_get_bdinfo(&dev->dd);
745 	if (bd == NULL)
746 		return (EIO);
747 
748 	if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
749 		if (!bd_int13probe(bd))
750 			return (EIO);
751 		if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
752 			return (EIO);
753 	}
754 	if (bd->bd_bcache == NULL)
755 	    bd->bd_bcache = bcache_allocate();
756 
757 	if (bd->bd_open == 0)
758 		bd->bd_sectors = bd_disk_get_sectors(dev);
759 	bd->bd_open++;
760 
761 	rc = 0;
762 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
763 		rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
764 		    bd->bd_sectorsize);
765 		if (rc != 0) {
766 			bd->bd_open--;
767 			if (bd->bd_open == 0) {
768 				bcache_free(bd->bd_bcache);
769 				bd->bd_bcache = NULL;
770 			}
771 		}
772 	}
773 	return (rc);
774 }
775 
776 static int
777 bd_close(struct open_file *f)
778 {
779 	struct disk_devdesc *dev;
780 	bdinfo_t *bd;
781 	int rc = 0;
782 
783 	dev = (struct disk_devdesc *)f->f_devdata;
784 	bd = bd_get_bdinfo(&dev->dd);
785 	if (bd == NULL)
786 		return (EIO);
787 
788 	bd->bd_open--;
789 	if (bd->bd_open == 0) {
790 	    bcache_free(bd->bd_bcache);
791 	    bd->bd_bcache = NULL;
792 	}
793 	if (dev->dd.d_dev->dv_type == DEVT_DISK)
794 		rc = disk_close(dev);
795 	return (rc);
796 }
797 
798 static int
799 bd_ioctl(struct open_file *f, u_long cmd, void *data)
800 {
801 	bdinfo_t *bd;
802 	struct disk_devdesc *dev;
803 	int rc;
804 
805 	dev = (struct disk_devdesc *)f->f_devdata;
806 	bd = bd_get_bdinfo(&dev->dd);
807 	if (bd == NULL)
808 		return (EIO);
809 
810 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
811 		rc = disk_ioctl(dev, cmd, data);
812 		if (rc != ENOTTY)
813 			return (rc);
814 	}
815 
816 	switch (cmd) {
817 	case DIOCGSECTORSIZE:
818 		*(uint32_t *)data = bd->bd_sectorsize;
819 		break;
820 	case DIOCGMEDIASIZE:
821 		*(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize;
822 		break;
823 	default:
824 		return (ENOTTY);
825 	}
826 	return (0);
827 }
828 
829 static int
830 bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
831     char *buf, size_t *rsize)
832 {
833 	bdinfo_t *bd;
834 	struct bcache_devdata bcd;
835 	struct disk_devdesc *dev;
836 	daddr_t offset;
837 
838 	dev = (struct disk_devdesc *)devdata;
839 	bd = bd_get_bdinfo(&dev->dd);
840 	if (bd == NULL)
841 		return (EINVAL);
842 
843 	bcd.dv_strategy = bd_realstrategy;
844 	bcd.dv_devdata = devdata;
845 	bcd.dv_cache = bd->bd_bcache;
846 
847 	offset = 0;
848 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
849 
850 		offset = dev->d_offset * bd->bd_sectorsize;
851 		offset /= BIOSDISK_SECSIZE;
852 	}
853 	return (bcache_strategy(&bcd, rw, dblk + offset, size,
854 	    buf, rsize));
855 }
856 
857 static int
858 bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
859     char *buf, size_t *rsize)
860 {
861 	struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
862 	bdinfo_t *bd;
863 	uint64_t disk_blocks, offset, d_offset;
864 	size_t blks, blkoff, bsize, rest;
865 	caddr_t bbuf;
866 	int rc;
867 
868 	bd = bd_get_bdinfo(&dev->dd);
869 	if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
870 		return (EIO);
871 
872 	/*
873 	 * First make sure the IO size is a multiple of 512 bytes. While we do
874 	 * process partial reads below, the strategy mechanism is built
875 	 * assuming IO is a multiple of 512B blocks. If the request is not
876 	 * a multiple of 512B blocks, it has to be some sort of bug.
877 	 */
878 	if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) {
879 		printf("bd_strategy: %d bytes I/O not multiple of %d\n",
880 		    size, BIOSDISK_SECSIZE);
881 		return (EIO);
882 	}
883 
884 	DEBUG("open_disk %p", dev);
885 
886 	offset = dblk * BIOSDISK_SECSIZE;
887 	dblk = offset / bd->bd_sectorsize;
888 	blkoff = offset % bd->bd_sectorsize;
889 
890 	/*
891 	 * Check the value of the size argument. We do have quite small
892 	 * heap (64MB), but we do not know good upper limit, so we check against
893 	 * INT_MAX here. This will also protect us against possible overflows
894 	 * while translating block count to bytes.
895 	 */
896 	if (size > INT_MAX) {
897 		DEBUG("too large I/O: %zu bytes", size);
898 		return (EIO);
899 	}
900 
901 	blks = size / bd->bd_sectorsize;
902 	if (blks == 0 || (size % bd->bd_sectorsize) != 0)
903 		blks++;
904 
905 	if (dblk > dblk + blks)
906 		return (EIO);
907 
908 	if (rsize)
909 		*rsize = 0;
910 
911 	/*
912 	 * Get disk blocks, this value is either for whole disk or for
913 	 * partition.
914 	 */
915 	d_offset = 0;
916 	disk_blocks = 0;
917 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
918 		if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
919 			/* DIOCGMEDIASIZE does return bytes. */
920 			disk_blocks /= bd->bd_sectorsize;
921 		}
922 		d_offset = dev->d_offset;
923 	}
924 	if (disk_blocks == 0)
925 		disk_blocks = bd->bd_sectors - d_offset;
926 
927 	/* Validate source block address. */
928 	if (dblk < d_offset || dblk >= d_offset + disk_blocks)
929 		return (EIO);
930 
931 	/*
932 	 * Truncate if we are crossing disk or partition end.
933 	 */
934 	if (dblk + blks >= d_offset + disk_blocks) {
935 		blks = d_offset + disk_blocks - dblk;
936 		size = blks * bd->bd_sectorsize;
937 		DEBUG("short I/O %d", blks);
938 	}
939 
940 	if (V86_IO_BUFFER_SIZE / bd->bd_sectorsize == 0)
941 		panic("BUG: Real mode buffer is too small");
942 
943 	bbuf = PTOV(V86_IO_BUFFER);
944 	rest = size;
945 
946 	while (blks > 0) {
947 		int x = min(blks, V86_IO_BUFFER_SIZE / bd->bd_sectorsize);
948 
949 		switch (rw & F_MASK) {
950 		case F_READ:
951 			DEBUG("read %d from %lld to %p", x, dblk, buf);
952 			bsize = bd->bd_sectorsize * x - blkoff;
953 			if (rest < bsize)
954 				bsize = rest;
955 
956 			if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0)
957 				return (EIO);
958 
959 			bcopy(bbuf + blkoff, buf, bsize);
960 			break;
961 		case F_WRITE :
962 			DEBUG("write %d from %lld to %p", x, dblk, buf);
963 			if (blkoff != 0) {
964 				/*
965 				 * We got offset to sector, read 1 sector to
966 				 * bbuf.
967 				 */
968 				x = 1;
969 				bsize = bd->bd_sectorsize - blkoff;
970 				bsize = min(bsize, rest);
971 				rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
972 			} else if (rest < bd->bd_sectorsize) {
973 				/*
974 				 * The remaining block is not full
975 				 * sector. Read 1 sector to bbuf.
976 				 */
977 				x = 1;
978 				bsize = rest;
979 				rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
980 			} else {
981 				/* We can write full sector(s). */
982 				bsize = bd->bd_sectorsize * x;
983 			}
984 			/*
985 			 * Put your Data In, Put your Data out,
986 			 * Put your Data In, and shake it all about
987 			 */
988 			bcopy(buf, bbuf + blkoff, bsize);
989 			if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0)
990 				return (EIO);
991 
992 			break;
993 		default:
994 			/* DO NOTHING */
995 			return (EROFS);
996 		}
997 
998 		blkoff = 0;
999 		buf += bsize;
1000 		rest -= bsize;
1001 		blks -= x;
1002 		dblk += x;
1003 	}
1004 
1005 	if (rsize != NULL)
1006 		*rsize = size;
1007 	return (0);
1008 }
1009 
1010 static int
1011 bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
1012     int dowrite)
1013 {
1014 	static struct edd_packet packet;
1015 
1016 	packet.len = sizeof(struct edd_packet);
1017 	packet.count = blks;
1018 	packet.off = VTOPOFF(dest);
1019 	packet.seg = VTOPSEG(dest);
1020 	packet.lba = dblk;
1021 	v86.ctl = V86_FLAGS;
1022 	v86.addr = 0x13;
1023 	/* Should we Write with verify ?? 0x4302 ? */
1024 	if (dowrite == BD_WR)
1025 		v86.eax = 0x4300;
1026 	else
1027 		v86.eax = 0x4200;
1028 	v86.edx = bd->bd_unit;
1029 	v86.ds = VTOPSEG(&packet);
1030 	v86.esi = VTOPOFF(&packet);
1031 	v86int();
1032 	if (V86_CY(v86.efl))
1033 		return (v86.eax >> 8);
1034 	return (0);
1035 }
1036 
1037 static int
1038 bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
1039     int dowrite)
1040 {
1041 	uint32_t x, bpc, cyl, hd, sec;
1042 
1043 	bpc = bd->bd_sec * bd->bd_hds;	/* blocks per cylinder */
1044 	x = dblk;
1045 	cyl = x / bpc;			/* block # / blocks per cylinder */
1046 	x %= bpc;				/* block offset into cylinder */
1047 	hd = x / bd->bd_sec;		/* offset / blocks per track */
1048 	sec = x % bd->bd_sec;		/* offset into track */
1049 
1050 	/* correct sector number for 1-based BIOS numbering */
1051 	sec++;
1052 
1053 	if (cyl > 1023) {
1054 		/* CHS doesn't support cylinders > 1023. */
1055 		return (1);
1056 	}
1057 
1058 	v86.ctl = V86_FLAGS;
1059 	v86.addr = 0x13;
1060 	if (dowrite == BD_WR)
1061 		v86.eax = 0x300 | blks;
1062 	else
1063 		v86.eax = 0x200 | blks;
1064 	v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
1065 	v86.edx = (hd << 8) | bd->bd_unit;
1066 	v86.es = VTOPSEG(dest);
1067 	v86.ebx = VTOPOFF(dest);
1068 	v86int();
1069 	if (V86_CY(v86.efl))
1070 		return (v86.eax >> 8);
1071 	return (0);
1072 }
1073 
1074 static void
1075 bd_io_workaround(bdinfo_t *bd)
1076 {
1077 	uint8_t buf[8 * 1024];
1078 
1079 	bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD);
1080 }
1081 
1082 static int
1083 bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks,
1084     caddr_t dest, int dowrite)
1085 {
1086 	int result, retry;
1087 
1088 	/* Just in case some idiot actually tries to read/write -1 blocks... */
1089 	if (blks < 0)
1090 		return (-1);
1091 
1092 	/*
1093 	 * Workaround for a problem with some HP ProLiant BIOS failing to work
1094 	 * out the boot disk after installation. hrs and kuriyama discovered
1095 	 * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and
1096 	 * discovered that an int13h call seems to cause a buffer overrun in
1097 	 * the bios. The problem is alleviated by doing an extra read before
1098 	 * the buggy read. It is not immediately known whether other models
1099 	 * are similarly affected.
1100 	 * Loop retrying the operation a couple of times.  The BIOS
1101 	 * may also retry.
1102 	 */
1103 	if (dowrite == BD_RD && dblk >= 0x100000000)
1104 		bd_io_workaround(bd);
1105 	for (retry = 0; retry < 3; retry++) {
1106 		if (bd->bd_flags & BD_MODEEDD)
1107 			result = bd_edd_io(bd, dblk, blks, dest, dowrite);
1108 		else
1109 			result = bd_chs_io(bd, dblk, blks, dest, dowrite);
1110 
1111 		if (result == 0) {
1112 			if (bd->bd_flags & BD_NO_MEDIA)
1113 				bd->bd_flags &= ~BD_NO_MEDIA;
1114 			break;
1115 		}
1116 
1117 		bd_reset_disk(bd->bd_unit);
1118 
1119 		/*
1120 		 * Error codes:
1121 		 * 20h	controller failure
1122 		 * 31h	no media in drive (IBM/MS INT 13 extensions)
1123 		 * 80h	no media in drive, VMWare (Fusion)
1124 		 * There is no reason to repeat the IO with errors above.
1125 		 */
1126 		if (result == 0x20 || result == 0x31 || result == 0x80) {
1127 			bd->bd_flags |= BD_NO_MEDIA;
1128 			break;
1129 		}
1130 	}
1131 
1132 	if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) {
1133 		if (dowrite == BD_WR) {
1134 			printf("%s%d: Write %d sector(s) from %p (0x%x) "
1135 			    "to %lld: 0x%x\n", dev->dd.d_dev->dv_name,
1136 			    dev->dd.d_unit, blks, dest, VTOP(dest), dblk,
1137 			    result);
1138 		} else {
1139 			printf("%s%d: Read %d sector(s) from %lld to %p "
1140 			    "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name,
1141 			    dev->dd.d_unit, blks, dblk, dest, VTOP(dest),
1142 			    result);
1143 		}
1144 	}
1145 
1146 	return (result);
1147 }
1148 
1149 /*
1150  * Return the BIOS geometry of a given "fixed drive" in a format
1151  * suitable for the legacy bootinfo structure.  Since the kernel is
1152  * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
1153  * prefer to get the information directly, rather than rely on being
1154  * able to put it together from information already maintained for
1155  * different purposes and for a probably different number of drives.
1156  *
1157  * For valid drives, the geometry is expected in the format (31..0)
1158  * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
1159  * indicated by returning the geometry of a "1.2M" PC-format floppy
1160  * disk.  And, incidentally, what is returned is not the geometry as
1161  * such but the highest valid cylinder, head, and sector numbers.
1162  */
1163 uint32_t
1164 bd_getbigeom(int bunit)
1165 {
1166 
1167 	v86.ctl = V86_FLAGS;
1168 	v86.addr = 0x13;
1169 	v86.eax = 0x800;
1170 	v86.edx = 0x80 + bunit;
1171 	v86int();
1172 	if (V86_CY(v86.efl))
1173 		return (0x4f010f);
1174 	return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
1175 	    (v86.edx & 0xff00) | (v86.ecx & 0x3f));
1176 }
1177 
1178 /*
1179  * Return a suitable dev_t value for (dev).
1180  *
1181  * In the case where it looks like (dev) is a SCSI disk, we allow the number of
1182  * IDE disks to be specified in $num_ide_disks.  There should be a Better Way.
1183  */
1184 int
1185 bd_getdev(struct i386_devdesc *d)
1186 {
1187 	struct disk_devdesc *dev;
1188 	bdinfo_t *bd;
1189 	int	biosdev;
1190 	int	major;
1191 	int	rootdev;
1192 	char	*nip, *cp;
1193 	int	i, unit, slice, partition;
1194 
1195 	/* XXX: Assume partition 'a'. */
1196 	slice = 0;
1197 	partition = 0;
1198 
1199 	dev = (struct disk_devdesc *)d;
1200 	bd = bd_get_bdinfo(&dev->dd);
1201 	if (bd == NULL)
1202 		return (-1);
1203 
1204 	biosdev = bd_unit2bios(d);
1205 	DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev);
1206 	if (biosdev == -1)			/* not a BIOS device */
1207 		return (-1);
1208 
1209 	if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1210 		if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
1211 		    bd->bd_sectorsize) != 0)	/* oops, not a viable device */
1212 			return (-1);
1213 		else
1214 			disk_close(dev);
1215 		slice = dev->d_slice + 1;
1216 		partition = dev->d_partition;
1217 	}
1218 
1219 	if (biosdev < 0x80) {
1220 		/* floppy (or emulated floppy) or ATAPI device */
1221 		if (bd->bd_type == DT_ATAPI) {
1222 			/* is an ATAPI disk */
1223 			major = WFDMAJOR;
1224 		} else {
1225 			/* is a floppy disk */
1226 			major = FDMAJOR;
1227 		}
1228 	} else {
1229 		/* assume an IDE disk */
1230 		major = WDMAJOR;
1231 	}
1232 	/* default root disk unit number */
1233 	unit = biosdev & 0x7f;
1234 
1235 	if (dev->dd.d_dev->dv_type == DEVT_CD) {
1236 		/*
1237 		 * XXX: Need to examine device spec here to figure out if
1238 		 * SCSI or ATAPI.  No idea on how to figure out device number.
1239 		 * All we can really pass to the kernel is what bus and device
1240 		 * on which bus we were booted from, which dev_t isn't well
1241 		 * suited to since those number don't match to unit numbers
1242 		 * very well.  We may just need to engage in a hack where
1243 		 * we pass -C to the boot args if we are the boot device.
1244 		 */
1245 		major = ACDMAJOR;
1246 		unit = 0;       /* XXX */
1247 	}
1248 
1249 	/* XXX a better kludge to set the root disk unit number */
1250 	if ((nip = getenv("root_disk_unit")) != NULL) {
1251 		i = strtol(nip, &cp, 0);
1252 		/* check for parse error */
1253 		if ((cp != nip) && (*cp == 0))
1254 			unit = i;
1255 	}
1256 
1257 	rootdev = MAKEBOOTDEV(major, slice, unit, partition);
1258 	DEBUG("dev is 0x%x\n", rootdev);
1259 	return (rootdev);
1260 }
1261