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