1/*	$NetBSD: efidisk_ll.c,v 1.2 2018/03/08 10:34:33 nonaka Exp $	 */
2/*	NetBSD: biosdisk_ll.c,v 1.31 2011/02/21 02:58:02 jakllsch Exp	 */
3
4/*-
5 * Copyright (c) 2005 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Bang Jun-Young.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1996
35 * 	Matthias Drochner.  All rights reserved.
36 * Copyright (c) 1996
37 * 	Perry E. Metzger.  All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 *    must display the following acknowledgements:
49 *	This product includes software developed for the NetBSD Project
50 *	by Matthias Drochner.
51 *	This product includes software developed for the NetBSD Project
52 *	by Perry E. Metzger.
53 * 4. The names of the authors may not be used to endorse or promote products
54 *    derived from this software without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
58 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
59 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
60 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
61 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
62 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
63 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
64 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
65 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 */
67
68/*
69 * shared by bootsector startup (bootsectmain) and biosdisk.c
70 * needs lowlevel parts from bios_disk.S
71 */
72
73#include "efiboot.h"
74
75#include "biosdisk_ll.h"
76#include "diskbuf.h"
77#include "efidisk.h"
78
79static int do_read(struct biosdisk_ll *, daddr_t, int, char *);
80
81#ifndef BIOSDISK_RETRIES
82#define BIOSDISK_RETRIES 5
83#endif
84
85int
86set_geometry(struct biosdisk_ll *d, struct biosdisk_extinfo *ed)
87{
88	const struct efidiskinfo *edi;
89	EFI_BLOCK_IO_MEDIA *media;
90
91	edi = efidisk_getinfo(d->dev);
92	if (edi == NULL)
93		return 1;
94
95	media = edi->bio->Media;
96
97	d->secsize = media->BlockSize;
98	d->type = edi->type;
99	d->flags = BIOSDISK_INT13EXT;
100
101	if (ed != NULL) {
102		ed->totsec = media->LastBlock + 1;
103		ed->sbytes = media->BlockSize;
104		ed->flags = 0;
105		if (media->RemovableMedia)
106			ed->flags |= EXTINFO_REMOVABLE;
107	}
108
109	return 0;
110}
111
112/*
113 * Global shared "diskbuf" is used as read ahead buffer.  For reading from
114 * floppies, the bootstrap has to be loaded on a 64K boundary to ensure that
115 * this buffer doesn't cross a 64K DMA boundary.
116 */
117static int      ra_dev;
118static daddr_t  ra_end;
119static daddr_t  ra_first;
120
121static int
122do_read(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf)
123{
124	EFI_STATUS status;
125	const struct efidiskinfo *edi;
126
127	edi = efidisk_getinfo(d->dev);
128	if (edi == NULL)
129		return -1;
130
131	status = uefi_call_wrapper(edi->bio->ReadBlocks, 5, edi->bio,
132	    edi->media_id, dblk, num * d->secsize, buf);
133	if (EFI_ERROR(status))
134		return -1;
135	return num;
136}
137
138/*
139 * NB if 'cold' is set below not all of the program is loaded, so
140 * mustn't use data segment, bss, call library functions or do read-ahead.
141 */
142int
143readsects(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf, int cold)
144{
145	while (num) {
146		int nsec;
147
148		/* check for usable data in read-ahead buffer */
149		if (cold || diskbuf_user != &ra_dev || d->dev != ra_dev
150		    || dblk < ra_first || dblk >= ra_end) {
151
152			/* no, read from disk */
153			char *trbuf;
154			int maxsecs;
155			int retries = BIOSDISK_RETRIES;
156
157			if (cold) {
158				/* transfer directly to buffer */
159				trbuf = buf;
160				maxsecs = num;
161			} else {
162				/* fill read-ahead buffer */
163				trbuf = alloc_diskbuf(0); /* no data yet */
164				maxsecs = DISKBUFSIZE / d->secsize;
165			}
166
167			while ((nsec = do_read(d, dblk, maxsecs, trbuf)) < 0) {
168#ifdef DISK_DEBUG
169				if (!cold)
170					printf("read error dblk %"PRId64"-%"PRId64"\n",
171					    dblk, (dblk + maxsecs - 1));
172#endif
173				if (--retries >= 0)
174					continue;
175				return -1;	/* XXX cannot output here if
176						 * (cold) */
177			}
178			if (!cold) {
179				ra_dev = d->dev;
180				ra_first = dblk;
181				ra_end = dblk + nsec;
182				diskbuf_user = &ra_dev;
183			}
184		} else		/* can take blocks from end of read-ahead
185				 * buffer */
186			nsec = ra_end - dblk;
187
188		if (!cold) {
189			/* copy data from read-ahead to user buffer */
190			if (nsec > num)
191				nsec = num;
192			memcpy(buf,
193			       diskbufp + (dblk - ra_first) * d->secsize,
194			       nsec * d->secsize);
195		}
196		buf += nsec * d->secsize;
197		num -= nsec;
198		dblk += nsec;
199	}
200
201	return 0;
202}
203