xref: /netbsd/sys/arch/macppc/stand/ofwboot/ofdev.c (revision bf9ec67e)
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