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