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