This source file includes following definitions.
- biosdreset
- bios_getdiskinfo
- CHS_rw
- EDD_rw
- biosd_io
- bios_getdisklabel
- biosopen
- biosdisk_err
- biosdisk_errno
- biosstrategy
- biosclose
- biosioctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/disklabel.h>
34 #include <machine/tss.h>
35 #include <machine/biosvar.h>
36 #include <lib/libsa/saerrno.h>
37 #include <isofs/cd9660/iso.h>
38 #include "disk.h"
39 #include "debug.h"
40 #include "libsa.h"
41 #include "biosdev.h"
42
43 static const char *biosdisk_err(u_int);
44 static int biosdisk_errno(u_int);
45
46 static int CHS_rw (int, int, int, int, int, int, void *);
47 static int EDD_rw (int, int, u_int64_t, u_int32_t, void *);
48
49 extern int debug;
50 int bios_bootdev;
51 int bios_cddev = -1;
52
53 #if 0
54 struct biosdisk {
55 bios_diskinfo_t *bios_info;
56 dev_t bsddev;
57 struct disklabel disklabel;
58 };
59 #endif
60
61 struct EDD_CB {
62 u_int8_t edd_len;
63 u_int8_t edd_res1;
64 u_int8_t edd_nblk;
65 u_int8_t edd_res2;
66 u_int16_t edd_off;
67 u_int16_t edd_seg;
68 u_int64_t edd_daddr;
69 };
70
71
72
73
74 static int
75 biosdreset(int dev)
76 {
77 int rv;
78
79 __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
80 : "0" (0), "d" (dev) : "%ecx", "cc");
81
82 return ((rv & 0xff)? rv >> 8 : 0);
83 }
84
85
86
87
88
89
90 int
91 bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
92 {
93 u_int rv;
94
95
96 rv = biosdreset(dev);
97
98 #ifdef BIOS_DEBUG
99 if (debug)
100 printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
101 #endif
102 __asm __volatile (DOINT(0x13) "\n\t"
103 "setc %b0; movzbl %h1, %1\n\t"
104 "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
105 "xchgb %%cl, %%ch; rolb $2, %%ch"
106 : "=a" (rv), "=d" (pdi->bios_heads),
107 "=c" (pdi->bios_cylinders),
108 "=b" (pdi->bios_sectors)
109 : "0" (0x0800), "1" (dev) : "cc");
110
111 #ifdef BIOS_DEBUG
112 if (debug) {
113 printf("getinfo: got #8\n");
114 printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
115 pdi->bios_heads, pdi->bios_sectors);
116 }
117 #endif
118 if (rv & 0xff)
119 return 1;
120
121
122 pdi->bios_number = dev;
123 pdi->bios_heads++;
124 pdi->bios_cylinders &= 0x3ff;
125 pdi->bios_cylinders++;
126
127
128 if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors)
129 return 1;
130
131
132 if (pdi->bios_heads < 2)
133 return 1;
134
135
136
137
138
139
140
141
142
143
144
145 if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev == bios_bootdev)) {
146 int bm;
147
148 #ifdef BIOS_DEBUG
149 if (debug)
150 printf("getinfo: try #41, 0x%x\n", dev);
151 #endif
152
153 __asm __volatile(DOINT(0x13) "; setc %b0"
154 : "=a" (rv), "=c" (bm)
155 : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc");
156 if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
157 pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
158 else
159 pdi->bios_edd = -1;
160
161 #ifdef BIOS_DEBUG
162 if (debug) {
163 printf("getinfo: got #41\n");
164 printf("disk 0x%x: 0x%x\n", dev, bm);
165 }
166 #endif
167
168
169
170
171 if (!(pdi->bios_edd & EXT_BM_EDA))
172 pdi->bios_edd = -1;
173 } else
174 pdi->bios_edd = -1;
175
176 return 0;
177 }
178
179
180
181
182 static __inline int
183 CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf)
184 {
185 int rv;
186
187 rw = rw == F_READ ? 2 : 3;
188 BIOS_regs.biosr_es = (u_int32_t)buf >> 4;
189 __asm __volatile ("movb %b7, %h1\n\t"
190 "movb %b6, %%dh\n\t"
191 "andl $0xf, %4\n\t"
192
193 "xchgb %%ch, %%cl\n\t"
194 "rorb $2, %%cl\n\t"
195 "orb %b5, %%cl\n\t"
196 "inc %%cx\n\t"
197 DOINT(0x13) "\n\t"
198 "setc %b0"
199 : "=a" (rv)
200 : "0" (nsect), "d" (dev), "c" (cyl),
201 "b" (buf), "m" (sect), "m" (head),
202 "m" (rw)
203 : "cc", "memory");
204
205 return ((rv & 0xff)? rv >> 8 : 0);
206 }
207
208 static __inline int
209 EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf)
210 {
211 int rv;
212 volatile static struct EDD_CB cb;
213
214
215 cb.edd_res1 = 0;
216 cb.edd_res2 = 0;
217
218
219 cb.edd_len = sizeof(cb);
220 cb.edd_nblk = nblk;
221 cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff;
222 cb.edd_off = (u_int32_t)buf & 0xf;
223 cb.edd_daddr = daddr;
224
225
226 if (!cb.edd_seg && !cb.edd_off)
227 return 1;
228
229
230 BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4;
231 __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
232 : "0" ((rw == F_READ)? 0x4200: 0x4300),
233 "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc");
234 return ((rv & 0xff)? rv >> 8 : 0);
235 }
236
237
238
239
240 int
241 biosd_io(int rw, bios_diskinfo_t *bd, daddr_t off, int nsect, void *buf)
242 {
243 int dev = bd->bios_number;
244 int j, error;
245 void *bb;
246 int bbsize = nsect * DEV_BSIZE;
247
248 if (bd->flags & BDI_EL_TORITO) {
249 dev &= 0xff;
250
251
252
253
254
255
256
257 off >>= (ISO_DEFAULT_BLOCK_SHIFT - DEV_BSHIFT);
258 nsect >>= (ISO_DEFAULT_BLOCK_SHIFT - DEV_BSHIFT);
259 }
260
261
262
263
264
265 if (((((u_int32_t)buf) & ~0xffff) !=
266 (((u_int32_t)buf + bbsize) & ~0xffff)) ||
267 (((u_int32_t)buf) >= 0x100000)) {
268
269
270
271
272 bb = alloca(bbsize);
273 if (rw != F_READ)
274 bcopy(buf, bb, bbsize);
275 } else
276 bb = buf;
277
278
279 for (error = 1, j = 5; j-- && error; ) {
280
281 if (bd->bios_edd != -1) {
282 error = EDD_rw(rw, dev, off, nsect, bb);
283 } else {
284 int cyl, head, sect;
285 size_t i, n;
286 char *p = bb;
287
288
289 for (error = i = 0; error == 0 && i < nsect;
290 i += n, off += n, p += n * DEV_BSIZE) {
291
292 btochs(off, cyl, head, sect, bd->bios_heads,
293 bd->bios_sectors);
294
295 if ((sect + (nsect - i)) >= bd->bios_sectors)
296 n = bd->bios_sectors - sect;
297 else
298 n = nsect - i;
299
300 error = CHS_rw(rw, dev, cyl, head, sect, n, p);
301
302
303 if (error == 0x11)
304 error = 0;
305 }
306 }
307 switch (error) {
308 case 0x00:
309 case 0x11:
310 error = 0;
311 break;
312
313 default:
314 #ifdef BIOS_DEBUG
315 if (debug)
316 printf("\nBIOS error 0x%x (%s)\n",
317 error, biosdisk_err(error));
318 #endif
319 biosdreset(dev);
320 break;
321 }
322 }
323
324 if (bb != buf && rw == F_READ)
325 bcopy(bb, buf, bbsize);
326
327 #ifdef BIOS_DEBUG
328 if (debug) {
329 if (error != 0)
330 printf("=0x%x(%s)", error, biosdisk_err(error));
331 putchar('\n');
332 }
333 #endif
334
335 return error;
336 }
337
338
339
340
341 const char *
342 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
343 {
344 daddr_t off = LABELSECTOR;
345 char *buf;
346 struct dos_mbr mbr;
347 int error, i;
348
349
350 if (bd->bios_heads == 0 || bd->bios_sectors == 0)
351 return "failed to read disklabel";
352
353
354 if (bd->bios_number & 0x80) {
355
356 error = biosd_io(F_READ, bd, DOSBBSECTOR, 1, &mbr);
357 if (error)
358 return (biosdisk_err(error));
359
360
361 if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
362 return "bad MBR signature\n";
363
364
365 for (off = 0, i = 0; off == 0 && i < NDOSPART; i++)
366 if (mbr.dmbr_parts[i].dp_typ == DOSPTYP_OPENBSD)
367 off = mbr.dmbr_parts[i].dp_start + LABELSECTOR;
368 if (off == 0)
369 return "no OpenBSD partition\n";
370 } else
371 off = LABELSECTOR;
372
373
374 buf = alloca(DEV_BSIZE);
375 #ifdef BIOS_DEBUG
376 if (debug)
377 printf("loading disklabel @ %u\n", off);
378 #endif
379
380 error = biosd_io(F_READ, bd, off, 1, buf);
381
382 if (error)
383 return "failed to read disklabel";
384
385
386 return (getdisklabel(buf, label));
387 }
388
389 int
390 biosopen(struct open_file *f, ...)
391 {
392 va_list ap;
393 register char *cp, **file;
394 dev_t maj, unit, part;
395 struct diskinfo *dip;
396 int biosdev;
397
398 va_start(ap, f);
399 cp = *(file = va_arg(ap, char **));
400 va_end(ap);
401
402 #ifdef BIOS_DEBUG
403 if (debug)
404 printf("%s\n", cp);
405 #endif
406
407 f->f_devdata = NULL;
408
409 cp += 2;
410 if (cp[2] != ':') {
411 if (cp[3] != ':')
412 return ENOENT;
413 else
414 cp++;
415 }
416
417 for (maj = 0; maj < nbdevs && strncmp(*file, bdevs[maj], cp - *file); )
418 maj++;
419 if (maj >= nbdevs) {
420 printf("Unknown device: ");
421 for (cp = *file; *cp != ':'; cp++)
422 putchar(*cp);
423 putchar('\n');
424 return EADAPT;
425 }
426
427
428 if ('0' <= *cp && *cp <= '9')
429 unit = *cp++ - '0';
430 else {
431 printf("Bad unit number\n");
432 return EUNIT;
433 }
434
435 if ('a' <= *cp && *cp <= 'p')
436 part = *cp++ - 'a';
437 else {
438 printf("Bad partition id\n");
439 return EPART;
440 }
441
442 cp++;
443 if (*cp != 0)
444 *file = cp;
445 else
446 f->f_flags |= F_RAW;
447
448 biosdev = unit;
449 switch (maj) {
450 case 0:
451 case 4:
452 case 17:
453 biosdev |= 0x80;
454 break;
455 case 2:
456 break;
457 case 6:
458 biosdev = bios_bootdev & 0xff;
459 break;
460 default:
461 return ENXIO;
462 }
463
464
465 bootdev_dip = dip = dklookup(biosdev);
466
467
468 { dev_t bsd_dev;
469 bsd_dev = dip->bios_info.bsd_dev;
470 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
471 B_CONTROLLER(bsd_dev), unit, part);
472 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
473 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
474 }
475
476 #if 0
477 dip->bios_info.bsd_dev = dip->bootdev;
478 bootdev = dip->bootdev;
479 #endif
480
481 #ifdef BIOS_DEBUG
482 if (debug) {
483 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
484 dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
485 dip->bios_info.bios_edd);
486 }
487 #endif
488
489
490 if (dip->bios_info.flags & BDI_BADLABEL){
491 const char *st = bios_getdisklabel(&dip->bios_info,
492 &dip->disklabel);
493 #ifdef BIOS_DEBUG
494 if (debug && st)
495 printf("%s\n", st);
496 #endif
497 if (!st) {
498 dip->bios_info.flags &= ~BDI_BADLABEL;
499 dip->bios_info.flags |= BDI_GOODLABEL;
500 } else
501 return ERDLAB;
502 }
503
504 f->f_devdata = dip;
505
506 return 0;
507 }
508
509 const u_char bidos_errs[] =
510
511 "\x01" "invalid function/parameter\0"
512 "\x02" "address mark not found\0"
513 "\x03" "write-protected\0"
514 "\x04" "sector not found\0"
515 "\x05" "reset failed\0"
516 "\x06" "disk changed\0"
517 "\x07" "drive parameter activity failed\0"
518 "\x08" "DMA overrun\0"
519 "\x09" "data boundary error\0"
520 "\x0A" "bad sector detected\0"
521 "\x0B" "bad track detected\0"
522 "\x0C" "invalid media\0"
523 "\x0E" "control data address mark detected\0"
524 "\x0F" "DMA arbitration level out of range\0"
525 "\x10" "uncorrectable CRC or ECC error on read\0"
526
527 "\x20" "controller failure\0"
528 "\x31" "no media in drive\0"
529 "\x32" "incorrect drive type in CMOS\0"
530 "\x40" "seek failed\0"
531 "\x80" "operation timed out\0"
532 "\xAA" "drive not ready\0"
533 "\xB0" "volume not locked in drive\0"
534 "\xB1" "volume locked in drive\0"
535 "\xB2" "volume not removable\0"
536 "\xB3" "volume in use\0"
537 "\xB4" "lock count exceeded\0"
538 "\xB5" "valid eject request failed\0"
539 "\xBB" "undefined error\0"
540 "\xCC" "write fault\0"
541 "\xE0" "status register error\0"
542 "\xFF" "sense operation failed\0"
543 "\x00" "\0";
544
545 static const char *
546 biosdisk_err(u_int error)
547 {
548 register const u_char *p = bidos_errs;
549
550 while (*p && *p != error)
551 while (*p++);
552
553 return ++p;
554 }
555
556 const struct biosdisk_errors {
557 u_char error;
558 u_char errno;
559 } tab[] = {
560 { 0x01, EINVAL },
561 { 0x03, EROFS },
562 { 0x08, EINVAL },
563 { 0x09, EINVAL },
564 { 0x0A, EBSE },
565 { 0x0B, EBSE },
566 { 0x0C, ENXIO },
567 { 0x0D, EINVAL },
568 { 0x10, EECC },
569 { 0x20, EHER },
570 { 0x31, ENXIO },
571 { 0x32, ENXIO },
572 { 0x00, EIO }
573 };
574
575 static int
576 biosdisk_errno(u_int error)
577 {
578 register const struct biosdisk_errors *p;
579
580 if (error == 0)
581 return 0;
582
583 for (p = tab; p->error && p->error != error; p++);
584
585 return p->errno;
586 }
587
588 int
589 biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
590 size_t *rsize)
591 {
592 struct diskinfo *dip = (struct diskinfo *)devdata;
593 bios_diskinfo_t *bd = &dip->bios_info;
594 u_int8_t error = 0;
595 size_t nsect;
596
597 nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
598 if (rsize != NULL)
599 blk += dip->disklabel.
600 d_partitions[B_PARTITION(dip->bsddev)].p_offset;
601
602
603 error = biosd_io(rw, bd, blk, nsect, buf);
604
605 #ifdef BIOS_DEBUG
606 if (debug) {
607 if (error != 0)
608 printf("=0x%x(%s)", error, biosdisk_err(error));
609 putchar('\n');
610 }
611 #endif
612
613 if (rsize != NULL)
614 *rsize = nsect * DEV_BSIZE;
615
616 return (biosdisk_errno(error));
617 }
618
619 int
620 biosclose(struct open_file *f)
621 {
622 f->f_devdata = NULL;
623
624 return 0;
625 }
626
627 int
628 biosioctl(struct open_file *f, u_long cmd, void *data)
629 {
630 return 0;
631 }