Deleted Added
full compact
bioscd.c (313355) bioscd.c (328889)
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 2001 John H. Baldwin <jhb@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>
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 2001 John H. Baldwin <jhb@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/sys/boot/pc98/libpc98/bioscd.c 313355 2017-02-06 22:03:07Z tsoome $");
29__FBSDID("$FreeBSD: stable/11/sys/boot/pc98/libpc98/bioscd.c 328889 2018-02-05 17:01:18Z kevans $");
30
31/*
32 * BIOS CD device handling for CD's that have been booted off of via no
33 * emulation booting as defined in the El Torito standard.
34 *
35 * Ideas and algorithms from:
36 *
37 * - FreeBSD libi386/biosdisk.c
38 *
39 */
40
41#include <stand.h>
42
43#include <sys/param.h>
44#include <machine/bootinfo.h>
45
46#include <stdarg.h>
47
48#include <bootstrap.h>
49#include <btxv86.h>
50#include "libi386.h"
51
52#define BIOSCD_SECSIZE 2048
53#define BUFSIZE (1 * BIOSCD_SECSIZE)
54#define MAXBCDEV 1
55
56/* Major numbers for devices we frontend for. */
57#define ACDMAJOR 117
58#define CDMAJOR 15
59
60#ifdef DISK_DEBUG
61# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
62#else
63# define DEBUG(fmt, args...)
64#endif
65
66struct specification_packet {
67 u_char sp_size;
68 u_char sp_bootmedia;
69 u_char sp_drive;
70 u_char sp_controller;
71 u_int sp_lba;
72 u_short sp_devicespec;
73 u_short sp_buffersegment;
74 u_short sp_loadsegment;
75 u_short sp_sectorcount;
76 u_short sp_cylsec;
77 u_char sp_head;
78};
79
80/*
81 * List of BIOS devices, translation from disk unit number to
82 * BIOS unit number.
83 */
84static struct bcinfo {
85 int bc_unit; /* BIOS unit number */
86 struct specification_packet bc_sp;
87 int bc_open; /* reference counter */
88 void *bc_bcache; /* buffer cache data */
89} bcinfo [MAXBCDEV];
90static int nbcinfo = 0;
91
92#define BC(dev) (bcinfo[(dev)->d_unit])
93
94static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest);
95static int bc_init(void);
96static int bc_strategy(void *devdata, int flag, daddr_t dblk,
97 size_t size, char *buf, size_t *rsize);
98static int bc_realstrategy(void *devdata, int flag, daddr_t dblk,
99 size_t size, char *buf, size_t *rsize);
100static int bc_open(struct open_file *f, ...);
101static int bc_close(struct open_file *f);
30
31/*
32 * BIOS CD device handling for CD's that have been booted off of via no
33 * emulation booting as defined in the El Torito standard.
34 *
35 * Ideas and algorithms from:
36 *
37 * - FreeBSD libi386/biosdisk.c
38 *
39 */
40
41#include <stand.h>
42
43#include <sys/param.h>
44#include <machine/bootinfo.h>
45
46#include <stdarg.h>
47
48#include <bootstrap.h>
49#include <btxv86.h>
50#include "libi386.h"
51
52#define BIOSCD_SECSIZE 2048
53#define BUFSIZE (1 * BIOSCD_SECSIZE)
54#define MAXBCDEV 1
55
56/* Major numbers for devices we frontend for. */
57#define ACDMAJOR 117
58#define CDMAJOR 15
59
60#ifdef DISK_DEBUG
61# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
62#else
63# define DEBUG(fmt, args...)
64#endif
65
66struct specification_packet {
67 u_char sp_size;
68 u_char sp_bootmedia;
69 u_char sp_drive;
70 u_char sp_controller;
71 u_int sp_lba;
72 u_short sp_devicespec;
73 u_short sp_buffersegment;
74 u_short sp_loadsegment;
75 u_short sp_sectorcount;
76 u_short sp_cylsec;
77 u_char sp_head;
78};
79
80/*
81 * List of BIOS devices, translation from disk unit number to
82 * BIOS unit number.
83 */
84static struct bcinfo {
85 int bc_unit; /* BIOS unit number */
86 struct specification_packet bc_sp;
87 int bc_open; /* reference counter */
88 void *bc_bcache; /* buffer cache data */
89} bcinfo [MAXBCDEV];
90static int nbcinfo = 0;
91
92#define BC(dev) (bcinfo[(dev)->d_unit])
93
94static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest);
95static int bc_init(void);
96static int bc_strategy(void *devdata, int flag, daddr_t dblk,
97 size_t size, char *buf, size_t *rsize);
98static int bc_realstrategy(void *devdata, int flag, daddr_t dblk,
99 size_t size, char *buf, size_t *rsize);
100static int bc_open(struct open_file *f, ...);
101static int bc_close(struct open_file *f);
102static void bc_print(int verbose);
102static int bc_print(int verbose);
103
104struct devsw bioscd = {
105 "cd",
106 DEVT_CD,
107 bc_init,
108 bc_strategy,
109 bc_open,
110 bc_close,
111 noioctl,
112 bc_print,
113 NULL
114};
115
116/*
117 * Translate between BIOS device numbers and our private unit numbers.
118 */
119int
120bc_bios2unit(int biosdev)
121{
122 int i;
123
124 DEBUG("looking for bios device 0x%x", biosdev);
125 for (i = 0; i < nbcinfo; i++) {
126 DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit);
127 if (bcinfo[i].bc_unit == biosdev)
128 return(i);
129 }
130 return(-1);
131}
132
133int
134bc_unit2bios(int unit)
135{
136 if ((unit >= 0) && (unit < nbcinfo))
137 return(bcinfo[unit].bc_unit);
138 return(-1);
139}
140
141/*
142 * We can't quiz, we have to be told what device to use, so this functoin
143 * doesn't do anything. Instead, the loader calls bc_add() with the BIOS
144 * device number to add.
145 */
146static int
147bc_init(void)
148{
149
150 return (0);
151}
152
153int
154bc_add(int biosdev)
155{
156
157 if (nbcinfo >= MAXBCDEV)
158 return (-1);
159 bcinfo[nbcinfo].bc_unit = biosdev;
160
161 /* SCSI CD-ROM only */
162 if ((biosdev & 0xf0) != 0xa0)
163 return (-1);
164 if ((((uint32_t *)PTOV(0xA1460))[biosdev & 0x0f] & 0x1f) != 5)
165 return (-1);
166
167 printf("BIOS CD is cd%d\n", nbcinfo);
168 nbcinfo++;
169 bcache_add_dev(nbcinfo); /* register cd device in bcache */
170 return(0);
171}
172
173/*
174 * Print information about disks
175 */
103
104struct devsw bioscd = {
105 "cd",
106 DEVT_CD,
107 bc_init,
108 bc_strategy,
109 bc_open,
110 bc_close,
111 noioctl,
112 bc_print,
113 NULL
114};
115
116/*
117 * Translate between BIOS device numbers and our private unit numbers.
118 */
119int
120bc_bios2unit(int biosdev)
121{
122 int i;
123
124 DEBUG("looking for bios device 0x%x", biosdev);
125 for (i = 0; i < nbcinfo; i++) {
126 DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit);
127 if (bcinfo[i].bc_unit == biosdev)
128 return(i);
129 }
130 return(-1);
131}
132
133int
134bc_unit2bios(int unit)
135{
136 if ((unit >= 0) && (unit < nbcinfo))
137 return(bcinfo[unit].bc_unit);
138 return(-1);
139}
140
141/*
142 * We can't quiz, we have to be told what device to use, so this functoin
143 * doesn't do anything. Instead, the loader calls bc_add() with the BIOS
144 * device number to add.
145 */
146static int
147bc_init(void)
148{
149
150 return (0);
151}
152
153int
154bc_add(int biosdev)
155{
156
157 if (nbcinfo >= MAXBCDEV)
158 return (-1);
159 bcinfo[nbcinfo].bc_unit = biosdev;
160
161 /* SCSI CD-ROM only */
162 if ((biosdev & 0xf0) != 0xa0)
163 return (-1);
164 if ((((uint32_t *)PTOV(0xA1460))[biosdev & 0x0f] & 0x1f) != 5)
165 return (-1);
166
167 printf("BIOS CD is cd%d\n", nbcinfo);
168 nbcinfo++;
169 bcache_add_dev(nbcinfo); /* register cd device in bcache */
170 return(0);
171}
172
173/*
174 * Print information about disks
175 */
176static void
176static int
177bc_print(int verbose)
178{
179 char line[80];
177bc_print(int verbose)
178{
179 char line[80];
180 int i;
180 int i, ret = 0;
181
181
182 pager_open();
182 if (nbcinfo == 0)
183 return (0);
184
185 printf("%s devices:", bioscd.dv_name);
186 if ((ret = pager_output("\n")) != 0)
187 return (ret);
188
183 for (i = 0; i < nbcinfo; i++) {
184 sprintf(line, " cd%d: Device 0x%x\n", i,
185 bcinfo[i].bc_sp.sp_devicespec);
189 for (i = 0; i < nbcinfo; i++) {
190 sprintf(line, " cd%d: Device 0x%x\n", i,
191 bcinfo[i].bc_sp.sp_devicespec);
186 if (pager_output(line))
192 if ((ret = pager_output(line)) != 0)
187 break;
188 }
193 break;
194 }
189 pager_close();
195 return (ret);
190}
191
192/*
193 * Attempt to open the disk described by (dev) for use by (f).
194 */
195static int
196bc_open(struct open_file *f, ...)
197{
198 va_list ap;
199 struct i386_devdesc *dev;
200
201 va_start(ap, f);
202 dev = va_arg(ap, struct i386_devdesc *);
203 va_end(ap);
204 if (dev->d_unit >= nbcinfo) {
205 DEBUG("attempt to open nonexistent disk");
206 return(ENXIO);
207 }
208
209 BC(dev).bc_open++;
210 if (BC(dev).bc_bcache == NULL)
211 BC(dev).bc_bcache = bcache_allocate();
212 return(0);
213}
214
215static int
216bc_close(struct open_file *f)
217{
218 struct i386_devdesc *dev;
219
220 dev = (struct i386_devdesc *)f->f_devdata;
221 BC(dev).bc_open--;
222 if (BC(dev).bc_open == 0) {
223 bcache_free(BC(dev).bc_bcache);
224 BC(dev).bc_bcache = NULL;
225 }
226 return(0);
227}
228
229static int
230bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
231 char *buf, size_t *rsize)
232{
233 struct bcache_devdata bcd;
234 struct i386_devdesc *dev;
235
236 dev = (struct i386_devdesc *)devdata;
237 bcd.dv_strategy = bc_realstrategy;
238 bcd.dv_devdata = devdata;
239 bcd.dv_cache = BC(dev).bc_bcache;
240
241 return (bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
242}
243
244static int
245bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
246 char *buf, size_t *rsize)
247{
248 struct i386_devdesc *dev;
249 int unit;
250 int blks;
251#ifdef BD_SUPPORT_FRAGS
252 char fragbuf[BIOSCD_SECSIZE];
253 size_t fragsize;
254
255 fragsize = size % BIOSCD_SECSIZE;
256#else
257 if (size % BIOSCD_SECSIZE)
258 return (EINVAL);
259#endif
260
261 if (rw != F_READ)
262 return(EROFS);
263 dev = (struct i386_devdesc *)devdata;
264 unit = dev->d_unit;
265 blks = size / BIOSCD_SECSIZE;
266 if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0)
267 return (EINVAL);
268 dblk /= (BIOSCD_SECSIZE / DEV_BSIZE);
269 DEBUG("read %d from %lld to %p", blks, dblk, buf);
270
271 if (rsize)
272 *rsize = 0;
273 if (blks && bc_read(unit, dblk, blks, buf)) {
274 DEBUG("read error");
275 return (EIO);
276 }
277#ifdef BD_SUPPORT_FRAGS
278 DEBUG("frag read %d from %lld+%d to %p",
279 fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
280 if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf)) {
281 DEBUG("frag read error");
282 return(EIO);
283 }
284 bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize);
285#endif
286 if (rsize)
287 *rsize = size;
288 return (0);
289}
290
291/* Max number of sectors to bounce-buffer at a time. */
292#define CD_BOUNCEBUF 8
293
294static int
295bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
296{
297 u_int maxfer, resid, result, retry, x;
298 caddr_t bbuf, p, xp;
299 int biosdev;
300#ifdef DISK_DEBUG
301 int error;
302#endif
303
304 /* Just in case some idiot actually tries to read -1 blocks... */
305 if (blks < 0)
306 return (-1);
307
308 /* If nothing to do, just return succcess. */
309 if (blks == 0)
310 return (0);
311
312 /* Decide whether we have to bounce */
313 if (VTOP(dest) >> 20 != 0) {
314 /*
315 * The destination buffer is above first 1MB of
316 * physical memory so we have to arrange a suitable
317 * bounce buffer.
318 */
319 x = min(CD_BOUNCEBUF, (unsigned)blks);
320 bbuf = alloca(x * BIOSCD_SECSIZE);
321 maxfer = x;
322 } else {
323 bbuf = NULL;
324 maxfer = 0;
325 }
326
327 biosdev = bc_unit2bios(unit);
328 resid = blks;
329 p = dest;
330
331 while (resid > 0) {
332 if (bbuf)
333 xp = bbuf;
334 else
335 xp = p;
336 x = resid;
337 if (maxfer > 0)
338 x = min(x, maxfer);
339
340 /*
341 * Loop retrying the operation a couple of times. The BIOS
342 * may also retry.
343 */
344 for (retry = 0; retry < 3; retry++) {
345 /* If retrying, reset the drive */
346 if (retry > 0) {
347 v86.ctl = V86_FLAGS;
348 v86.addr = 0x1b;
349 v86.eax = 0x0300 | biosdev;
350 v86int();
351 }
352
353 v86.ctl = V86_FLAGS;
354 v86.addr = 0x1b;
355 v86.eax = 0x0600 | (biosdev & 0x7f);
356 v86.ebx = x * BIOSCD_SECSIZE;
357 v86.ecx = dblk & 0xffff;
358 v86.edx = (dblk >> 16) & 0xffff;
359 v86.ebp = VTOPOFF(xp);
360 v86.es = VTOPSEG(xp);
361 v86int();
362 result = V86_CY(v86.efl);
363 if (result == 0)
364 break;
365 }
366
367#ifdef DISK_DEBUG
368 error = (v86.eax >> 8) & 0xff;
369#endif
370 DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
371 VTOP(p), result ? "failed" : "ok");
372 DEBUG("unit %d status 0x%x", unit, error);
373 if (bbuf != NULL)
374 bcopy(bbuf, p, x * BIOSCD_SECSIZE);
375 p += (x * BIOSCD_SECSIZE);
376 dblk += x;
377 resid -= x;
378 }
379
380/* hexdump(dest, (blks * BIOSCD_SECSIZE)); */
381 return(0);
382}
383
384/*
385 * Return a suitable dev_t value for (dev).
386 */
387int
388bc_getdev(struct i386_devdesc *dev)
389{
390 int biosdev, unit, device;
391 int major;
392 int rootdev;
393
394 unit = dev->d_unit;
395 biosdev = bc_unit2bios(unit);
396 DEBUG("unit %d BIOS device %d", unit, biosdev);
397 if (biosdev == -1) /* not a BIOS device */
398 return(-1);
399
400 device = biosdev & 0xf0;
401 if (device == 0x80)
402 major = ACDMAJOR;
403 else if (device == 0xa0)
404 major = CDMAJOR;
405 else
406 return (-1);
407
408 unit = 0; /* XXX */
409
410 /* XXX: Assume partition 'a'. */
411 rootdev = MAKEBOOTDEV(major, 0, unit, 0);
412 DEBUG("dev is 0x%x\n", rootdev);
413 return(rootdev);
414}
196}
197
198/*
199 * Attempt to open the disk described by (dev) for use by (f).
200 */
201static int
202bc_open(struct open_file *f, ...)
203{
204 va_list ap;
205 struct i386_devdesc *dev;
206
207 va_start(ap, f);
208 dev = va_arg(ap, struct i386_devdesc *);
209 va_end(ap);
210 if (dev->d_unit >= nbcinfo) {
211 DEBUG("attempt to open nonexistent disk");
212 return(ENXIO);
213 }
214
215 BC(dev).bc_open++;
216 if (BC(dev).bc_bcache == NULL)
217 BC(dev).bc_bcache = bcache_allocate();
218 return(0);
219}
220
221static int
222bc_close(struct open_file *f)
223{
224 struct i386_devdesc *dev;
225
226 dev = (struct i386_devdesc *)f->f_devdata;
227 BC(dev).bc_open--;
228 if (BC(dev).bc_open == 0) {
229 bcache_free(BC(dev).bc_bcache);
230 BC(dev).bc_bcache = NULL;
231 }
232 return(0);
233}
234
235static int
236bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
237 char *buf, size_t *rsize)
238{
239 struct bcache_devdata bcd;
240 struct i386_devdesc *dev;
241
242 dev = (struct i386_devdesc *)devdata;
243 bcd.dv_strategy = bc_realstrategy;
244 bcd.dv_devdata = devdata;
245 bcd.dv_cache = BC(dev).bc_bcache;
246
247 return (bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
248}
249
250static int
251bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
252 char *buf, size_t *rsize)
253{
254 struct i386_devdesc *dev;
255 int unit;
256 int blks;
257#ifdef BD_SUPPORT_FRAGS
258 char fragbuf[BIOSCD_SECSIZE];
259 size_t fragsize;
260
261 fragsize = size % BIOSCD_SECSIZE;
262#else
263 if (size % BIOSCD_SECSIZE)
264 return (EINVAL);
265#endif
266
267 if (rw != F_READ)
268 return(EROFS);
269 dev = (struct i386_devdesc *)devdata;
270 unit = dev->d_unit;
271 blks = size / BIOSCD_SECSIZE;
272 if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0)
273 return (EINVAL);
274 dblk /= (BIOSCD_SECSIZE / DEV_BSIZE);
275 DEBUG("read %d from %lld to %p", blks, dblk, buf);
276
277 if (rsize)
278 *rsize = 0;
279 if (blks && bc_read(unit, dblk, blks, buf)) {
280 DEBUG("read error");
281 return (EIO);
282 }
283#ifdef BD_SUPPORT_FRAGS
284 DEBUG("frag read %d from %lld+%d to %p",
285 fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
286 if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf)) {
287 DEBUG("frag read error");
288 return(EIO);
289 }
290 bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize);
291#endif
292 if (rsize)
293 *rsize = size;
294 return (0);
295}
296
297/* Max number of sectors to bounce-buffer at a time. */
298#define CD_BOUNCEBUF 8
299
300static int
301bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
302{
303 u_int maxfer, resid, result, retry, x;
304 caddr_t bbuf, p, xp;
305 int biosdev;
306#ifdef DISK_DEBUG
307 int error;
308#endif
309
310 /* Just in case some idiot actually tries to read -1 blocks... */
311 if (blks < 0)
312 return (-1);
313
314 /* If nothing to do, just return succcess. */
315 if (blks == 0)
316 return (0);
317
318 /* Decide whether we have to bounce */
319 if (VTOP(dest) >> 20 != 0) {
320 /*
321 * The destination buffer is above first 1MB of
322 * physical memory so we have to arrange a suitable
323 * bounce buffer.
324 */
325 x = min(CD_BOUNCEBUF, (unsigned)blks);
326 bbuf = alloca(x * BIOSCD_SECSIZE);
327 maxfer = x;
328 } else {
329 bbuf = NULL;
330 maxfer = 0;
331 }
332
333 biosdev = bc_unit2bios(unit);
334 resid = blks;
335 p = dest;
336
337 while (resid > 0) {
338 if (bbuf)
339 xp = bbuf;
340 else
341 xp = p;
342 x = resid;
343 if (maxfer > 0)
344 x = min(x, maxfer);
345
346 /*
347 * Loop retrying the operation a couple of times. The BIOS
348 * may also retry.
349 */
350 for (retry = 0; retry < 3; retry++) {
351 /* If retrying, reset the drive */
352 if (retry > 0) {
353 v86.ctl = V86_FLAGS;
354 v86.addr = 0x1b;
355 v86.eax = 0x0300 | biosdev;
356 v86int();
357 }
358
359 v86.ctl = V86_FLAGS;
360 v86.addr = 0x1b;
361 v86.eax = 0x0600 | (biosdev & 0x7f);
362 v86.ebx = x * BIOSCD_SECSIZE;
363 v86.ecx = dblk & 0xffff;
364 v86.edx = (dblk >> 16) & 0xffff;
365 v86.ebp = VTOPOFF(xp);
366 v86.es = VTOPSEG(xp);
367 v86int();
368 result = V86_CY(v86.efl);
369 if (result == 0)
370 break;
371 }
372
373#ifdef DISK_DEBUG
374 error = (v86.eax >> 8) & 0xff;
375#endif
376 DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
377 VTOP(p), result ? "failed" : "ok");
378 DEBUG("unit %d status 0x%x", unit, error);
379 if (bbuf != NULL)
380 bcopy(bbuf, p, x * BIOSCD_SECSIZE);
381 p += (x * BIOSCD_SECSIZE);
382 dblk += x;
383 resid -= x;
384 }
385
386/* hexdump(dest, (blks * BIOSCD_SECSIZE)); */
387 return(0);
388}
389
390/*
391 * Return a suitable dev_t value for (dev).
392 */
393int
394bc_getdev(struct i386_devdesc *dev)
395{
396 int biosdev, unit, device;
397 int major;
398 int rootdev;
399
400 unit = dev->d_unit;
401 biosdev = bc_unit2bios(unit);
402 DEBUG("unit %d BIOS device %d", unit, biosdev);
403 if (biosdev == -1) /* not a BIOS device */
404 return(-1);
405
406 device = biosdev & 0xf0;
407 if (device == 0x80)
408 major = ACDMAJOR;
409 else if (device == 0xa0)
410 major = CDMAJOR;
411 else
412 return (-1);
413
414 unit = 0; /* XXX */
415
416 /* XXX: Assume partition 'a'. */
417 rootdev = MAKEBOOTDEV(major, 0, unit, 0);
418 DEBUG("dev is 0x%x\n", rootdev);
419 return(rootdev);
420}