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