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