1 /* $NetBSD: ofdev.c,v 1.1 2002/02/10 01:58:18 thorpej 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 <sys/param.h> 38 #include <sys/disklabel.h> 39 #include <sys/disklabel_mbr.h> 40 41 #include <netinet/in.h> 42 43 #include <lib/libsa/stand.h> 44 #include <lib/libsa/ufs.h> 45 #include <lib/libsa/cd9660.h> 46 #include <lib/libsa/dosfs.h> 47 #include <lib/libsa/nfs.h> 48 49 #include "ofdev.h" 50 51 extern char bootdev[]; 52 53 #ifdef DEBUG 54 # define DPRINTF printf 55 #else 56 # define DPRINTF while (0) printf 57 #endif 58 59 static char * 60 filename(str, ppart) 61 char *str; 62 char *ppart; 63 { 64 char *cp, *lp; 65 char savec; 66 int dhandle; 67 char devtype[16]; 68 69 lp = str; 70 devtype[0] = 0; 71 *ppart = 0; 72 for (cp = str; *cp; lp = cp) { 73 /* For each component of the path name... */ 74 while (*++cp && *cp != '/'); 75 savec = *cp; 76 *cp = 0; 77 /* ...look whether there is a device with this name */ 78 dhandle = OF_finddevice(str); 79 *cp = savec; 80 if (dhandle == -1) { 81 /* if not, lp is the delimiter between device and path */ 82 /* if the last component was a block device... */ 83 if (!strcmp(devtype, "block")) { 84 /* search for arguments */ 85 for (cp = lp; 86 --cp >= str && *cp != '/' && *cp != ':';); 87 if (cp >= str && *cp == ':') { 88 /* found arguments, make firmware ignore them */ 89 *cp = 0; 90 for (cp = lp; *--cp && *cp != ',';); 91 if (*++cp >= 'a' && *cp <= 'a' + MAXPARTITIONS) 92 *ppart = *cp; 93 } 94 } 95 return lp; 96 } else if (OF_getprop(dhandle, "device_type", devtype, sizeof devtype) < 0) 97 devtype[0] = 0; 98 } 99 return 0; 100 } 101 102 static int 103 strategy(devdata, rw, blk, size, buf, rsize) 104 void *devdata; 105 int rw; 106 daddr_t blk; 107 size_t size; 108 void *buf; 109 size_t *rsize; 110 { 111 struct of_dev *dev = devdata; 112 u_quad_t pos; 113 int n; 114 115 if (rw != F_READ) 116 return EPERM; 117 if (dev->type != OFDEV_DISK) 118 panic("strategy"); 119 120 pos = (u_quad_t)(blk + dev->partoff) * dev->bsize; 121 122 for (;;) { 123 if (OF_seek(dev->handle, pos) < 0) 124 break; 125 n = OF_read(dev->handle, buf, size); 126 if (n == -2) 127 continue; 128 if (n < 0) 129 break; 130 *rsize = n; 131 return 0; 132 } 133 return EIO; 134 } 135 136 static int 137 devclose(of) 138 struct open_file *of; 139 { 140 struct of_dev *op = of->f_devdata; 141 142 if (op->type == OFDEV_NET) 143 net_close(op); 144 OF_close(op->handle); 145 op->handle = -1; 146 } 147 148 static struct devsw devsw[1] = { 149 "OpenFirmware", 150 strategy, 151 (int (*)__P((struct open_file *, ...)))nodev, 152 devclose, 153 noioctl 154 }; 155 int ndevs = sizeof devsw / sizeof devsw[0]; 156 157 static struct fs_ops file_system_ufs = { 158 ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat 159 }; 160 static struct fs_ops file_system_cd9660 = { 161 cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, 162 cd9660_stat 163 }; 164 static struct fs_ops file_system_dosfs = { 165 dosfs_open, dosfs_close, dosfs_read, dosfs_write, dosfs_seek, 166 dosfs_stat 167 }; 168 static struct fs_ops file_system_nfs = { 169 nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat 170 }; 171 172 struct fs_ops file_system[3]; 173 int nfsys; 174 175 static struct of_dev ofdev = { 176 -1, 177 }; 178 179 char opened_name[256]; 180 int floppyboot; 181 182 static u_long 183 get_long(p) 184 const void *p; 185 { 186 const unsigned char *cp = p; 187 188 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 189 } 190 191 /* 192 * Find a valid disklabel. 193 */ 194 static int 195 search_label(devp, off, buf, lp, off0) 196 struct of_dev *devp; 197 u_long off; 198 char *buf; 199 struct disklabel *lp; 200 u_long off0; 201 { 202 size_t read; 203 struct mbr_partition *p; 204 int i; 205 u_long poff; 206 static int recursion; 207 208 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 209 || read != DEV_BSIZE) 210 return ERDLAB; 211 212 if (buf[510] != 0x55 || buf[511] != 0xaa) 213 return ERDLAB; 214 215 if (recursion++ <= 1) 216 off0 += off; 217 for (p = (struct mbr_partition *)(buf + MBR_PARTOFF), i = 4; 218 --i >= 0; p++) { 219 if (p->mbrp_typ == MBR_PTYPE_NETBSD 220 #ifdef COMPAT_386BSD_MBRPART 221 || (p->mbrp_typ == MBR_PTYPE_386BSD && 222 (printf("WARNING: old BSD partition ID!\n"), 1) 223 /* XXX XXX - libsa printf() is void */ ) 224 #endif 225 ) { 226 poff = get_long(&p->mbrp_start) + off0; 227 if (strategy(devp, F_READ, poff + LABELSECTOR, 228 DEV_BSIZE, buf, &read) == 0 229 && read == DEV_BSIZE) { 230 if (!getdisklabel(buf, lp)) { 231 recursion--; 232 return 0; 233 } 234 } 235 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 236 || read != DEV_BSIZE) { 237 recursion--; 238 return ERDLAB; 239 } 240 } else if (p->mbrp_typ == MBR_PTYPE_EXT) { 241 poff = get_long(&p->mbrp_start); 242 if (!search_label(devp, poff, buf, lp, off0)) { 243 recursion--; 244 return 0; 245 } 246 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 247 || read != DEV_BSIZE) { 248 recursion--; 249 return ERDLAB; 250 } 251 } 252 } 253 recursion--; 254 return ERDLAB; 255 } 256 257 int 258 devopen(of, name, file) 259 struct open_file *of; 260 const char *name; 261 char **file; 262 { 263 char *cp; 264 char partition; 265 char fname[256]; 266 char buf[DEV_BSIZE]; 267 struct disklabel label; 268 int handle, part; 269 size_t read; 270 int error = 0; 271 272 if (ofdev.handle != -1) 273 panic("devopen"); 274 if (of->f_flags != F_READ) 275 return EPERM; 276 strcpy(fname, name); 277 cp = filename(fname, &partition); 278 if (cp) { 279 DPRINTF("filename=%s\n", cp); 280 strcpy(buf, cp); 281 *cp = 0; 282 } 283 if (!cp || !*buf) 284 strcpy(buf, DEFAULT_KERNEL); 285 if (!*fname) 286 strcpy(fname, bootdev); 287 DPRINTF("fname=%s\n", fname); 288 strcpy(opened_name, fname); 289 if (partition) { 290 cp = opened_name + strlen(opened_name); 291 *cp++ = ':'; 292 *cp++ = partition; 293 *cp = 0; 294 } 295 if (*buf != '/') 296 strcat(opened_name, "/"); 297 strcat(opened_name, buf); 298 *file = opened_name + strlen(fname) + 1; 299 if ((handle = OF_finddevice(fname)) == -1) { 300 DPRINTF("OF_finddevice(\"%s\") failed\n", fname); 301 return ENOENT; 302 } 303 if (OF_getprop(handle, "name", buf, sizeof buf) < 0) 304 return ENXIO; 305 floppyboot = !strcmp(buf, "floppy"); 306 if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0) 307 return ENXIO; 308 if (!strcmp(buf, "block")) 309 /* For block devices, indicate raw partition (:0 in OpenFirmware) */ 310 strcat(fname, ":0"); 311 if ((handle = OF_open(fname)) == -1) 312 return ENXIO; 313 memset(&ofdev, 0, sizeof ofdev); 314 ofdev.handle = handle; 315 if (!strcmp(buf, "block")) { 316 ofdev.type = OFDEV_DISK; 317 ofdev.bsize = DEV_BSIZE; 318 /* First try to find a disklabel without MBR partitions */ 319 if (strategy(&ofdev, F_READ, 320 LABELSECTOR, DEV_BSIZE, buf, &read) != 0 321 || read != DEV_BSIZE 322 || getdisklabel(buf, &label)) { 323 /* Else try MBR partitions */ 324 error = search_label(&ofdev, 0, buf, &label, 0); 325 if (error && error != ERDLAB) 326 goto bad; 327 } 328 329 if (error == ERDLAB) { 330 if (partition) 331 /* User specified a parititon, but there is none */ 332 goto bad; 333 /* No, label, just use complete disk */ 334 ofdev.partoff = 0; 335 } else { 336 part = partition ? partition - 'a' : 0; 337 ofdev.partoff = label.d_partitions[part].p_offset; 338 } 339 340 of->f_dev = devsw; 341 of->f_devdata = &ofdev; 342 file_system[0] = file_system_ufs; 343 file_system[1] = file_system_cd9660; 344 file_system[1] = file_system_dosfs; 345 nfsys = 2; 346 return 0; 347 } 348 if (!strcmp(buf, "network")) { 349 ofdev.type = OFDEV_NET; 350 of->f_dev = devsw; 351 of->f_devdata = &ofdev; 352 file_system[0] = file_system_nfs; 353 nfsys = 1; 354 if (error = net_open(&ofdev)) 355 goto bad; 356 return 0; 357 } 358 error = EFTYPE; 359 bad: 360 OF_close(handle); 361 ofdev.handle = -1; 362 return error; 363 } 364