1 /* $OpenBSD: ofdev.c,v 1.11 2009/08/17 14:23:09 jsing Exp $ */ 2 /* $NetBSD: ofdev.c,v 1.1 2000/08/20 14:58:41 mrg Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 /* 35 * Device I/O routines using Open Firmware 36 */ 37 #include <sys/param.h> 38 #include <sys/disklabel.h> 39 #ifdef NETBOOT 40 #include <netinet/in.h> 41 #endif 42 43 #include <lib/libsa/stand.h> 44 #include <lib/libsa/ufs.h> 45 #include <lib/libsa/cd9660.h> 46 #ifdef NETBOOT 47 #include <lib/libsa/nfs.h> 48 #endif 49 50 #include <dev/sun/disklabel.h> 51 #include "ofdev.h" 52 53 extern char bootdev[]; 54 55 /* 56 * This is ugly. A path on a sparc machine is something like this: 57 * 58 * [device] [-<options] [path] [-options] [otherstuff] [-<more options] 59 * 60 */ 61 62 static char * 63 filename(char *str, char *ppart) 64 { 65 char *cp, *lp; 66 char savec; 67 int dhandle; 68 char devtype[16]; 69 70 lp = str; 71 devtype[0] = 0; 72 *ppart = 0; 73 for (cp = str; *cp; lp = cp) { 74 /* For each component of the path name... */ 75 while (*++cp && *cp != '/'); 76 savec = *cp; 77 *cp = 0; 78 /* ...look whether there is a device with this name */ 79 dhandle = OF_finddevice(str); 80 #ifdef NOTDEF_DEBUG 81 printf("filename: OF_finddevice(%s) says %x\n", 82 str, dhandle); 83 #endif 84 *cp = savec; 85 if (dhandle == -1) { 86 /* if not, lp is the delimiter between device and path */ 87 /* if the last component was a block device... */ 88 if (!strcmp(devtype, "block")) { 89 /* search for arguments */ 90 #ifdef NOTDEF_DEBUG 91 printf("filename: hunting for arguments in %s\n", str); 92 #endif 93 for (cp = lp; 94 --cp >= str && *cp != '/' && *cp != '-';); 95 if (cp >= str && *cp == '-') { 96 /* found arguments, make firmware ignore them */ 97 *cp = 0; 98 for (cp = lp; *--cp && *cp != ',';); 99 if (*++cp >= 'a' && *cp <= 'a' + MAXPARTITIONS) 100 *ppart = *cp; 101 } 102 } 103 #ifdef NOTDEF_DEBUG 104 printf("filename: found %s\n",lp); 105 #endif 106 return lp; 107 } else if (OF_getprop(dhandle, "device_type", devtype, sizeof devtype) < 0) 108 devtype[0] = 0; 109 } 110 #ifdef NOTDEF_DEBUG 111 printf("filename: not found\n",lp); 112 #endif 113 return 0; 114 } 115 116 static int 117 strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 118 size_t *rsize) 119 { 120 struct of_dev *dev = devdata; 121 u_quad_t pos; 122 int n; 123 124 if (rw != F_READ) 125 return EPERM; 126 if (dev->type != OFDEV_DISK) 127 panic("strategy"); 128 129 #ifdef NON_DEBUG 130 printf("strategy: block %lx, partition offset %lx, blksz %lx\n", 131 (long)blk, (long)dev->partoff, (long)dev->bsize); 132 printf("strategy: seek position should be: %lx\n", 133 (long)((blk + dev->partoff) * dev->bsize)); 134 #endif 135 pos = (u_quad_t)(blk + dev->partoff) * dev->bsize; 136 137 for (;;) { 138 #ifdef NON_DEBUG 139 printf("strategy: seeking to %lx\n", (long)pos); 140 #endif 141 if (OF_seek(dev->handle, pos) < 0) 142 break; 143 #ifdef NON_DEBUG 144 printf("strategy: reading %lx at %p\n", (long)size, buf); 145 #endif 146 n = OF_read(dev->handle, buf, size); 147 if (n == -2) 148 continue; 149 if (n < 0) 150 break; 151 *rsize = n; 152 return 0; 153 } 154 return EIO; 155 } 156 157 static int 158 devclose(struct open_file *of) 159 { 160 struct of_dev *op = of->f_devdata; 161 162 #ifdef NETBOOT 163 if (op->type == OFDEV_NET) 164 net_close(op); 165 #endif 166 OF_close(op->handle); 167 op->handle = -1; 168 } 169 170 static struct devsw devsw[1] = { 171 "OpenFirmware", 172 strategy, 173 (int (*)(struct open_file *, ...))nodev, 174 devclose, 175 noioctl 176 }; 177 int ndevs = sizeof devsw / sizeof devsw[0]; 178 179 #ifdef SPARC_BOOT_UFS 180 static struct fs_ops file_system_ufs = { 181 ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat 182 }; 183 #endif 184 #ifdef SPARC_BOOT_HSFS 185 static struct fs_ops file_system_cd9660 = { 186 cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, 187 cd9660_stat 188 }; 189 #endif 190 #ifdef NETBOOT 191 static struct fs_ops file_system_nfs = { 192 nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat 193 }; 194 #endif 195 196 struct fs_ops file_system[3]; 197 int nfsys; 198 199 static struct of_dev ofdev = { 200 -1, 201 }; 202 203 char opened_name[256]; 204 205 static u_long 206 get_long(const void *p) 207 { 208 const unsigned char *cp = p; 209 210 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 211 } 212 /************************************************************************ 213 * 214 * The rest of this was taken from arch/sparc64/scsi/sun_disklabel.c 215 * and then substantially rewritten by Gordon W. Ross 216 * 217 ************************************************************************/ 218 219 /* What partition types to assume for Sun disklabels: */ 220 static u_char 221 sun_fstypes[8] = { 222 FS_BSDFFS, /* a */ 223 FS_SWAP, /* b */ 224 FS_OTHER, /* c - whole disk */ 225 FS_BSDFFS, /* d */ 226 FS_BSDFFS, /* e */ 227 FS_BSDFFS, /* f */ 228 FS_BSDFFS, /* g */ 229 FS_BSDFFS, /* h */ 230 }; 231 232 /* 233 * Given a SunOS disk label, set lp to a BSD disk label. 234 * Returns NULL on success, else an error string. 235 * 236 * The BSD label is cleared out before this is called. 237 */ 238 static char * 239 disklabel_sun_to_bsd(char *cp, struct disklabel *lp) 240 { 241 struct sun_disklabel *sl; 242 struct partition *npp; 243 struct sun_dkpart *spp; 244 int i, secpercyl; 245 u_short cksum, *sp1, *sp2; 246 247 sl = (struct sun_disklabel *)cp; 248 249 /* Verify the XOR check. */ 250 sp1 = (u_short *)sl; 251 sp2 = (u_short *)(sl + 1); 252 cksum = 0; 253 while (sp1 < sp2) 254 cksum ^= *sp1++; 255 if (cksum != 0) 256 return("SunOS disk label, bad checksum"); 257 258 /* Format conversion. */ 259 lp->d_magic = DISKMAGIC; 260 lp->d_magic2 = DISKMAGIC; 261 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 262 263 lp->d_secsize = 512; 264 lp->d_nsectors = sl->sl_nsectors; 265 lp->d_ntracks = sl->sl_ntracks; 266 lp->d_ncylinders = sl->sl_ncylinders; 267 268 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 269 lp->d_secpercyl = secpercyl; 270 lp->d_secperunit = secpercyl * sl->sl_ncylinders; 271 272 lp->d_sparespercyl = sl->sl_sparespercyl; 273 lp->d_acylinders = sl->sl_acylinders; 274 lp->d_rpm = sl->sl_rpm; 275 lp->d_interleave = sl->sl_interleave; 276 277 lp->d_npartitions = MAXPARTITIONS; 278 /* These are as defined in <ufs/ffs/fs.h> */ 279 lp->d_bbsize = 8192; /* XXX */ 280 lp->d_sbsize = 8192; /* XXX */ 281 282 for (i = 0; i < 8; i++) { 283 spp = &sl->sl_part[i]; 284 npp = &lp->d_partitions[i]; 285 npp->p_offset = spp->sdkp_cyloffset * secpercyl; 286 npp->p_size = spp->sdkp_nsectors; 287 #ifdef NOTDEF_DEBUG 288 printf("partition %d start %x size %x\n", i, (int)npp->p_offset, (int)npp->p_size); 289 #endif 290 if (npp->p_size == 0) { 291 npp->p_fstype = FS_UNUSED; 292 } else { 293 npp->p_fstype = sun_fstypes[i]; 294 if (npp->p_fstype == FS_BSDFFS) { 295 /* 296 * The sun label does not store the FFS fields, 297 * so just set them with default values here. 298 */ 299 npp->p_fragblock = 300 DISKLABELV1_FFS_FRAGBLOCK(1024, 8); 301 npp->p_cpg = 16; 302 } 303 } 304 } 305 306 lp->d_checksum = 0; 307 lp->d_checksum = dkcksum(lp); 308 #ifdef NOTDEF_DEBUG 309 printf("disklabel_sun_to_bsd: success!\n"); 310 #endif 311 return (NULL); 312 } 313 314 /* 315 * Find a valid disklabel. 316 */ 317 static char * 318 search_label(struct of_dev *devp, u_long off, char *buf, struct disklabel *lp, 319 u_long off0) 320 { 321 size_t read; 322 struct mbr_partition *p; 323 int i; 324 u_long poff; 325 static int recursion; 326 327 struct disklabel *dlp; 328 struct sun_disklabel *slp; 329 int error; 330 331 /* minimal requirements for archetypal disk label */ 332 if (lp->d_secperunit == 0) 333 lp->d_secperunit = 0x1fffffff; 334 lp->d_npartitions = MAXPARTITIONS; 335 if (lp->d_partitions[0].p_size == 0) 336 lp->d_partitions[0].p_size = 0x1fffffff; 337 lp->d_partitions[0].p_offset = 0; 338 339 if (strategy(devp, F_READ, LABELSECTOR, DEV_BSIZE, buf, &read) 340 || read != DEV_BSIZE) 341 return ("Cannot read label"); 342 /* Check for a NetBSD disk label. */ 343 dlp = (struct disklabel *) (buf + LABELOFFSET); 344 if (dlp->d_magic == DISKMAGIC) { 345 if (dkcksum(dlp)) 346 return ("NetBSD disk label corrupted"); 347 *lp = *dlp; 348 #ifdef NOTDEF_DEBUG 349 printf("search_label: found NetBSD label\n"); 350 #endif 351 return (NULL); 352 } 353 354 /* Check for a Sun disk label (for PROM compatibility). */ 355 slp = (struct sun_disklabel *) buf; 356 if (slp->sl_magic == SUN_DKMAGIC) 357 return (disklabel_sun_to_bsd(buf, lp)); 358 359 360 bzero(buf, sizeof(buf)); 361 return ("no disk label"); 362 } 363 364 int 365 devopen(struct open_file *of, const char *name, char **file) 366 { 367 char *cp; 368 char partition; 369 char fname[256]; 370 char buf[DEV_BSIZE]; 371 struct disklabel label; 372 int handle, part; 373 size_t read; 374 char *errmsg = NULL; 375 int error = 0; 376 377 if (ofdev.handle != -1) 378 panic("devopen"); 379 if (of->f_flags != F_READ) 380 return EPERM; 381 #ifdef NOTDEF_DEBUG 382 printf("devopen: you want %s\n", name); 383 #endif 384 strlcpy(fname, name, sizeof fname); 385 cp = filename(fname, &partition); 386 if (cp) { 387 strlcpy(buf, cp, sizeof buf); 388 *cp = 0; 389 } 390 if (!cp || !*buf) 391 strlcpy(buf, DEFAULT_KERNEL, sizeof buf); 392 if (!*fname) 393 strlcpy(fname, bootdev, sizeof fname); 394 strlcpy(opened_name, fname, sizeof opened_name); 395 if (partition) { 396 cp = opened_name + strlen(opened_name); 397 *cp++ = ':'; 398 *cp++ = partition; 399 *cp = 0; 400 } 401 if (*buf != '/') 402 strlcat(opened_name, "/", sizeof opened_name); 403 strlcat(opened_name, buf, sizeof opened_name); 404 *file = opened_name + strlen(fname) + 1; 405 #ifdef NOTDEF_DEBUG 406 printf("devopen: trying %s\n", fname); 407 #endif 408 if ((handle = OF_finddevice(fname)) == -1) 409 return ENOENT; 410 #ifdef NOTDEF_DEBUG 411 printf("devopen: found %s\n", fname); 412 #endif 413 if (OF_getprop(handle, "name", buf, sizeof buf) < 0) 414 return ENXIO; 415 #ifdef NOTDEF_DEBUG 416 printf("devopen: %s is called %s\n", fname, buf); 417 #endif 418 if (OF_getprop(handle, "device_type", buf, sizeof buf) < 0) 419 return ENXIO; 420 #ifdef NOTDEF_DEBUG 421 printf("devopen: %s is a %s device\n", fname, buf); 422 #endif 423 #ifdef NOTDEF_DEBUG 424 printf("devopen: opening %s\n", fname); 425 #endif 426 if ((handle = OF_open(fname)) == -1) { 427 #ifdef NOTDEF_DEBUG 428 printf("devopen: open of %s failed\n", fname); 429 #endif 430 return ENXIO; 431 } 432 #ifdef NOTDEF_DEBUG 433 printf("devopen: %s is now open\n", fname); 434 #endif 435 bzero(&ofdev, sizeof ofdev); 436 ofdev.handle = handle; 437 if (!strcmp(buf, "block")) { 438 ofdev.type = OFDEV_DISK; 439 ofdev.bsize = DEV_BSIZE; 440 /* First try to find a disklabel without MBR partitions */ 441 #ifdef NOTDEF_DEBUG 442 printf("devopen: trying to read disklabel\n"); 443 #endif 444 if (strategy(&ofdev, F_READ, 445 LABELSECTOR, DEV_BSIZE, buf, &read) != 0 446 || read != DEV_BSIZE 447 || (errmsg = getdisklabel(buf, &label))) { 448 #ifdef NOTDEF_DEBUG 449 if (errmsg) printf("devopen: getdisklabel says %s\n", errmsg); 450 #endif 451 /* Else try MBR partitions */ 452 errmsg = search_label(&ofdev, 0, buf, &label, 0); 453 if (errmsg) { 454 printf("devopen: search_label says %s\n", errmsg); 455 error = ERDLAB; 456 } 457 if (error && error != ERDLAB) 458 goto bad; 459 } 460 461 if (error == ERDLAB) { 462 if (partition) 463 /* User specified a parititon, but there is none */ 464 goto bad; 465 /* No, label, just use complete disk */ 466 ofdev.partoff = 0; 467 } else { 468 part = partition ? partition - 'a' : 0; 469 ofdev.partoff = label.d_partitions[part].p_offset; 470 #ifdef NOTDEF_DEBUG 471 printf("devopen: setting partition %d offset %x\n", 472 part, ofdev.partoff); 473 #endif 474 } 475 476 of->f_dev = devsw; 477 of->f_devdata = &ofdev; 478 #ifdef SPARC_BOOT_UFS 479 bcopy(&file_system_ufs, &file_system[nfsys++], sizeof file_system[0]); 480 #endif 481 #ifdef SPARC_BOOT_HSFS 482 bcopy(&file_system_cd9660, &file_system[nfsys++], 483 sizeof file_system[0]); 484 #endif 485 #ifdef NOTDEF_DEBUG 486 printf("devopen: return 0\n"); 487 #endif 488 return 0; 489 } 490 #ifdef NETBOOT 491 if (!strcmp(buf, "network")) { 492 ofdev.type = OFDEV_NET; 493 of->f_dev = devsw; 494 of->f_devdata = &ofdev; 495 bcopy(&file_system_nfs, file_system, sizeof file_system[0]); 496 nfsys = 1; 497 if (error = net_open(&ofdev)) 498 goto bad; 499 return 0; 500 } 501 #endif 502 error = EFTYPE; 503 bad: 504 #ifdef NOTDEF_DEBUG 505 printf("devopen: error %d, cannot open device\n", error); 506 #endif 507 OF_close(handle); 508 ofdev.handle = -1; 509 return error; 510 } 511