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}
|