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@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 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