1 1.19 phx /* $NetBSD: ofdev.c,v 1.19 2011/08/21 13:12:48 phx Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 1.1 thorpej * Copyright (C) 1995, 1996 TooLs GmbH. 6 1.1 thorpej * All rights reserved. 7 1.1 thorpej * 8 1.1 thorpej * Redistribution and use in source and binary forms, with or without 9 1.1 thorpej * modification, are permitted provided that the following conditions 10 1.1 thorpej * are met: 11 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 12 1.1 thorpej * notice, this list of conditions and the following disclaimer. 13 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 15 1.1 thorpej * documentation and/or other materials provided with the distribution. 16 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 17 1.1 thorpej * must display the following acknowledgement: 18 1.1 thorpej * This product includes software developed by TooLs GmbH. 19 1.1 thorpej * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 1.1 thorpej * derived from this software without specific prior written permission. 21 1.1 thorpej * 22 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.1 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.1 thorpej * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 1.1 thorpej * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 1.1 thorpej * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 1.1 thorpej * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.1 thorpej * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 1.1 thorpej * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 1.1 thorpej * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 thorpej */ 33 1.1 thorpej /* 34 1.1 thorpej * Device I/O routines using Open Firmware 35 1.1 thorpej */ 36 1.2 mycroft 37 1.9 aymeric #include "ofdev.h" 38 1.9 aymeric 39 1.1 thorpej #include <sys/param.h> 40 1.2 mycroft 41 1.1 thorpej #include <netinet/in.h> 42 1.10 simonb 43 1.10 simonb #include <lib/libkern/libkern.h> 44 1.1 thorpej 45 1.9 aymeric #include <lib/libsa/byteorder.h> 46 1.1 thorpej #include <lib/libsa/ufs.h> 47 1.1 thorpej #include <lib/libsa/cd9660.h> 48 1.6 thorpej #include <lib/libsa/dosfs.h> 49 1.1 thorpej #include <lib/libsa/nfs.h> 50 1.1 thorpej 51 1.9 aymeric #include "net.h" 52 1.9 aymeric #include "openfirm.h" 53 1.17 phx #include "mbr.h" 54 1.17 phx #include "rdb.h" 55 1.1 thorpej 56 1.1 thorpej extern char bootdev[]; 57 1.1 thorpej 58 1.6 thorpej #ifdef DEBUG 59 1.6 thorpej # define DPRINTF printf 60 1.8 chs #else 61 1.6 thorpej # define DPRINTF while (0) printf 62 1.8 chs #endif 63 1.6 thorpej 64 1.1 thorpej static char * 65 1.9 aymeric filename(char *str, char *ppart) 66 1.1 thorpej { 67 1.1 thorpej char *cp, *lp; 68 1.1 thorpej char savec; 69 1.1 thorpej int dhandle; 70 1.1 thorpej char devtype[16]; 71 1.8 chs 72 1.1 thorpej lp = str; 73 1.1 thorpej devtype[0] = 0; 74 1.1 thorpej *ppart = 0; 75 1.1 thorpej for (cp = str; *cp; lp = cp) { 76 1.8 chs 77 1.1 thorpej /* For each component of the path name... */ 78 1.8 chs while (*++cp && *cp != '/') 79 1.8 chs ; 80 1.1 thorpej savec = *cp; 81 1.1 thorpej *cp = 0; 82 1.8 chs 83 1.1 thorpej /* ...look whether there is a device with this name */ 84 1.1 thorpej dhandle = OF_finddevice(str); 85 1.1 thorpej *cp = savec; 86 1.1 thorpej if (dhandle == -1) { 87 1.8 chs 88 1.8 chs /* 89 1.8 chs * if not, lp is the delimiter between device and path 90 1.8 chs * if the last component was a block device. 91 1.8 chs */ 92 1.8 chs 93 1.1 thorpej if (!strcmp(devtype, "block")) { 94 1.8 chs 95 1.1 thorpej /* search for arguments */ 96 1.1 thorpej for (cp = lp; 97 1.8 chs --cp >= str && *cp != '/' && *cp != ':';) 98 1.8 chs ; 99 1.18 phx 100 1.1 thorpej if (cp >= str && *cp == ':') { 101 1.8 chs /* 102 1.8 chs * found some arguments, 103 1.8 chs * make OFW ignore them. 104 1.8 chs */ 105 1.1 thorpej *cp = 0; 106 1.8 chs for (cp = lp; *--cp && *cp != ',';) 107 1.8 chs ; 108 1.8 chs if (*++cp >= 'a' && 109 1.8 chs *cp < 'a' + MAXPARTITIONS) 110 1.1 thorpej *ppart = *cp; 111 1.1 thorpej } 112 1.1 thorpej } 113 1.1 thorpej return lp; 114 1.8 chs } 115 1.8 chs if (OF_getprop(dhandle, "device_type", devtype, 116 1.8 chs sizeof devtype) < 0) 117 1.1 thorpej devtype[0] = 0; 118 1.1 thorpej } 119 1.1 thorpej return 0; 120 1.1 thorpej } 121 1.1 thorpej 122 1.17 phx int 123 1.9 aymeric strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 124 1.18 phx size_t *rsize) 125 1.1 thorpej { 126 1.1 thorpej struct of_dev *dev = devdata; 127 1.9 aymeric u_quad_t pos; 128 1.1 thorpej int n; 129 1.8 chs 130 1.1 thorpej if (rw != F_READ) 131 1.1 thorpej return EPERM; 132 1.1 thorpej if (dev->type != OFDEV_DISK) 133 1.1 thorpej panic("strategy"); 134 1.8 chs 135 1.9 aymeric pos = (u_quad_t)((blk + dev->partoff) * dev->bsize); 136 1.8 chs 137 1.1 thorpej for (;;) { 138 1.1 thorpej if (OF_seek(dev->handle, pos) < 0) 139 1.1 thorpej break; 140 1.1 thorpej n = OF_read(dev->handle, buf, size); 141 1.1 thorpej if (n == -2) 142 1.1 thorpej continue; 143 1.1 thorpej if (n < 0) 144 1.1 thorpej break; 145 1.1 thorpej *rsize = n; 146 1.1 thorpej return 0; 147 1.1 thorpej } 148 1.1 thorpej return EIO; 149 1.1 thorpej } 150 1.1 thorpej 151 1.1 thorpej static int 152 1.18 phx devopen_dummy(struct open_file *of, ...) 153 1.18 phx { 154 1.18 phx 155 1.9 aymeric return -1; 156 1.9 aymeric } 157 1.9 aymeric 158 1.9 aymeric static int 159 1.9 aymeric devclose(struct open_file *of) 160 1.1 thorpej { 161 1.1 thorpej struct of_dev *op = of->f_devdata; 162 1.8 chs 163 1.1 thorpej if (op->type == OFDEV_NET) 164 1.1 thorpej net_close(op); 165 1.1 thorpej OF_close(op->handle); 166 1.1 thorpej op->handle = -1; 167 1.9 aymeric return 0; 168 1.1 thorpej } 169 1.1 thorpej 170 1.14 he struct devsw devsw[1] = { 171 1.9 aymeric { "OpenFirmware", strategy, devopen_dummy, devclose, noioctl } 172 1.1 thorpej }; 173 1.1 thorpej int ndevs = sizeof devsw / sizeof devsw[0]; 174 1.1 thorpej 175 1.12 junyoung static struct fs_ops file_system_ufs = FS_OPS(ufs); 176 1.12 junyoung static struct fs_ops file_system_cd9660 = FS_OPS(cd9660); 177 1.12 junyoung static struct fs_ops file_system_dosfs = FS_OPS(dosfs); 178 1.12 junyoung static struct fs_ops file_system_nfs = FS_OPS(nfs); 179 1.1 thorpej 180 1.1 thorpej struct fs_ops file_system[3]; 181 1.1 thorpej int nfsys; 182 1.1 thorpej 183 1.1 thorpej static struct of_dev ofdev = { 184 1.1 thorpej -1, 185 1.1 thorpej }; 186 1.1 thorpej 187 1.1 thorpej char opened_name[256]; 188 1.1 thorpej int floppyboot; 189 1.1 thorpej 190 1.1 thorpej int 191 1.9 aymeric devopen(struct open_file *of, const char *name, char **file) 192 1.1 thorpej { 193 1.1 thorpej char *cp; 194 1.1 thorpej char partition; 195 1.1 thorpej char fname[256]; 196 1.1 thorpej struct disklabel label; 197 1.1 thorpej int handle, part; 198 1.1 thorpej size_t read; 199 1.1 thorpej int error = 0; 200 1.17 phx /* allow disk blocks up to 65536 bytes */ 201 1.17 phx char buf[DEV_BSIZE<<7]; 202 1.1 thorpej 203 1.1 thorpej if (ofdev.handle != -1) 204 1.1 thorpej panic("devopen"); 205 1.1 thorpej if (of->f_flags != F_READ) 206 1.1 thorpej return EPERM; 207 1.18 phx 208 1.1 thorpej strcpy(fname, name); 209 1.1 thorpej cp = filename(fname, &partition); 210 1.1 thorpej if (cp) { 211 1.6 thorpej DPRINTF("filename=%s\n", cp); 212 1.1 thorpej strcpy(buf, cp); 213 1.1 thorpej *cp = 0; 214 1.1 thorpej } 215 1.1 thorpej if (!cp || !*buf) 216 1.1 thorpej strcpy(buf, DEFAULT_KERNEL); 217 1.18 phx 218 1.1 thorpej if (!*fname) 219 1.1 thorpej strcpy(fname, bootdev); 220 1.6 thorpej DPRINTF("fname=%s\n", fname); 221 1.1 thorpej strcpy(opened_name, fname); 222 1.1 thorpej if (partition) { 223 1.1 thorpej cp = opened_name + strlen(opened_name); 224 1.1 thorpej *cp++ = ':'; 225 1.1 thorpej *cp++ = partition; 226 1.1 thorpej *cp = 0; 227 1.1 thorpej } 228 1.1 thorpej if (*buf != '/') 229 1.1 thorpej strcat(opened_name, "/"); 230 1.1 thorpej strcat(opened_name, buf); 231 1.1 thorpej *file = opened_name + strlen(fname) + 1; 232 1.8 chs if (partition) { 233 1.8 chs *file += 2; 234 1.8 chs } 235 1.18 phx 236 1.6 thorpej if ((handle = OF_finddevice(fname)) == -1) { 237 1.6 thorpej DPRINTF("OF_finddevice(\"%s\") failed\n", fname); 238 1.1 thorpej return ENOENT; 239 1.6 thorpej } 240 1.18 phx 241 1.1 thorpej if (OF_getprop(handle, "name", buf, sizeof buf) < 0) 242 1.1 thorpej return ENXIO; 243 1.1 thorpej floppyboot = !strcmp(buf, "floppy"); 244 1.1 thorpej if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0) 245 1.1 thorpej return ENXIO; 246 1.8 chs if (!strcmp(buf, "block")) { 247 1.8 chs /* 248 1.8 chs * For block devices, indicate raw partition 249 1.8 chs * (:0 in OpenFirmware) 250 1.8 chs */ 251 1.1 thorpej strcat(fname, ":0"); 252 1.8 chs } 253 1.18 phx 254 1.15 mrg DPRINTF("calling OF_open(fname=%s)\n", fname); 255 1.1 thorpej if ((handle = OF_open(fname)) == -1) 256 1.1 thorpej return ENXIO; 257 1.5 wiz memset(&ofdev, 0, sizeof ofdev); 258 1.1 thorpej ofdev.handle = handle; 259 1.18 phx 260 1.1 thorpej if (!strcmp(buf, "block")) { 261 1.1 thorpej ofdev.type = OFDEV_DISK; 262 1.1 thorpej ofdev.bsize = DEV_BSIZE; 263 1.8 chs 264 1.18 phx /* First try to read a disklabel from a NetBSD MBR partition */ 265 1.18 phx error = search_mbr_label(&ofdev, 0, buf, &label, 0); 266 1.17 phx 267 1.18 phx if (error == ERDLAB) { 268 1.18 phx /* Try to construct a disklabel from RDB partitions */ 269 1.17 phx error = search_rdb_label(&ofdev, buf, &label); 270 1.18 phx 271 1.18 phx if (error == ERDLAB) { 272 1.18 phx /* At last read a raw NetBSD disklabel */ 273 1.18 phx error = strategy(&ofdev, F_READ, LABELSECTOR, 274 1.18 phx DEV_BSIZE, buf, &read); 275 1.18 phx if (error == 0 && read != DEV_BSIZE) 276 1.18 phx error = EIO; 277 1.18 phx if (error == 0) 278 1.18 phx if (getdisklabel(buf, &label) != NULL) 279 1.18 phx error = ERDLAB; 280 1.18 phx } 281 1.1 thorpej } 282 1.1 thorpej 283 1.1 thorpej if (error == ERDLAB) { 284 1.8 chs if (partition) { 285 1.8 chs /* 286 1.18 phx * User specified a partition, 287 1.8 chs * but there is none. 288 1.8 chs */ 289 1.1 thorpej goto bad; 290 1.8 chs } 291 1.8 chs /* No label, just use complete disk */ 292 1.1 thorpej ofdev.partoff = 0; 293 1.18 phx } else if (error != 0) 294 1.18 phx goto bad; 295 1.19 phx else { 296 1.19 phx part = partition ? partition - 'a' : 0; 297 1.19 phx ofdev.partoff = label.d_partitions[part].p_offset; 298 1.19 phx if (label.d_partitions[part].p_fstype == FS_RAID) { 299 1.15 mrg #define RF_PROTECTED_SECTORS 64 300 1.19 phx ofdev.partoff += RF_PROTECTED_SECTORS; 301 1.19 phx DPRINTF("devopen: found RAID partition, " 302 1.19 phx "adjusting offset to %lx\n", ofdev.partoff); 303 1.19 phx } 304 1.1 thorpej } 305 1.1 thorpej of->f_dev = devsw; 306 1.1 thorpej of->f_devdata = &ofdev; 307 1.6 thorpej file_system[0] = file_system_ufs; 308 1.6 thorpej file_system[1] = file_system_cd9660; 309 1.8 chs file_system[2] = file_system_dosfs; 310 1.8 chs nfsys = 3; 311 1.1 thorpej return 0; 312 1.1 thorpej } 313 1.18 phx 314 1.1 thorpej if (!strcmp(buf, "network")) { 315 1.1 thorpej ofdev.type = OFDEV_NET; 316 1.1 thorpej of->f_dev = devsw; 317 1.1 thorpej of->f_devdata = &ofdev; 318 1.6 thorpej file_system[0] = file_system_nfs; 319 1.1 thorpej nfsys = 1; 320 1.9 aymeric if ((error = net_open(&ofdev)) != 0) 321 1.1 thorpej goto bad; 322 1.1 thorpej return 0; 323 1.1 thorpej } 324 1.18 phx 325 1.1 thorpej error = EFTYPE; 326 1.18 phx bad: 327 1.1 thorpej OF_close(handle); 328 1.1 thorpej ofdev.handle = -1; 329 1.1 thorpej return error; 330 1.1 thorpej } 331