1 /* $NetBSD: biosdisk.c,v 1.29 2009/09/13 22:45:27 jmcneill Exp $ */
4 * Copyright (c) 1996, 1998
5 * Matthias Drochner. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * raw BIOS disk device for libsa.
31 * needs lowlevel parts from bios_disk.S and biosdisk_ll.c
32 * partly from netbsd:sys/arch/i386/boot/disk.c
35 * A lot of this must match sys/kern/subr_disk_mbr.c
39 * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
41 * Mach Operating System
42 * Copyright (c) 1992, 1991 Carnegie Mellon University
43 * All Rights Reserved.
45 * Permission to use, copy, modify and distribute this software and its
46 * documentation is hereby granted, provided that both the copyright
47 * notice and this permission notice appear in all copies of the
48 * software, derivative works or modified versions, and any portions
49 * thereof, and that both notices appear in supporting documentation.
51 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
52 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
53 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
55 * Carnegie Mellon requests users of this software to return to
57 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
58 * School of Computer Science
59 * Carnegie Mellon University
60 * Pittsburgh PA 15213-3890
62 * any improvements or extensions that they make and grant Carnegie Mellon
63 * the rights to redistribute these changes.
70 #include <sys/types.h>
72 #include <sys/param.h>
73 #include <sys/disklabel.h>
75 #include <fs/cd9660/iso.h>
77 #include <lib/libsa/stand.h>
78 #include <lib/libsa/saerrno.h>
79 #include <machine/stdarg.h>
80 #include <machine/cpu.h>
83 #include "biosdisk_ll.h"
89 #define BUFSIZE 2048 /* must be large enough for a CD sector */
92 struct biosdisk_ll ll
;
98 static struct btinfo_bootdisk bi_disk
;
99 static struct btinfo_bootwedge bi_wedge
;
102 #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */
105 biosdisk_strategy(void *devdata
, int flag
, daddr_t dblk
, size_t size
,
106 void *buf
, size_t *rsize
)
114 d
= (struct biosdisk
*) devdata
;
116 if (d
->ll
.type
== BIOSDISK_TYPE_CD
)
117 dblk
= dblk
* DEV_BSIZE
/ ISO_DEFAULT_BLOCK_SIZE
;
121 blks
= size
/ d
->ll
.secsize
;
122 if (blks
&& readsects(&d
->ll
, dblk
, blks
, buf
, 0)) {
129 frag
= size
% d
->ll
.secsize
;
131 if (readsects(&d
->ll
, dblk
+ blks
, 1, d
->buf
, 0)) {
133 *rsize
= blks
* d
->ll
.secsize
;
136 memcpy(buf
+ blks
* d
->ll
.secsize
, d
->buf
, frag
);
144 static struct biosdisk
*
145 alloc_biosdisk(int biosdev
)
149 d
= alloc(sizeof(*d
));
152 memset(d
, 0, sizeof(*d
));
155 if (set_geometry(&d
->ll
, NULL
)) {
157 printf("no geometry information\n");
159 dealloc(d
, sizeof(*d
));
167 check_label(struct biosdisk
*d
, int sector
)
169 struct disklabel
*lp
;
171 /* find partition in NetBSD disklabel */
172 if (readsects(&d
->ll
, sector
+ LABELSECTOR
, 1, d
->buf
, 0)) {
174 printf("Error reading disklabel\n");
178 lp
= (struct disklabel
*) (d
->buf
+ LABELOFFSET
);
179 if (lp
->d_magic
!= DISKMAGIC
|| dkcksum(lp
)) {
181 printf("warning: no disklabel in sector %u\n", sector
);
191 read_label(struct biosdisk
*d
)
193 struct disklabel dflt_lbl
;
194 struct mbr_partition mbr
[MBR_PART_COUNT
];
199 int ext_base
, this_ext
, next_ext
;
200 #ifdef COMPAT_386BSD_MBRPART
201 int sector_386bsd
= -1;
204 memset(&dflt_lbl
, 0, sizeof(dflt_lbl
));
205 dflt_lbl
.d_npartitions
= 8;
209 if (d
->ll
.type
!= BIOSDISK_TYPE_HD
)
210 /* No label on floppy and CD */
214 * find NetBSD Partition in DOS partition table
220 this_ext
= ext_base
+ next_ext
;
222 if (readsects(&d
->ll
, this_ext
, 1, d
->buf
, 0)) {
224 printf("error reading MBR sector %d\n", this_ext
);
228 memcpy(&mbr
, ((struct mbr_sector
*)d
->buf
)->mbr_parts
,
230 /* Look for NetBSD partition ID */
231 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
232 typ
= mbr
[i
].mbrp_type
;
235 sector
= this_ext
+ mbr
[i
].mbrp_start
;
237 printf("ptn type %d in sector %u\n", typ
, sector
);
239 if (typ
== MBR_PTYPE_NETBSD
) {
240 error
= check_label(d
, sector
);
244 if (MBR_IS_EXTENDED(typ
)) {
245 next_ext
= mbr
[i
].mbrp_start
;
248 #ifdef COMPAT_386BSD_MBRPART
249 if (this_ext
== 0 && typ
== MBR_PTYPE_386BSD
)
250 sector_386bsd
= sector
;
253 if (dflt_lbl
.d_npartitions
>= MAXPARTITIONS
)
255 p
= &dflt_lbl
.d_partitions
[dflt_lbl
.d_npartitions
++];
257 p
= &dflt_lbl
.d_partitions
[i
];
258 p
->p_offset
= sector
;
259 p
->p_size
= mbr
[i
].mbrp_size
;
260 p
->p_fstype
= xlat_mbr_fstype(typ
);
271 #ifdef COMPAT_386BSD_MBRPART
272 if (sector_386bsd
!= -1) {
273 printf("old BSD partition ID!\n");
274 sector
= sector_386bsd
;
281 * 2. no NetBSD partition in MBR
283 * We simply default to "start of disk" in this case and
286 error
= check_label(d
, sector
);
291 * Nothing at start of disk, return info from mbr partitions.
293 /* XXX fill it to make checksum match kernel one */
294 dflt_lbl
.d_checksum
= dkcksum(&dflt_lbl
);
295 memcpy(d
->buf
, &dflt_lbl
, sizeof(dflt_lbl
));
298 #endif /* NO_DISKLABEL */
304 struct disklabel
*lp
;
308 struct biosdisk_extinfo ed
;
312 for (i
= 0; i
< MAX_BIOSDISKS
+ 2; i
++) {
314 memset(&d
, 0, sizeof(d
));
315 memset(&ed
, 0, sizeof(ed
));
316 if (i
>= MAX_BIOSDISKS
)
317 d
.ll
.dev
= 0x00 + i
- MAX_BIOSDISKS
; /* fd */
319 d
.ll
.dev
= 0x80 + i
; /* hd/cd */
320 if (set_geometry(&d
.ll
, &ed
))
324 case BIOSDISK_TYPE_CD
:
325 printf("cd0\n cd0a\n");
327 case BIOSDISK_TYPE_FD
:
328 printf("fd%d\n", d
.ll
.dev
& 0x7f);
329 printf(" fd%da\n", d
.ll
.dev
& 0x7f);
331 case BIOSDISK_TYPE_HD
:
332 printf("hd%d", d
.ll
.dev
& 0x7f);
333 if (d
.ll
.flags
& BIOSDISK_INT13EXT
) {
335 size
= ed
.totsec
* ed
.sbytes
;
336 if (size
>= (10ULL * 1024 * 1024 * 1024))
338 size
/ (1024 * 1024 * 1024));
341 size
/ (1024 * 1024));
347 if (d
.ll
.type
!= BIOSDISK_TYPE_HD
)
349 if (read_label(&d
) == -1)
351 lp
= (struct disklabel
*)(d
.buf
+ LABELOFFSET
);
352 for (part
= 0; part
< lp
->d_npartitions
; part
++) {
353 if (lp
->d_partitions
[part
].p_size
== 0)
355 if (lp
->d_partitions
[part
].p_fstype
== FS_UNUSED
)
361 printf(" hd%d%c(", d
.ll
.dev
& 0x7f, part
+ 'a');
362 if (lp
->d_partitions
[part
].p_fstype
< FSMAXTYPES
)
364 fstypenames
[lp
->d_partitions
[part
].p_fstype
]);
366 printf("%d", lp
->d_partitions
[part
].p_fstype
);
375 /* Determine likely partition for possible sector number of dos
380 biosdisk_findpartition(int biosdev
, u_int sector
)
387 struct disklabel
*lp
;
389 printf("looking for partition device %x, sector %u\n", biosdev
, sector
);
392 /* Look for netbsd partition that is the dos boot one */
393 d
= alloc_biosdisk(biosdev
);
397 if (read_label(d
) == 0) {
398 lp
= (struct disklabel
*)(d
->buf
+ LABELOFFSET
);
399 for (partition
= lp
->d_npartitions
; --partition
;){
400 if (lp
->d_partitions
[partition
].p_fstype
== FS_UNUSED
)
402 if (lp
->d_partitions
[partition
].p_offset
== sector
)
407 dealloc(d
, sizeof(*d
));
409 #endif /* NO_DISKLABEL */
413 biosdisk_open(struct open_file
*f
, ...)
414 /* struct open_file *f, int biosdev, int partition */
421 struct disklabel
*lp
;
426 biosdev
= va_arg(ap
, int);
427 d
= alloc_biosdisk(biosdev
);
433 partition
= va_arg(ap
, int);
435 bi_disk
.biosdev
= d
->ll
.dev
;
436 bi_disk
.partition
= partition
;
437 bi_disk
.labelsector
= -1;
439 bi_wedge
.biosdev
= d
->ll
.dev
;
440 bi_wedge
.matchblk
= -1;
444 if (partition
== RAW_PART
)
446 error
= read_label(d
);
454 lp
= (struct disklabel
*) (d
->buf
+ LABELOFFSET
);
455 if (partition
>= lp
->d_npartitions
||
456 lp
->d_partitions
[partition
].p_fstype
== FS_UNUSED
) {
458 printf("illegal partition\n");
464 bi_disk
.labelsector
= d
->boff
+ LABELSECTOR
;
465 bi_disk
.label
.type
= lp
->d_type
;
466 memcpy(bi_disk
.label
.packname
, lp
->d_packname
, 16);
467 bi_disk
.label
.checksum
= lp
->d_checksum
;
469 bi_wedge
.startblk
= lp
->d_partitions
[partition
].p_offset
;
470 bi_wedge
.nblks
= lp
->d_partitions
[partition
].p_size
;
471 bi_wedge
.matchblk
= d
->boff
+ LABELSECTOR
;
472 bi_wedge
.matchnblks
= 1;
477 MD5Update(&ctx
, (void *) d
->buf
, 512);
478 MD5Final(bi_wedge
.matchhash
, &ctx
);
481 d
->boff
= lp
->d_partitions
[partition
].p_offset
;
482 if (lp
->d_partitions
[partition
].p_fstype
== FS_RAID
)
483 d
->boff
+= RF_PROTECTED_SECTORS
;
485 #endif /* NO_DISKLABEL */
488 printf("partition @%d\n", d
->boff
);
492 BI_ADD(&bi_disk
, BTINFO_BOOTDISK
, sizeof(bi_disk
));
493 BI_ADD(&bi_wedge
, BTINFO_BOOTWEDGE
, sizeof(bi_wedge
));
500 dealloc(d
, sizeof(struct biosdisk
));
504 #ifndef LIBSA_NO_FS_CLOSE
506 biosdisk_close(struct open_file
*f
)
508 struct biosdisk
*d
= f
->f_devdata
;
510 /* let the floppy drive go off */
511 if (d
->ll
.type
== BIOSDISK_TYPE_FD
)
512 delay(3000000); /* 2s is enough on all PCs I found */
514 dealloc(d
, sizeof(struct biosdisk
));
521 biosdisk_ioctl(struct open_file
*f
, u_long cmd
, void *arg
)