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