1 /* $OpenBSD: biosdev.c,v 1.102 2024/04/14 03:26:25 jsg Exp $ */
2
3 /*
4 * Copyright (c) 1996 Michael Shalayeff
5 * Copyright (c) 2003 Tobias Weingartner
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/disklabel.h>
34 #include <isofs/cd9660/iso.h>
35 #include <lib/libsa/saerrno.h>
36 #include <machine/biosvar.h>
37 #include <machine/tss.h>
38
39 #include "biosdev.h"
40 #include "debug.h"
41 #include "disk.h"
42 #include "libsa.h"
43
44 #ifdef SOFTRAID
45 #include <dev/softraidvar.h>
46 #include <lib/libsa/softraid.h>
47 #include "softraid_i386.h"
48 #endif
49
50 static const char *biosdisk_err(u_int);
51 static int biosdisk_errno(u_int);
52
53 int CHS_rw (int, int, int, int, int, int, void *);
54 static int EDD_rw (int, int, u_int32_t, u_int32_t, void *);
55
56 static int biosd_io(int, bios_diskinfo_t *, u_int, int, void *);
57 static u_int findopenbsd(bios_diskinfo_t *, const char **);
58
59 extern int debug;
60 int bios_bootdev;
61 int bios_cddev = -1; /* Set by srt0 if coming from CD */
62
63 struct EDD_CB {
64 u_int8_t edd_len; /* size of packet */
65 u_int8_t edd_res1; /* reserved */
66 u_int8_t edd_nblk; /* # of blocks to transfer */
67 u_int8_t edd_res2; /* reserved */
68 u_int16_t edd_off; /* address of buffer (offset) */
69 u_int16_t edd_seg; /* address of buffer (segment) */
70 u_int64_t edd_daddr; /* starting block */
71 };
72
73 /*
74 * reset disk system
75 */
76 static int
biosdreset(int dev)77 biosdreset(int dev)
78 {
79 int rv;
80
81 __asm volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
82 : "0" (0), "d" (dev) : "%ecx", "cc");
83
84 return ((rv & 0xff)? rv >> 8 : 0);
85 }
86
87 /*
88 * Fill out a bios_diskinfo_t for this device.
89 * Return 0 if all ok.
90 * Return 1 if not ok.
91 */
92 int
bios_getdiskinfo(int dev,bios_diskinfo_t * pdi)93 bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
94 {
95 u_int rv;
96
97 /* Just reset, don't check return code */
98 rv = biosdreset(dev);
99
100 #ifdef BIOS_DEBUG
101 if (debug)
102 printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
103 #endif
104 __asm volatile (DOINT(0x13) "\n\t"
105 "setc %b0; movzbl %h1, %1\n\t"
106 "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
107 "xchgb %%cl, %%ch; rolb $2, %%ch"
108 : "=a" (rv), "=d" (pdi->bios_heads),
109 "=c" (pdi->bios_cylinders),
110 "=b" (pdi->bios_sectors)
111 : "0" (0x0800), "1" (dev) : "cc");
112
113 #ifdef BIOS_DEBUG
114 if (debug) {
115 printf("getinfo: got #8\n");
116 printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
117 pdi->bios_heads, pdi->bios_sectors);
118 }
119 #endif
120 if (rv & 0xff)
121 return 1;
122
123 /* Fix up info */
124 pdi->bios_number = dev;
125 pdi->bios_heads++;
126 pdi->bios_cylinders &= 0x3ff;
127 pdi->bios_cylinders++;
128
129 /* NOTE:
130 * This currently hangs/reboots some machines
131 * The IBM ThinkPad 750ED for one.
132 *
133 * Funny that an IBM/MS extension would not be
134 * implemented by an IBM system...
135 *
136 * Future hangs (when reported) can be "fixed"
137 * with getSYSCONFaddr() and an exceptions list.
138 */
139 if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev == bios_bootdev)) {
140 int bm;
141
142 #ifdef BIOS_DEBUG
143 if (debug)
144 printf("getinfo: try #41, 0x%x\n", dev);
145 #endif
146 /* EDD support check */
147 __asm volatile(DOINT(0x13) "; setc %b0"
148 : "=a" (rv), "=c" (bm)
149 : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc");
150 if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
151 pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
152 else
153 pdi->bios_edd = -1;
154
155 #ifdef BIOS_DEBUG
156 if (debug) {
157 printf("getinfo: got #41\n");
158 printf("disk 0x%x: 0x%x\n", dev, bm);
159 }
160 #endif
161 /*
162 * If extended disk access functions are not supported
163 * there is not much point on doing EDD.
164 */
165 if (!(pdi->bios_edd & EXT_BM_EDA))
166 pdi->bios_edd = -1;
167 } else
168 pdi->bios_edd = -1;
169
170 /* Skip sanity check for CHS options in EDD mode. */
171 if (pdi->bios_edd != -1)
172 return 0;
173
174 /* Sanity check */
175 if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors)
176 return 1;
177
178 /* CD-ROMs sometimes return heads == 1 */
179 if (pdi->bios_heads < 2)
180 return 1;
181
182 return 0;
183 }
184
185 /*
186 * Read/Write a block from given place using the BIOS.
187 */
188 int
CHS_rw(int rw,int dev,int cyl,int head,int sect,int nsect,void * buf)189 CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf)
190 {
191 int rv;
192
193 rw = rw == F_READ ? 2 : 3;
194 BIOS_regs.biosr_es = (u_int32_t)buf >> 4;
195 __asm volatile ("movb %b7, %h1\n\t"
196 "movb %b6, %%dh\n\t"
197 "andl $0xf, %4\n\t"
198 /* cylinder; the highest 2 bits of cyl is in %cl */
199 "xchgb %%ch, %%cl\n\t"
200 "rorb $2, %%cl\n\t"
201 "orb %b5, %%cl\n\t"
202 "inc %%cx\n\t"
203 DOINT(0x13) "\n\t"
204 "setc %b0"
205 : "=a" (rv)
206 : "0" (nsect), "d" (dev), "c" (cyl),
207 "b" (buf), "m" (sect), "m" (head),
208 "m" (rw)
209 : "cc", "memory");
210
211 return ((rv & 0xff)? rv >> 8 : 0);
212 }
213
214 static __inline int
EDD_rw(int rw,int dev,u_int32_t daddr,u_int32_t nblk,void * buf)215 EDD_rw(int rw, int dev, u_int32_t daddr, u_int32_t nblk, void *buf)
216 {
217 int rv;
218 volatile static struct EDD_CB cb;
219
220 /* Zero out reserved stuff */
221 cb.edd_res1 = 0;
222 cb.edd_res2 = 0;
223
224 /* Fill in parameters */
225 cb.edd_len = sizeof(cb);
226 cb.edd_nblk = nblk;
227 cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff;
228 cb.edd_off = (u_int32_t)buf & 0xf;
229 cb.edd_daddr = daddr;
230
231 /* if offset/segment are zero, punt */
232 if (!cb.edd_seg && !cb.edd_off)
233 return 1;
234
235 /* Call extended read/write (with disk packet) */
236 BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4;
237 __asm volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
238 : "0" ((rw == F_READ)? 0x4200: 0x4300),
239 "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc");
240 return ((rv & 0xff)? rv >> 8 : 0);
241 }
242
243 /*
244 * Read given sector, handling retry/errors/etc.
245 */
246 int
biosd_io(int rw,bios_diskinfo_t * bd,u_int off,int nsect,void * buf)247 biosd_io(int rw, bios_diskinfo_t *bd, u_int off, int nsect, void *buf)
248 {
249 int dev = bd->bios_number;
250 int j, error;
251 void *bb, *bb1 = NULL;
252 int bbsize = nsect * DEV_BSIZE;
253
254 if (bd->flags & BDI_EL_TORITO) { /* It's a CD device */
255 dev &= 0xff; /* Mask out this flag bit */
256
257 /*
258 * sys/lib/libsa/cd9600.c converts 2,048-byte CD sectors
259 * to DEV_BSIZE blocks before calling the device strategy
260 * routine. However, the El Torito spec says that the
261 * BIOS will work in 2,048-byte sectors. So shift back.
262 */
263 off /= (ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE);
264 nsect /= (ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE);
265 }
266
267 /*
268 * Use a bounce buffer to not cross 64k DMA boundary, and to
269 * not access 1 MB or above.
270 */
271 if (((((u_int32_t)buf) & ~0xffff) !=
272 (((u_int32_t)buf + bbsize) & ~0xffff)) ||
273 (((u_int32_t)buf) >= 0x100000)) {
274 bb = bb1 = alloc(bbsize * 2);
275 if ((((u_int32_t)bb) & ~0xffff) !=
276 (((u_int32_t)bb + bbsize - 1) & ~0xffff))
277 bb = (void *)(((u_int32_t)bb + bbsize - 1) & ~0xffff);
278 if (rw != F_READ)
279 bcopy(buf, bb, bbsize);
280 } else
281 bb = buf;
282
283 /* Try to do operation up to 5 times */
284 for (error = 1, j = 5; j-- && error; ) {
285 /* CHS or LBA access? */
286 if (bd->bios_edd != -1) {
287 error = EDD_rw(rw, dev, off, nsect, bb);
288 } else {
289 int cyl, head, sect;
290 size_t i, n;
291 char *p = bb;
292
293 /* Handle track boundaries */
294 for (error = i = 0; error == 0 && i < nsect;
295 i += n, off += n, p += n * DEV_BSIZE) {
296
297 btochs(off, cyl, head, sect, bd->bios_heads,
298 bd->bios_sectors);
299
300 if ((sect + (nsect - i)) >= bd->bios_sectors)
301 n = bd->bios_sectors - sect;
302 else
303 n = nsect - i;
304
305 error = CHS_rw(rw, dev, cyl, head, sect, n, p);
306
307 /* ECC corrected */
308 if (error == 0x11)
309 error = 0;
310 }
311 }
312 switch (error) {
313 case 0x00: /* No errors */
314 case 0x11: /* ECC corrected */
315 error = 0;
316 break;
317
318 default: /* All other errors */
319 #ifdef BIOS_DEBUG
320 if (debug)
321 printf("\nBIOS error 0x%x (%s)\n",
322 error, biosdisk_err(error));
323 #endif
324 biosdreset(dev);
325 break;
326 }
327 }
328
329 if (bb != buf && rw == F_READ)
330 bcopy(bb, buf, bbsize);
331 free(bb1, bbsize * 2);
332
333 #ifdef BIOS_DEBUG
334 if (debug) {
335 if (error != 0)
336 printf("=0x%x(%s)", error, biosdisk_err(error));
337 putchar('\n');
338 }
339 #endif
340
341 return error;
342 }
343
344 #define MAXSECTS 32
345
346 int
biosd_diskio(int rw,struct diskinfo * dip,u_int off,int nsect,void * buf)347 biosd_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
348 {
349 char *dest = buf;
350 int n, ret;
351
352 /*
353 * Avoid doing too large reads, the bounce buffer used by biosd_io()
354 * might run us out-of-mem.
355 */
356 for (ret = 0; ret == 0 && nsect > 0;
357 off += MAXSECTS, dest += MAXSECTS * DEV_BSIZE, nsect -= MAXSECTS) {
358 n = nsect >= MAXSECTS ? MAXSECTS : nsect;
359 ret = biosd_io(rw, &dip->bios_info, off, n, dest);
360 }
361 return ret;
362 }
363
364 /*
365 * Try to read the bsd label on the given BIOS device.
366 */
367 static u_int
findopenbsd(bios_diskinfo_t * bd,const char ** err)368 findopenbsd(bios_diskinfo_t *bd, const char **err)
369 {
370 struct dos_mbr mbr;
371 struct dos_partition *dp;
372 u_int mbroff = DOSBBSECTOR;
373 u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */
374 int error, i, maxebr = DOS_MAXEBR, nextebr;
375
376 again:
377 if (!maxebr--) {
378 *err = "too many extended partitions";
379 return (-1);
380 }
381
382 /* Read MBR */
383 bzero(&mbr, sizeof(mbr));
384 error = biosd_io(F_READ, bd, mbroff, 1, &mbr);
385 if (error) {
386 *err = biosdisk_err(error);
387 return (-1);
388 }
389
390 /* check mbr signature */
391 if (mbr.dmbr_sign != DOSMBR_SIGNATURE) {
392 *err = "bad MBR signature\n";
393 return (-1);
394 }
395
396 /* Search for OpenBSD partition */
397 nextebr = 0;
398 for (i = 0; i < NDOSPART; i++) {
399 dp = &mbr.dmbr_parts[i];
400 if (!dp->dp_size)
401 continue;
402 #ifdef BIOS_DEBUG
403 if (debug)
404 printf("found partition %u: "
405 "type %u (0x%x) offset %u (0x%x)\n",
406 (int)(dp - mbr.dmbr_parts),
407 dp->dp_typ, dp->dp_typ,
408 dp->dp_start, dp->dp_start);
409 #endif
410 if (dp->dp_typ == DOSPTYP_OPENBSD) {
411 if (dp->dp_start > (dp->dp_start + mbroff))
412 continue;
413 return (dp->dp_start + mbroff);
414 }
415
416 /*
417 * Record location of next ebr if and only if this is the first
418 * extended partition in this boot record!
419 */
420 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND ||
421 dp->dp_typ == DOSPTYP_EXTENDL)) {
422 nextebr = dp->dp_start + mbr_eoff;
423 if (nextebr < dp->dp_start)
424 nextebr = (u_int)-1;
425 if (mbr_eoff == DOSBBSECTOR)
426 mbr_eoff = dp->dp_start;
427 }
428 }
429
430 if (nextebr && nextebr != (u_int)-1) {
431 mbroff = nextebr;
432 goto again;
433 }
434
435 return (-1);
436 }
437
438 const char *
bios_getdisklabel(bios_diskinfo_t * bd,struct disklabel * label)439 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
440 {
441 u_int start = 0;
442 char buf[DEV_BSIZE];
443 const char *err = NULL;
444 int error;
445
446 /* Sanity check */
447 if (bd->bios_edd == -1 &&
448 (bd->bios_heads == 0 || bd->bios_sectors == 0))
449 return "failed to read disklabel";
450
451 /* MBR is a harddisk thing */
452 if (bd->bios_number & 0x80) {
453 start = findopenbsd(bd, &err);
454 if (start == (u_int)-1) {
455 if (err != NULL)
456 return (err);
457 return "no OpenBSD partition\n";
458 }
459 }
460
461 /* Load BSD disklabel */
462 #ifdef BIOS_DEBUG
463 if (debug)
464 printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR);
465 #endif
466 /* read disklabel */
467 error = biosd_io(F_READ, bd, start + DOS_LABELSECTOR, 1, buf);
468
469 if (error)
470 return "failed to read disklabel";
471
472 /* Fill in disklabel */
473 return (getdisklabel(buf, label));
474 }
475
476 int
biosopen(struct open_file * f,...)477 biosopen(struct open_file *f, ...)
478 {
479 #ifdef SOFTRAID
480 struct sr_boot_volume *bv;
481 #endif
482 register char *cp, **file;
483 dev_t maj, unit, part;
484 struct diskinfo *dip;
485 int biosdev, devlen;
486 const char *st;
487 va_list ap;
488 char *dev;
489
490 va_start(ap, f);
491 cp = *(file = va_arg(ap, char **));
492 va_end(ap);
493
494 #ifdef BIOS_DEBUG
495 if (debug)
496 printf("%s\n", cp);
497 #endif
498
499 f->f_devdata = NULL;
500
501 /* Search for device specification. */
502 dev = cp;
503 if (cp[4] == ':')
504 devlen = 2;
505 else if (cp[5] == ':')
506 devlen = 3;
507 else
508 return ENOENT;
509 cp += devlen;
510
511 /* Get unit. */
512 if ('0' <= *cp && *cp <= '9')
513 unit = *cp++ - '0';
514 else {
515 printf("Bad unit number\n");
516 return EUNIT;
517 }
518
519 /* Get partition. */
520 if ('a' <= *cp && *cp <= 'p')
521 part = *cp++ - 'a';
522 else {
523 printf("Bad partition\n");
524 return EPART;
525 }
526
527 /* Get filename. */
528 cp++; /* skip ':' */
529 if (*cp != 0)
530 *file = cp;
531 else
532 f->f_flags |= F_RAW;
533
534 #ifdef SOFTRAID
535 /* Intercept softraid disks. */
536 if (strncmp("sr", dev, 2) == 0) {
537 /* We only support read-only softraid. */
538 f->f_flags |= F_NOWRITE;
539
540 /* Create a fake diskinfo for this softraid volume. */
541 SLIST_FOREACH(bv, &sr_volumes, sbv_link)
542 if (bv->sbv_unit == unit)
543 break;
544 if (bv == NULL) {
545 printf("Unknown device: sr%d\n", unit);
546 return EADAPT;
547 }
548
549 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL)
550 if (sr_crypto_unlock_volume(bv) != 0)
551 return EPERM;
552
553 if (bv->sbv_diskinfo == NULL) {
554 dip = alloc(sizeof(struct diskinfo));
555 bzero(dip, sizeof(*dip));
556 dip->strategy = biosstrategy;
557 bv->sbv_diskinfo = dip;
558 dip->sr_vol = bv;
559 dip->bios_info.flags |= BDI_BADLABEL;
560 }
561
562 dip = bv->sbv_diskinfo;
563
564 if (dip->bios_info.flags & BDI_BADLABEL) {
565 /* Attempt to read disklabel. */
566 bv->sbv_part = 'c';
567 if (sr_getdisklabel(bv, &dip->disklabel))
568 return ERDLAB;
569 dip->bios_info.flags &= ~BDI_BADLABEL;
570 check_hibernate(dip);
571 }
572
573 bv->sbv_part = part + 'a';
574
575 bootdev_dip = dip;
576 f->f_devdata = dip;
577
578 return 0;
579 }
580 #endif
581
582 for (maj = 0; maj < nbdevs &&
583 strncmp(dev, bdevs[maj], devlen); maj++);
584 if (maj >= nbdevs) {
585 printf("Unknown device: ");
586 for (cp = *file; *cp != ':'; cp++)
587 putchar(*cp);
588 putchar('\n');
589 return EADAPT;
590 }
591
592 biosdev = unit;
593 switch (maj) {
594 case 0: /* wd */
595 case 4: /* sd */
596 case 17: /* hd */
597 biosdev |= 0x80;
598 break;
599 case 2: /* fd */
600 break;
601 case 6: /* cd */
602 biosdev = bios_bootdev & 0xff;
603 break;
604 default:
605 return ENXIO;
606 }
607
608 /* Find device */
609 bootdev_dip = dip = dklookup(biosdev);
610
611 /* Fix up bootdev */
612 { dev_t bsd_dev;
613 bsd_dev = dip->bios_info.bsd_dev;
614 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
615 B_CONTROLLER(bsd_dev), unit, part);
616 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
617 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
618 }
619
620 #if 0
621 dip->bios_info.bsd_dev = dip->bootdev;
622 bootdev = dip->bootdev;
623 #endif
624
625 #ifdef BIOS_DEBUG
626 if (debug) {
627 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
628 dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
629 dip->bios_info.bios_edd);
630 }
631 #endif
632
633 /* Try for disklabel again (might be removable media) */
634 if (dip->bios_info.flags & BDI_BADLABEL) {
635 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel);
636 #ifdef BIOS_DEBUG
637 if (debug && st)
638 printf("%s\n", st);
639 #endif
640 if (!st) {
641 dip->bios_info.flags &= ~BDI_BADLABEL;
642 dip->bios_info.flags |= BDI_GOODLABEL;
643 } else
644 return ERDLAB;
645 }
646
647 f->f_devdata = dip;
648
649 return 0;
650 }
651
652 const u_char bidos_errs[] =
653 /* ignored "\x00" "successful completion\0" */
654 "\x01" "invalid function/parameter\0"
655 "\x02" "address mark not found\0"
656 "\x03" "write-protected\0"
657 "\x04" "sector not found\0"
658 "\x05" "reset failed\0"
659 "\x06" "disk changed\0"
660 "\x07" "drive parameter activity failed\0"
661 "\x08" "DMA overrun\0"
662 "\x09" "data boundary error\0"
663 "\x0A" "bad sector detected\0"
664 "\x0B" "bad track detected\0"
665 "\x0C" "invalid media\0"
666 "\x0E" "control data address mark detected\0"
667 "\x0F" "DMA arbitration level out of range\0"
668 "\x10" "uncorrectable CRC or ECC error on read\0"
669 /* ignored "\x11" "data ECC corrected\0" */
670 "\x20" "controller failure\0"
671 "\x31" "no media in drive\0"
672 "\x32" "incorrect drive type in CMOS\0"
673 "\x40" "seek failed\0"
674 "\x80" "operation timed out\0"
675 "\xAA" "drive not ready\0"
676 "\xB0" "volume not locked in drive\0"
677 "\xB1" "volume locked in drive\0"
678 "\xB2" "volume not removable\0"
679 "\xB3" "volume in use\0"
680 "\xB4" "lock count exceeded\0"
681 "\xB5" "valid eject request failed\0"
682 "\xBB" "undefined error\0"
683 "\xCC" "write fault\0"
684 "\xE0" "status register error\0"
685 "\xFF" "sense operation failed\0"
686 "\x00" "\0";
687
688 static const char *
biosdisk_err(u_int error)689 biosdisk_err(u_int error)
690 {
691 register const u_char *p = bidos_errs;
692
693 while (*p && *p != error)
694 while (*p++);
695
696 return ++p;
697 }
698
699 const struct biosdisk_errors {
700 u_char error;
701 u_char errno;
702 } tab[] = {
703 { 0x01, EINVAL },
704 { 0x03, EROFS },
705 { 0x08, EINVAL },
706 { 0x09, EINVAL },
707 { 0x0A, EBSE },
708 { 0x0B, EBSE },
709 { 0x0C, ENXIO },
710 { 0x0D, EINVAL },
711 { 0x10, EECC },
712 { 0x20, EHER },
713 { 0x31, ENXIO },
714 { 0x32, ENXIO },
715 { 0x00, EIO }
716 };
717
718 static int
biosdisk_errno(u_int error)719 biosdisk_errno(u_int error)
720 {
721 register const struct biosdisk_errors *p;
722
723 if (error == 0)
724 return 0;
725
726 for (p = tab; p->error && p->error != error; p++)
727 ;
728
729 return p->errno;
730 }
731
732 int
biosstrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)733 biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
734 size_t *rsize)
735 {
736 struct diskinfo *dip = (struct diskinfo *)devdata;
737 u_int8_t error = 0;
738 size_t nsect;
739
740 #ifdef SOFTRAID
741 /* Intercept strategy for softraid volumes. */
742 if (dip->sr_vol)
743 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
744 #endif
745
746 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
747 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset;
748
749 /* Read all, sub-functions handle track boundaries */
750 if (blk < 0)
751 error = EINVAL;
752 else
753 error = biosd_diskio(rw, dip, blk, nsect, buf);
754
755 #ifdef BIOS_DEBUG
756 if (debug) {
757 if (error != 0)
758 printf("=0x%x(%s)", error, biosdisk_err(error));
759 putchar('\n');
760 }
761 #endif
762
763 if (rsize != NULL)
764 *rsize = nsect * DEV_BSIZE;
765
766 return (biosdisk_errno(error));
767 }
768
769 int
biosclose(struct open_file * f)770 biosclose(struct open_file *f)
771 {
772 f->f_devdata = NULL;
773
774 return 0;
775 }
776
777 int
biosioctl(struct open_file * f,u_long cmd,void * data)778 biosioctl(struct open_file *f, u_long cmd, void *data)
779 {
780 return 0;
781 }
782