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