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