Home | History | Annotate | Line # | Download | only in lib
biosdisk.c revision 1.16
      1 /*	$NetBSD: biosdisk.c,v 1.16 2003/02/01 14:48:17 dsl Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996, 1998
      5  *	Matthias Drochner.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     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.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed for the NetBSD Project
     18  *	by Matthias Drochner.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  *
     33  */
     34 
     35 /*
     36  * raw BIOS disk device for libsa.
     37  * needs lowlevel parts from bios_disk.S and biosdisk_ll.c
     38  * partly from netbsd:sys/arch/i386/boot/disk.c
     39  * no bad144 handling!
     40  */
     41 
     42 /*
     43  * Ported to boot 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992
     44  *
     45  * Mach Operating System
     46  * Copyright (c) 1992, 1991 Carnegie Mellon University
     47  * All Rights Reserved.
     48  *
     49  * Permission to use, copy, modify and distribute this software and its
     50  * documentation is hereby granted, provided that both the copyright
     51  * notice and this permission notice appear in all copies of the
     52  * software, derivative works or modified versions, and any portions
     53  * thereof, and that both notices appear in supporting documentation.
     54  *
     55  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     56  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     57  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     58  *
     59  * Carnegie Mellon requests users of this software to return to
     60  *
     61  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     62  *  School of Computer Science
     63  *  Carnegie Mellon University
     64  *  Pittsburgh PA 15213-3890
     65  *
     66  * any improvements or extensions that they make and grant Carnegie Mellon
     67  * the rights to redistribute these changes.
     68  */
     69 
     70 #include <sys/types.h>
     71 #include <sys/disklabel.h>
     72 
     73 #include <lib/libsa/stand.h>
     74 #include <lib/libsa/saerrno.h>
     75 #include <machine/stdarg.h>
     76 
     77 #include "libi386.h"
     78 #include "biosdisk_ll.h"
     79 #include "biosdisk.h"
     80 #ifdef _STANDALONE
     81 #include "bootinfo.h"
     82 #endif
     83 
     84 extern void memset(void *, int, size_t);
     85 
     86 #define BUFSIZE (1 * BIOSDISK_SECSIZE)
     87 
     88 struct biosdisk {
     89 	struct biosdisk_ll ll;
     90 	int             boff;
     91 	char            buf[BUFSIZE];
     92 };
     93 
     94 #ifdef _STANDALONE
     95 static struct btinfo_bootdisk bi_disk;
     96 #endif
     97 
     98 #define	RF_PROTECTED_SECTORS	64	/* XXX refer to <.../rf_optnames.h> */
     99 
    100 int boot_biossector;	/* disk sector partition might have started in */
    101 
    102 int
    103 biosdiskstrategy(devdata, flag, dblk, size, buf, rsize)
    104 	void           *devdata;
    105 	int             flag;
    106 	daddr_t         dblk;
    107 	size_t          size;
    108 	void           *buf;
    109 	size_t         *rsize;
    110 {
    111 	struct biosdisk *d;
    112 	int             blks, frag;
    113 
    114 	if (flag != F_READ)
    115 		return (EROFS);
    116 
    117 	d = (struct biosdisk *) devdata;
    118 
    119 	dblk += d->boff;
    120 
    121 	blks = size / BIOSDISK_SECSIZE;
    122 	if (blks && readsects(&d->ll, dblk, blks, buf, 0)) {
    123 		if (rsize)
    124 			*rsize = 0;
    125 		return (EIO);
    126 	}
    127 	/* do we really need this? */
    128 	frag = size % BIOSDISK_SECSIZE;
    129 	if (frag) {
    130 		if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) {
    131 			if (rsize)
    132 				*rsize = blks * BIOSDISK_SECSIZE;
    133 			return (EIO);
    134 		}
    135 		memcpy(buf + blks * BIOSDISK_SECSIZE, d->buf, frag);
    136 	}
    137 	if (rsize)
    138 		*rsize = size;
    139 	return (0);
    140 }
    141 
    142 static struct biosdisk *
    143 alloc_biosdisk(int dev)
    144 {
    145 	struct biosdisk *d;
    146 
    147 	d = (struct biosdisk *)alloc(sizeof *d);
    148 	if (!d)
    149 		return NULL;
    150 	memset(d, 0, sizeof *d);
    151 
    152 	d->ll.dev = dev;;
    153 	if (set_geometry(&d->ll, NULL)) {
    154 #ifdef DISK_DEBUG
    155 		printf("no geometry information\n");
    156 #endif
    157 		free(d, sizeof *d);
    158 		return NULL;
    159 	}
    160 	return d;
    161 }
    162 
    163 #ifndef NO_DISKLABEL
    164 static int
    165 read_label(struct biosdisk *d)
    166 {
    167 	struct mbr_partition *dptr;
    168 	int sector, i;
    169 	struct disklabel *lp;
    170 
    171 	d->boff = 0;
    172 
    173 	if (!(d->ll.dev & 0x80)) /* floppy */
    174 		/* No label on floppy */
    175 		return -1;
    176 
    177 	/*
    178 	 * find NetBSD Partition in DOS partition table
    179 	 * XXX check magic???
    180 	 */
    181 	if (readsects(&d->ll, 0, 1, d->buf, 0)) {
    182 #ifdef DISK_DEBUG
    183 		printf("error reading MBR\n");
    184 #endif
    185 		return EIO;
    186 	}
    187 	sector = -1;
    188 	dptr = (struct mbr_partition *) & d->buf[MBR_PARTOFF];
    189 	/* Look for NetBSD partition ID */
    190 	for (i = 0; i < NMBRPART; i++, dptr++)
    191 		if (dptr->mbrp_typ == MBR_PTYPE_NETBSD) {
    192 			sector = dptr->mbrp_start;
    193 			break;
    194 		}
    195 #ifdef COMPAT_386BSD_MBRPART
    196 	if (sector == -1) {
    197 		/* If we didn't find one, look for 386BSD partition ID */
    198 		dptr = (struct mbr_partition *) & d->buf[MBR_PARTOFF];
    199 		for (i = 0; i < NMBRPART; i++, dptr++)
    200 			if (dptr->mbrp_typ == MBR_PTYPE_386BSD) {
    201 				printf("old BSD partition ID!\n");
    202 				sector = dptr->mbrp_start;
    203 				break;
    204 			}
    205 	}
    206 #endif
    207 	if (sector == -1) {
    208 		/*
    209 		 * One of two things:
    210 		 * 	1. no MBR
    211 		 *	2. no NetBSD partition in MBR
    212 		 *
    213 		 * We simply default to "start of disk" in this case and
    214 		 * press on.
    215 		 */
    216 		sector = 0;
    217 	}
    218 
    219 	d->boff = sector;
    220 
    221 	/* find partition in NetBSD disklabel */
    222 	if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) {
    223 #ifdef DISK_DEBUG
    224 		printf("Error reading disklabel\n");
    225 #endif
    226 		return EIO;
    227 	}
    228 	lp = (struct disklabel *) (d->buf + LABELOFFSET);
    229 	if (lp->d_magic != DISKMAGIC) {
    230 #ifdef DISK_DEBUG
    231 		printf("warning: no disklabel\n");
    232 #endif
    233 		return -1;
    234 	}
    235 	return 0;
    236 }
    237 #endif /* NO_DISKLABEL */
    238 
    239 /* Determine likely partition for possible sector number of dos
    240    partition. */
    241 
    242 u_int
    243 biosdiskfindptn(int biosdev, u_int sector)
    244 {
    245 #ifdef NO_DISKLABEL
    246 	return 0;
    247 #else
    248 	struct biosdisk *d;
    249 	u_int partition = 0;
    250 	struct disklabel *lp;
    251 
    252 	/* Look for netbsd partition that is the dos boot one */
    253 	d = alloc_biosdisk(biosdev);
    254 	if (d != NULL && read_label(d) == 0) {
    255 		lp = (struct disklabel *)(d->buf + LABELOFFSET);
    256 		for (partition = lp->d_npartitions; --partition;){
    257 			if (lp->d_partitions[partition].p_fstype == FS_UNUSED)
    258 				continue;
    259 			if (lp->d_partitions[partition].p_offset == sector)
    260 				break;
    261 		}
    262 	}
    263 
    264 	if (d)
    265 		free(d, sizeof *d);
    266 	return partition;
    267 }
    268 #endif /* NO_DISKLABEL */
    269 
    270 int
    271 biosdiskopen(struct open_file *f, ...)
    272 /* file, biosdev, partition */
    273 {
    274 	va_list ap;
    275 	struct biosdisk *d;
    276 	int partition;
    277 #ifndef NO_DISKLABEL
    278 	struct disklabel *lp;
    279 #endif
    280 	int error = 0;
    281 
    282 	va_start(ap, f);
    283 	d = alloc_biosdisk(va_arg(ap, int));
    284 	if (!d) {
    285 		error = ENXIO;
    286 		goto out;
    287 	}
    288 
    289 	partition = va_arg(ap, int);
    290 #ifdef _STANDALONE
    291 	bi_disk.biosdev = d->ll.dev;
    292 	bi_disk.partition = partition;
    293 	bi_disk.labelsector = -1;
    294 #endif
    295 
    296 #ifndef NO_DISKLABEL
    297 	if (partition == RAW_PART)
    298 		goto nolabel;
    299 	error = read_label(d);
    300 	if (error == -1) {
    301 		error = 0;
    302 		goto nolabel;
    303 	}
    304 	if (error)
    305 		goto out;
    306 
    307 	lp = (struct disklabel *) (d->buf + LABELOFFSET);
    308 	if (partition >= lp->d_npartitions ||
    309 	   lp->d_partitions[partition].p_fstype == FS_UNUSED) {
    310 #ifdef DISK_DEBUG
    311 		printf("illegal partition\n");
    312 #endif
    313 		error = EPART;
    314 		goto out;
    315 	}
    316 #ifdef _STANDALONE
    317 	bi_disk.labelsector = d->boff + LABELSECTOR;
    318 	bi_disk.label.type = lp->d_type;
    319 	memcpy(bi_disk.label.packname, lp->d_packname, 16);
    320 	bi_disk.label.checksum = lp->d_checksum;
    321 #endif
    322 	d->boff = lp->d_partitions[partition].p_offset;
    323 	if (lp->d_partitions[partition].p_fstype == FS_RAID)
    324 		d->boff += RF_PROTECTED_SECTORS;
    325 nolabel:
    326 #endif /* NO_DISKLABEL */
    327 
    328 #ifdef DISK_DEBUG
    329 	printf("partition @%d\n", d->boff);
    330 #endif
    331 
    332 #ifdef _STANDALONE
    333 	BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk));
    334 #endif
    335 
    336 	f->f_devdata = d;
    337 out:
    338         va_end(ap);
    339 	if (error)
    340 		free(d, sizeof(struct biosdisk));
    341 	return (error);
    342 }
    343 
    344 #ifndef LIBSA_NO_FS_CLOSE
    345 int
    346 biosdiskclose(f)
    347 	struct open_file *f;
    348 {
    349 	struct biosdisk *d = f->f_devdata;
    350 
    351 	if (!(d->ll.dev & 0x80))/* let the floppy drive go off */
    352 		delay(3000000);	/* 2s is enough on all PCs I found */
    353 
    354 	free(d, sizeof(struct biosdisk));
    355 	f->f_devdata = NULL;
    356 	return (0);
    357 }
    358 #endif
    359 
    360 int
    361 biosdiskioctl(f, cmd, arg)
    362 	struct open_file *f;
    363 	u_long          cmd;
    364 	void           *arg;
    365 {
    366 	return EIO;
    367 }
    368