1 /* $NetBSD: biosdisk.c,v 1.12 1999/08/03 19:46:22 drochner 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@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@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 #define BUFSIZE (1 * BIOSDISK_SECSIZE) 85 86 struct biosdisk { 87 struct biosdisk_ll ll; 88 #ifdef COMPAT_OLDBOOT 89 int disktype; 90 #endif 91 int boff; 92 char buf[BUFSIZE]; 93 }; 94 95 #ifdef _STANDALONE 96 static struct btinfo_bootdisk bi_disk; 97 #endif 98 99 int 100 biosdiskstrategy(devdata, flag, dblk, size, buf, rsize) 101 void *devdata; 102 int flag; 103 daddr_t dblk; 104 size_t size; 105 void *buf; 106 size_t *rsize; 107 { 108 struct biosdisk *d; 109 int blks, frag; 110 111 if (flag != F_READ) 112 return (EROFS); 113 114 d = (struct biosdisk *) devdata; 115 116 dblk += d->boff; 117 118 blks = size / BIOSDISK_SECSIZE; 119 if (blks && readsects(&d->ll, dblk, blks, buf, 0)) { 120 if (rsize) 121 *rsize = 0; 122 return (EIO); 123 } 124 /* do we really need this? */ 125 frag = size % BIOSDISK_SECSIZE; 126 if (frag) { 127 if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) { 128 if (rsize) 129 *rsize = blks * BIOSDISK_SECSIZE; 130 return (EIO); 131 } 132 bcopy(d->buf, buf + blks * BIOSDISK_SECSIZE, frag); 133 } 134 if (rsize) 135 *rsize = size; 136 return (0); 137 } 138 139 #ifdef COMPAT_OLDBOOT 140 int 141 biosdisk_gettype(f) 142 struct open_file *f; 143 { 144 struct biosdisk *d = f->f_devdata; 145 return (d->disktype); 146 } 147 #endif 148 149 int 150 biosdiskopen(struct open_file *f, ...) 151 /* file, biosdev, partition */ 152 { 153 va_list ap; 154 struct biosdisk *d; 155 int partition; 156 #ifndef NO_DISKLABEL 157 struct mbr_partition *dptr; 158 int sector, i; 159 struct disklabel *lp; 160 #endif 161 int error = 0; 162 163 d = (struct biosdisk *) alloc(sizeof(struct biosdisk)); 164 if (!d) { 165 #ifdef DEBUG 166 printf("biosdiskopen: no memory\n"); 167 #endif 168 return (ENOMEM); 169 } 170 va_start(ap, f); 171 d->ll.dev = va_arg(ap, int); 172 if (set_geometry(&d->ll, NULL)) { 173 #ifdef DISK_DEBUG 174 printf("no geometry information\n"); 175 #endif 176 error = ENXIO; 177 goto out; 178 } 179 180 d->boff = 0; 181 partition = va_arg(ap, int); 182 #ifdef _STANDALONE 183 bi_disk.biosdev = d->ll.dev; 184 bi_disk.partition = partition; 185 bi_disk.labelsector = -1; 186 #endif 187 188 #ifndef NO_DISKLABEL 189 if (!(d->ll.dev & 0x80) /* floppy */ 190 || partition == RAW_PART) 191 goto nolabel; 192 193 /* 194 * find NetBSD Partition in DOS partition table 195 * XXX check magic??? 196 */ 197 if (readsects(&d->ll, 0, 1, d->buf, 0)) { 198 #ifdef DISK_DEBUG 199 printf("error reading MBR\n"); 200 #endif 201 error = EIO; 202 goto out; 203 } 204 sector = -1; 205 dptr = (struct mbr_partition *) & d->buf[MBR_PARTOFF]; 206 /* Look for NetBSD partition ID */ 207 for (i = 0; i < NMBRPART; i++, dptr++) 208 if (dptr->mbrp_typ == MBR_PTYPE_NETBSD) { 209 sector = dptr->mbrp_start; 210 break; 211 } 212 #ifdef COMPAT_386BSD_MBRPART 213 if (sector == -1) { 214 /* If we didn't find one, look for 386BSD partition ID */ 215 dptr = (struct mbr_partition *) & d->buf[MBR_PARTOFF]; 216 for (i = 0; i < NMBRPART; i++, dptr++) 217 if (dptr->mbrp_typ == MBR_PTYPE_386BSD) { 218 printf("old BSD partition ID!\n"); 219 sector = dptr->mbrp_start; 220 break; 221 } 222 } 223 #endif 224 if (sector == -1) { 225 /* 226 * One of two things: 227 * 1. no MBR 228 * 2. no NetBSD partition in MBR 229 * 230 * We simply default to "start of disk" in this case and 231 * press on. 232 */ 233 sector = 0; 234 } 235 236 /* find partition in NetBSD disklabel */ 237 if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) { 238 #ifdef DISK_DEBUG 239 printf("Error reading disklabel\n"); 240 #endif 241 error = EIO; 242 goto out; 243 } 244 lp = (struct disklabel *) (d->buf + LABELOFFSET); 245 if (lp->d_magic != DISKMAGIC) { 246 #ifdef DISK_DEBUG 247 printf("warning: no disklabel\n"); 248 #endif 249 d->boff = sector; 250 } else if (partition >= lp->d_npartitions || 251 lp->d_partitions[partition].p_fstype == FS_UNUSED) { 252 #ifdef DISK_DEBUG 253 printf("illegal partition\n"); 254 #endif 255 error = EPART; 256 goto out; 257 } else { 258 d->boff = lp->d_partitions[partition].p_offset; 259 #ifdef COMPAT_OLDBOOT 260 d->disktype = lp->d_type; 261 #endif 262 #ifdef _STANDALONE 263 bi_disk.labelsector = sector + LABELSECTOR; 264 bi_disk.label.type = lp->d_type; 265 bcopy(lp->d_packname, bi_disk.label.packname, 16); 266 bi_disk.label.checksum = lp->d_checksum; 267 #endif 268 } 269 nolabel: 270 #endif /* NO_DISKLABEL */ 271 272 #ifdef DISK_DEBUG 273 printf("partition @%d\n", d->boff); 274 #endif 275 276 #ifdef _STANDALONE 277 BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk)); 278 #endif 279 280 f->f_devdata = d; 281 out: 282 va_end(ap); 283 if (error) 284 free(d, sizeof(struct biosdisk)); 285 return (error); 286 } 287 288 #ifndef LIBSA_NO_FS_CLOSE 289 int 290 biosdiskclose(f) 291 struct open_file *f; 292 { 293 struct biosdisk *d = f->f_devdata; 294 295 if (!(d->ll.dev & 0x80))/* let the floppy drive go off */ 296 delay(3000000); /* 2s is enough on all PCs I found */ 297 298 free(d, sizeof(struct biosdisk)); 299 f->f_devdata = NULL; 300 return (0); 301 } 302 #endif 303 304 int 305 biosdiskioctl(f, cmd, arg) 306 struct open_file *f; 307 u_long cmd; 308 void *arg; 309 { 310 return EIO; 311 } 312