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