xref: /netbsd-src/sys/arch/sparc/stand/ofwboot/ofdev.c (revision be9f90e87153cd472561b72aa3f03674c0ffcb65)
1*be9f90e8Smartin /*	$NetBSD: ofdev.c,v 1.37 2017/09/15 13:25:34 martin Exp $	*/
2e144281cSmrg 
3e144281cSmrg /*
4e144281cSmrg  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5e144281cSmrg  * Copyright (C) 1995, 1996 TooLs GmbH.
6e144281cSmrg  * All rights reserved.
7e144281cSmrg  *
8e144281cSmrg  * Redistribution and use in source and binary forms, with or without
9e144281cSmrg  * modification, are permitted provided that the following conditions
10e144281cSmrg  * are met:
11e144281cSmrg  * 1. Redistributions of source code must retain the above copyright
12e144281cSmrg  *    notice, this list of conditions and the following disclaimer.
13e144281cSmrg  * 2. Redistributions in binary form must reproduce the above copyright
14e144281cSmrg  *    notice, this list of conditions and the following disclaimer in the
15e144281cSmrg  *    documentation and/or other materials provided with the distribution.
16e144281cSmrg  * 3. All advertising materials mentioning features or use of this software
17e144281cSmrg  *    must display the following acknowledgement:
18e144281cSmrg  *	This product includes software developed by TooLs GmbH.
19e144281cSmrg  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20e144281cSmrg  *    derived from this software without specific prior written permission.
21e144281cSmrg  *
22e144281cSmrg  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23e144281cSmrg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24e144281cSmrg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25e144281cSmrg  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e144281cSmrg  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27e144281cSmrg  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28e144281cSmrg  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29e144281cSmrg  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30e144281cSmrg  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31e144281cSmrg  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32e144281cSmrg  */
33e144281cSmrg /*
34e144281cSmrg  * Device I/O routines using Open Firmware
35e144281cSmrg  */
36e144281cSmrg #include <sys/param.h>
37e144281cSmrg #include <sys/disklabel.h>
38e144281cSmrg #ifdef NETBOOT
39e144281cSmrg #include <netinet/in.h>
40e144281cSmrg #endif
41e144281cSmrg 
42e144281cSmrg #include <lib/libsa/stand.h>
43e144281cSmrg #include <lib/libsa/ufs.h>
44feea5ba2Seeh #include <lib/libsa/lfs.h>
45e144281cSmrg #include <lib/libsa/cd9660.h>
46e144281cSmrg #ifdef NETBOOT
47e144281cSmrg #include <lib/libsa/nfs.h>
4817740d28Smlelstv #include <lib/libsa/tftp.h>
49e144281cSmrg #endif
50e144281cSmrg #include <lib/libkern/libkern.h>
51e144281cSmrg 
52e144281cSmrg #include <dev/sun/disklabel.h>
534c2f43b8Smartin #include <dev/raidframe/raidframevar.h>
544c2f43b8Smartin 
5597aa1417Scdi #include <machine/promlib.h>
5697aa1417Scdi 
57e144281cSmrg #include "ofdev.h"
58e3218c43Smartin #include "boot.h"
59c95f237aStsutsui #include "net.h"
60e144281cSmrg 
61e144281cSmrg extern char bootdev[];
629df63719Smartin extern bool root_fs_quickseekable;
63e144281cSmrg 
64*be9f90e8Smartin struct btinfo_bootdev_unit bi_unit;
65*be9f90e8Smartin bool bootinfo_pass_bootunit = false;
66*be9f90e8Smartin 
67e144281cSmrg /*
68e144281cSmrg  * This is ugly.  A path on a sparc machine is something like this:
69e144281cSmrg  *
70e144281cSmrg  *	[device] [-<options] [path] [-options] [otherstuff] [-<more options]
71e144281cSmrg  *
72e144281cSmrg  */
73e144281cSmrg 
74e3218c43Smartin char *
filename(char * str,char * ppart)754c3c91e6Suwe filename(char *str, char *ppart)
76e144281cSmrg {
77e144281cSmrg 	char *cp, *lp;
78e144281cSmrg 	char savec;
79e144281cSmrg 	int dhandle;
80e144281cSmrg 	char devtype[16];
81e144281cSmrg 
82e144281cSmrg 	lp = str;
83e144281cSmrg 	devtype[0] = 0;
8442c234cfSmartin 	*ppart = '\0';
85e144281cSmrg 	for (cp = str; *cp; lp = cp) {
86e144281cSmrg 		/* For each component of the path name... */
87e144281cSmrg 		while (*++cp && *cp != '/');
88e144281cSmrg 		savec = *cp;
89e144281cSmrg 		*cp = 0;
90e144281cSmrg 		/* ...look whether there is a device with this name */
9197aa1417Scdi 		dhandle = prom_finddevice(str);
92e3218c43Smartin 		DPRINTF(("filename: prom_finddevice(%s) returned %x\n",
93e3218c43Smartin 		       str, dhandle));
94e144281cSmrg 		*cp = savec;
95e144281cSmrg 		if (dhandle == -1) {
96d06249b5Smrg 			/*
97d06249b5Smrg 			 * if not, lp is the delimiter between device and
98d06249b5Smrg 			 * path.  if the last component was a block device.
99d06249b5Smrg 			 */
1000ed481bcSmartin 			if (strcmp(devtype, "block") == 0
1010ed481bcSmartin 			    || strcmp(devtype, "scsi") == 0) {
102e144281cSmrg 				/* search for arguments */
103e3218c43Smartin 				DPRINTF(("filename: hunting for arguments "
10442c234cfSmartin 				       "in %s\n", lp));
105f19a67c5Smartin 				for (cp = lp; ; ) {
106f19a67c5Smartin 					cp--;
107d06249b5Smrg 					if (cp < str ||
108d06249b5Smrg 					    cp[0] == '/' ||
109d06249b5Smrg 					    (cp[0] == ' ' && (cp+1) != lp &&
110d06249b5Smrg 					     cp[1] == '-'))
111f19a67c5Smartin 						break;
112f19a67c5Smartin 				}
1134c2f43b8Smartin 				if (cp >= str && *cp == '-')
11442c234cfSmartin 					/* found arguments, make firmware
11542c234cfSmartin 					   ignore them */
11642c234cfSmartin 					*cp = 0;
11742c234cfSmartin 				for (cp = lp; *--cp && *cp != ','
11842c234cfSmartin 					&& *cp != ':';)
11942c234cfSmartin 						;
12042c234cfSmartin 				if (cp[0] == ':' && cp[1] >= 'a' &&
12142c234cfSmartin 				    cp[1] <= 'a' + MAXPARTITIONS) {
12242c234cfSmartin 					*ppart = cp[1];
12342c234cfSmartin 					cp[0] = '\0';
124e144281cSmrg 				}
125e144281cSmrg 			}
126e3218c43Smartin 			DPRINTF(("filename: found %s\n",lp));
127e144281cSmrg 			return lp;
12842c234cfSmartin 		} else if (_prom_getprop(dhandle, "device_type", devtype,
12942c234cfSmartin 				sizeof devtype) < 0)
130e144281cSmrg 			devtype[0] = 0;
131e144281cSmrg 	}
1323bf07950Snakayama 	DPRINTF(("filename: not found\n"));
133e144281cSmrg 	return 0;
134e144281cSmrg }
135e144281cSmrg 
136e144281cSmrg static int
strategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)137454af1c0Sdsl strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, size_t *rsize)
138e144281cSmrg {
139e144281cSmrg 	struct of_dev *dev = devdata;
140e144281cSmrg 	u_quad_t pos;
141e144281cSmrg 	int n;
142e144281cSmrg 
143e144281cSmrg 	if (rw != F_READ)
144e144281cSmrg 		return EPERM;
145e144281cSmrg 	if (dev->type != OFDEV_DISK)
146e144281cSmrg 		panic("strategy");
147e144281cSmrg 
148e144281cSmrg #ifdef NON_DEBUG
149e144281cSmrg 	printf("strategy: block %lx, partition offset %lx, blksz %lx\n",
150e144281cSmrg 	       (long)blk, (long)dev->partoff, (long)dev->bsize);
151e144281cSmrg 	printf("strategy: seek position should be: %lx\n",
152e144281cSmrg 	       (long)((blk + dev->partoff) * dev->bsize));
153e144281cSmrg #endif
154e144281cSmrg 	pos = (u_quad_t)(blk + dev->partoff) * dev->bsize;
155e144281cSmrg 
156e144281cSmrg 	for (;;) {
157e144281cSmrg #ifdef NON_DEBUG
158e144281cSmrg 		printf("strategy: seeking to %lx\n", (long)pos);
159e144281cSmrg #endif
16097aa1417Scdi 		if (prom_seek(dev->handle, pos) < 0)
161e144281cSmrg 			break;
162e144281cSmrg #ifdef NON_DEBUG
163e144281cSmrg 		printf("strategy: reading %lx at %p\n", (long)size, buf);
164e144281cSmrg #endif
16597aa1417Scdi 		n = prom_read(dev->handle, buf, size);
166e144281cSmrg 		if (n == -2)
167e144281cSmrg 			continue;
168e144281cSmrg 		if (n < 0)
169e144281cSmrg 			break;
170e144281cSmrg 		*rsize = n;
171e144281cSmrg 		return 0;
172e144281cSmrg 	}
173e144281cSmrg 	return EIO;
174e144281cSmrg }
175e144281cSmrg 
176e144281cSmrg static int
devclose(struct open_file * of)1774c3c91e6Suwe devclose(struct open_file *of)
178e144281cSmrg {
179e144281cSmrg 	struct of_dev *op = of->f_devdata;
180e144281cSmrg 
181e144281cSmrg #ifdef NETBOOT
182e144281cSmrg 	if (op->type == OFDEV_NET)
183e144281cSmrg 		net_close(op);
184e144281cSmrg #endif
18597aa1417Scdi 	prom_close(op->handle);
186e144281cSmrg 	op->handle = -1;
187c95f237aStsutsui 	return 0;
188e144281cSmrg }
189e144281cSmrg 
190cec53020Smrg static struct devsw ofdevsw[1] = {
191c95f237aStsutsui 	{
192e144281cSmrg 		"OpenFirmware",
193e144281cSmrg 		strategy,
1944c3c91e6Suwe 		(int (*)(struct open_file *, ...))nodev,
195e144281cSmrg 		devclose,
196e144281cSmrg 		noioctl
197c95f237aStsutsui 	}
198e144281cSmrg };
199cec53020Smrg int ndevs = sizeof ofdevsw / sizeof ofdevsw[0];
200e144281cSmrg 
201feea5ba2Seeh 
202e144281cSmrg #ifdef SPARC_BOOT_UFS
203feea5ba2Seeh static struct fs_ops file_system_ufs[] =
204feea5ba2Seeh { FS_OPS(ufs), FS_OPS(ffsv2), FS_OPS(lfsv1), FS_OPS(lfsv2) };
205e144281cSmrg #endif
206c068dc64Smartin #ifdef SPARC_BOOT_CD9660
20717670568Sjunyoung static struct fs_ops file_system_cd9660 = FS_OPS(cd9660);
208e144281cSmrg #endif
209e144281cSmrg #ifdef NETBOOT
21017670568Sjunyoung static struct fs_ops file_system_nfs = FS_OPS(nfs);
21117740d28Smlelstv static struct fs_ops file_system_tftp = FS_OPS(tftp);
212e144281cSmrg #endif
213e144281cSmrg 
214feea5ba2Seeh struct fs_ops file_system[7];
215e144281cSmrg int nfsys;
216e144281cSmrg 
217e144281cSmrg static struct of_dev ofdev = {
218e144281cSmrg 	-1,
219e144281cSmrg };
220e144281cSmrg 
221e144281cSmrg char opened_name[256];
222e144281cSmrg int floppyboot;
223e144281cSmrg 
224e144281cSmrg /************************************************************************
225e144281cSmrg  *
226e144281cSmrg  * The rest of this was taken from arch/sparc64/scsi/sun_disklabel.c
227e144281cSmrg  * and then substantially rewritten by Gordon W. Ross
228e144281cSmrg  *
229e144281cSmrg  ************************************************************************/
230e144281cSmrg 
231e144281cSmrg /* What partition types to assume for Sun disklabels: */
232e144281cSmrg static u_char
233e144281cSmrg sun_fstypes[8] = {
234e144281cSmrg 	FS_BSDFFS,	/* a */
235e144281cSmrg 	FS_SWAP,	/* b */
236e144281cSmrg 	FS_OTHER,	/* c - whole disk */
237e144281cSmrg 	FS_BSDFFS,	/* d */
238e144281cSmrg 	FS_BSDFFS,	/* e */
239e144281cSmrg 	FS_BSDFFS,	/* f */
240e144281cSmrg 	FS_BSDFFS,	/* g */
241e144281cSmrg 	FS_BSDFFS,	/* h */
242e144281cSmrg };
243e144281cSmrg 
244e144281cSmrg /*
245e144281cSmrg  * Given a SunOS disk label, set lp to a BSD disk label.
246e144281cSmrg  * Returns NULL on success, else an error string.
247e144281cSmrg  *
248e144281cSmrg  * The BSD label is cleared out before this is called.
249e144281cSmrg  */
250e144281cSmrg static char *
disklabel_sun_to_bsd(char * cp,struct disklabel * lp)2514c3c91e6Suwe disklabel_sun_to_bsd(char *cp, struct disklabel *lp)
252e144281cSmrg {
253e144281cSmrg 	struct sun_disklabel *sl;
254e144281cSmrg 	struct partition *npp;
255e144281cSmrg 	struct sun_dkpart *spp;
256e144281cSmrg 	int i, secpercyl;
257e144281cSmrg 	u_short cksum, *sp1, *sp2;
258e144281cSmrg 
259e144281cSmrg 	sl = (struct sun_disklabel *)cp;
260e144281cSmrg 
261e144281cSmrg 	/* Verify the XOR check. */
262e144281cSmrg 	sp1 = (u_short *)sl;
263e144281cSmrg 	sp2 = (u_short *)(sl + 1);
264e144281cSmrg 	cksum = 0;
265e144281cSmrg 	while (sp1 < sp2)
266e144281cSmrg 		cksum ^= *sp1++;
267e144281cSmrg 	if (cksum != 0)
268e144281cSmrg 		return("SunOS disk label, bad checksum");
269e144281cSmrg 
270e144281cSmrg 	/* Format conversion. */
271e144281cSmrg 	lp->d_magic = DISKMAGIC;
272e144281cSmrg 	lp->d_magic2 = DISKMAGIC;
273e144281cSmrg 	memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
274e144281cSmrg 
275e144281cSmrg 	lp->d_secsize = 512;
276e144281cSmrg 	lp->d_nsectors   = sl->sl_nsectors;
277e144281cSmrg 	lp->d_ntracks    = sl->sl_ntracks;
278e144281cSmrg 	lp->d_ncylinders = sl->sl_ncylinders;
279e144281cSmrg 
280e144281cSmrg 	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
281e144281cSmrg 	lp->d_secpercyl  = secpercyl;
282e144281cSmrg 	lp->d_secperunit = secpercyl * sl->sl_ncylinders;
283e144281cSmrg 
284e144281cSmrg 	lp->d_sparespercyl = sl->sl_sparespercyl;
285e144281cSmrg 	lp->d_acylinders   = sl->sl_acylinders;
286e144281cSmrg 	lp->d_rpm          = sl->sl_rpm;
287e144281cSmrg 	lp->d_interleave   = sl->sl_interleave;
288e144281cSmrg 
289e144281cSmrg 	lp->d_npartitions = 8;
290e144281cSmrg 	/* These are as defined in <ufs/ffs/fs.h> */
291e144281cSmrg 	lp->d_bbsize = 8192;	/* XXX */
292e144281cSmrg 	lp->d_sbsize = 8192;	/* XXX */
293e144281cSmrg 
294e144281cSmrg 	for (i = 0; i < 8; i++) {
295e144281cSmrg 		spp = &sl->sl_part[i];
296e144281cSmrg 		npp = &lp->d_partitions[i];
297e144281cSmrg 		npp->p_offset = spp->sdkp_cyloffset * secpercyl;
298e144281cSmrg 		npp->p_size = spp->sdkp_nsectors;
299e3218c43Smartin 		DPRINTF(("partition %d start %x size %x\n", i, (int)npp->p_offset, (int)npp->p_size));
300e144281cSmrg 		if (npp->p_size == 0) {
301e144281cSmrg 			npp->p_fstype = FS_UNUSED;
302e144281cSmrg 		} else {
303e144281cSmrg 			npp->p_fstype = sun_fstypes[i];
304e144281cSmrg 			if (npp->p_fstype == FS_BSDFFS) {
305e144281cSmrg 				/*
306e144281cSmrg 				 * The sun label does not store the FFS fields,
307e144281cSmrg 				 * so just set them with default values here.
308e144281cSmrg 				 */
309e144281cSmrg 				npp->p_fsize = 1024;
310e144281cSmrg 				npp->p_frag = 8;
311e144281cSmrg 				npp->p_cpg = 16;
312e144281cSmrg 			}
313e144281cSmrg 		}
314e144281cSmrg 	}
315e144281cSmrg 
316e144281cSmrg 	lp->d_checksum = 0;
317e144281cSmrg 	lp->d_checksum = dkcksum(lp);
318e3218c43Smartin 	DPRINTF(("disklabel_sun_to_bsd: success!\n"));
319e144281cSmrg 	return (NULL);
320e144281cSmrg }
321e144281cSmrg 
322e144281cSmrg /*
323e144281cSmrg  * Find a valid disklabel.
324e144281cSmrg  */
325e144281cSmrg static char *
search_label(struct of_dev * devp,u_long off,char * buf,struct disklabel * lp,u_long off0)3264c3c91e6Suwe search_label(struct of_dev *devp, u_long off, char *buf,
3274c3c91e6Suwe 	     struct disklabel *lp, u_long off0)
328e144281cSmrg {
329c95f237aStsutsui 	size_t readsize;
330e144281cSmrg 	struct disklabel *dlp;
331e144281cSmrg 	struct sun_disklabel *slp;
332e144281cSmrg 
333e144281cSmrg 	/* minimal requirements for archtypal disk label */
334e144281cSmrg 	if (lp->d_secperunit == 0)
335e144281cSmrg 		lp->d_secperunit = 0x1fffffff;
336e144281cSmrg 	lp->d_npartitions = 1;
337e144281cSmrg 	if (lp->d_partitions[0].p_size == 0)
338e144281cSmrg 		lp->d_partitions[0].p_size = 0x1fffffff;
339e144281cSmrg 	lp->d_partitions[0].p_offset = 0;
340e144281cSmrg 
341c95f237aStsutsui 	if (strategy(devp, F_READ, LABELSECTOR, DEV_BSIZE, buf, &readsize)
342c95f237aStsutsui 	    || readsize != DEV_BSIZE)
343e144281cSmrg 		return ("Cannot read label");
344e144281cSmrg 	/* Check for a NetBSD disk label. */
345e144281cSmrg 	dlp = (struct disklabel *) (buf + LABELOFFSET);
346e144281cSmrg 	if (dlp->d_magic == DISKMAGIC) {
347e144281cSmrg 		if (dkcksum(dlp))
348e144281cSmrg 			return ("NetBSD disk label corrupted");
349e144281cSmrg 		*lp = *dlp;
350e3218c43Smartin 		DPRINTF(("search_label: found NetBSD label\n"));
351e144281cSmrg 		return (NULL);
352e144281cSmrg 	}
353e144281cSmrg 
354e144281cSmrg 	/* Check for a Sun disk label (for PROM compatibility). */
355e144281cSmrg 	slp = (struct sun_disklabel *) buf;
356e144281cSmrg 	if (slp->sl_magic == SUN_DKMAGIC)
357e144281cSmrg 		return (disklabel_sun_to_bsd(buf, lp));
358e144281cSmrg 
359e144281cSmrg 
36054539e4aSjoerg 	memset(buf, 0, DEV_BSIZE);
361e144281cSmrg 	return ("no disk label");
362e144281cSmrg }
363e144281cSmrg 
364*be9f90e8Smartin static void
device_target_unit(const char * dev,int ihandle)365*be9f90e8Smartin device_target_unit(const char *dev, int ihandle)
366*be9f90e8Smartin {
367*be9f90e8Smartin 	cell_t units[4], phandle, myself, depth = 0, odepth = 0, cnt;
368*be9f90e8Smartin 	char buf[256];
369*be9f90e8Smartin 
370*be9f90e8Smartin 	/* init the data passed to the kernel */
371*be9f90e8Smartin 	bootinfo_pass_bootunit = false;
372*be9f90e8Smartin 	memset(&bi_unit, 0, sizeof(bi_unit));
373*be9f90e8Smartin 
374*be9f90e8Smartin 	/* save old my-self value */
375*be9f90e8Smartin 	OF_interpret("my-self", 0, 1, &myself);
376*be9f90e8Smartin 	/* set our device as my-self */
377*be9f90e8Smartin 	OF_interpret("to my-self", 1, 0, HDL2CELL(ihandle));
378*be9f90e8Smartin 
379*be9f90e8Smartin 	/*
380*be9f90e8Smartin 	 * my-unit delivers a variable number of cells, we could
381*be9f90e8Smartin 	 * walk up the path and find a #address-cells value that
382*be9f90e8Smartin 	 * describes it, but it seems to just work this simple
383*be9f90e8Smartin 	 * way.
384*be9f90e8Smartin 	 */
385*be9f90e8Smartin 	OF_interpret("depth", 0, 1, &odepth);
386*be9f90e8Smartin 	OF_interpret("my-unit depth", 0, 5, &depth,
387*be9f90e8Smartin 	    &units[0], &units[1], &units[2], &units[3]);
388*be9f90e8Smartin 	cnt = depth-odepth;
389*be9f90e8Smartin 
390*be9f90e8Smartin 	/*
391*be9f90e8Smartin 	 * Old versions of QEMU's OpenBIOS have a bug in the
392*be9f90e8Smartin 	 * CIF implementation for instance_to_package, test
393*be9f90e8Smartin 	 * for that explicitly here and work around it if needed.
394*be9f90e8Smartin 	 */
395*be9f90e8Smartin 	phandle = OF_instance_to_package(ihandle);
396*be9f90e8Smartin 	OF_package_to_path(phandle, buf, sizeof(buf));
397*be9f90e8Smartin 	buf[sizeof(buf)-1] = 0;
398*be9f90e8Smartin 	if (strlen(buf) > 2 && strlen(dev) > 2 &&
399*be9f90e8Smartin 	    strncmp(buf, dev, strlen(buf)) != 0) {
400*be9f90e8Smartin 		DPRINTF(("OpenBIOS workaround: phandle %" PRIx32 "is %s, "
401*be9f90e8Smartin 		    "does not match %s\n", (uint32_t)phandle, buf, dev));
402*be9f90e8Smartin 		OF_interpret("my-self ihandle>non-interposed-phandle",
403*be9f90e8Smartin 		     0, 1, &phandle);
404*be9f90e8Smartin 		OF_package_to_path(phandle, buf, sizeof(buf));
405*be9f90e8Smartin 		DPRINTF(("new phandle %" PRIx32 " is %s\n",
406*be9f90e8Smartin 		    (uint32_t)phandle, buf));
407*be9f90e8Smartin 	}
408*be9f90e8Smartin 
409*be9f90e8Smartin 	bi_unit.phandle = phandle;
410*be9f90e8Smartin 	bi_unit.parent = OF_parent(phandle);
411*be9f90e8Smartin 	bi_unit.lun = units[cnt > 2 ? 3 : 1];
412*be9f90e8Smartin 	bi_unit.target = units[cnt > 2 ? 2 : 0];
413*be9f90e8Smartin 	if (cnt >= 4)
414*be9f90e8Smartin 		bi_unit.wwn = (uint64_t)units[0] << 32 | (uint32_t)units[1];
415*be9f90e8Smartin 	DPRINTF(("boot device package: %" PRIx32 ", parent: %" PRIx32
416*be9f90e8Smartin 	    ", lun: %" PRIu32 ", target: %" PRIu32 ", wwn: %" PRIx64 "\n",
417*be9f90e8Smartin 	    bi_unit.phandle, bi_unit.parent, bi_unit.lun, bi_unit.target,
418*be9f90e8Smartin 	    bi_unit.wwn));
419*be9f90e8Smartin 
420*be9f90e8Smartin 	/* restore my-self */
421*be9f90e8Smartin 	OF_interpret("to my-self", 1, 0, myself);
422*be9f90e8Smartin 
423*be9f90e8Smartin 	/* now that we have gatherd all the details, pass them to the kernel */
424*be9f90e8Smartin 	bootinfo_pass_bootunit = true;
425*be9f90e8Smartin }
426*be9f90e8Smartin 
427e144281cSmrg int
devopen(struct open_file * of,const char * name,char ** file)4284c3c91e6Suwe devopen(struct open_file *of, const char *name, char **file)
429e144281cSmrg {
430e144281cSmrg 	char *cp;
431e144281cSmrg 	char partition;
4323f99501dSmartin 	char fname[256], devname[256];
4336bcd1bdfSmartin 	union {
434e144281cSmrg 		char buf[DEV_BSIZE];
435e144281cSmrg 		struct disklabel label;
4366bcd1bdfSmartin 	} b;
4376bcd1bdfSmartin 	struct disklabel label;
438e3218c43Smartin 	int handle, part, try = 0;
439c95f237aStsutsui 	size_t readsize;
440c95f237aStsutsui 	char *errmsg = NULL, *pp = NULL, savedpart = 0;
441e144281cSmrg 	int error = 0;
442*be9f90e8Smartin 	bool get_target_unit = false;
443e144281cSmrg 
444e144281cSmrg 	if (ofdev.handle != -1)
4452715e8caSmartin 		panic("devopen: ofdev already in use");
446e144281cSmrg 	if (of->f_flags != F_READ)
447e144281cSmrg 		return EPERM;
448e3218c43Smartin 	DPRINTF(("devopen: you want %s\n", name));
449e144281cSmrg 	strcpy(fname, name);
450e144281cSmrg 	cp = filename(fname, &partition);
451e144281cSmrg 	if (cp) {
4526bcd1bdfSmartin 		strcpy(b.buf, cp);
453e144281cSmrg 		*cp = 0;
454e144281cSmrg 	}
4556bcd1bdfSmartin 	if (!cp || !b.buf[0])
4566bcd1bdfSmartin 		strcpy(b.buf, DEFAULT_KERNEL);
457e144281cSmrg 	if (!*fname)
458e144281cSmrg 		strcpy(fname, bootdev);
459e144281cSmrg 	strcpy(opened_name, fname);
460e144281cSmrg 	if (partition) {
461e144281cSmrg 		cp = opened_name + strlen(opened_name);
462e144281cSmrg 		*cp++ = ':';
463e144281cSmrg 		*cp++ = partition;
464e144281cSmrg 		*cp = 0;
465e144281cSmrg 	}
4664c2f43b8Smartin 	*file = opened_name + strlen(opened_name);
4676bcd1bdfSmartin 	if (b.buf[0] != '/')
468e144281cSmrg 		strcat(opened_name, "/");
4696bcd1bdfSmartin 	strcat(opened_name, b.buf);
470e3218c43Smartin 	DPRINTF(("devopen: trying %s\n", fname));
47197aa1417Scdi 	if ((handle = prom_finddevice(fname)) == -1)
472e144281cSmrg 		return ENOENT;
473e3218c43Smartin 	DPRINTF(("devopen: found %s\n", fname));
4746bcd1bdfSmartin 	if (_prom_getprop(handle, "name", b.buf, sizeof b.buf) < 0)
475e144281cSmrg 		return ENXIO;
476e3218c43Smartin 	DPRINTF(("devopen: %s is called %s\n", fname, b.buf));
4776bcd1bdfSmartin 	floppyboot = !strcmp(b.buf, "floppy");
4786bcd1bdfSmartin 	if (_prom_getprop(handle, "device_type", b.buf, sizeof b.buf) < 0)
479e144281cSmrg 		return ENXIO;
480e3218c43Smartin 	DPRINTF(("devopen: %s is a %s device\n", fname, b.buf));
4810ed481bcSmartin 	if (strcmp(b.buf, "block") == 0 || strcmp(b.buf, "scsi") == 0) {
482*be9f90e8Smartin 
483*be9f90e8Smartin 		get_target_unit = true;
484*be9f90e8Smartin 
485e3218c43Smartin 		pp = strrchr(fname, ':');
486e3218c43Smartin 		if (pp && pp[1] >= 'a' && pp[1] <= 'f' && pp[2] == 0) {
487e3218c43Smartin 			savedpart = pp[1];
488e3218c43Smartin 		} else {
489e3218c43Smartin 			savedpart = 'a';
4903f99501dSmartin 			handle = prom_open(fname);
4913f99501dSmartin 			if (handle != -1) {
4923f99501dSmartin 				OF_instance_to_path(handle, devname,
4933f99501dSmartin 				    sizeof(devname));
4943f99501dSmartin 				DPRINTF(("real path: %s\n", devname));
4953f99501dSmartin 				prom_close(handle);
4963f99501dSmartin 				pp = devname + strlen(devname);
4973f99501dSmartin 				if (pp > devname + 3) pp -= 2;
4983f99501dSmartin 				if (pp[0] == ':')
4993f99501dSmartin 					savedpart = pp[1];
5003f99501dSmartin 			}
501e3218c43Smartin 			pp = fname + strlen(fname);
502e3218c43Smartin 			pp[0] = ':';
503e3218c43Smartin 			pp[2] = '\0';
504e3218c43Smartin 		}
505e3218c43Smartin 		pp[1] = 'c';
506e3218c43Smartin 		DPRINTF(("devopen: replacing by whole disk device %s\n",
507e3218c43Smartin 		    fname));
5083f99501dSmartin 		if (savedpart)
5093f99501dSmartin 			partition = savedpart;
510e3218c43Smartin 	}
511e3218c43Smartin 
512e3218c43Smartin open_again:
513e3218c43Smartin 	DPRINTF(("devopen: opening %s\n", fname));
51497aa1417Scdi 	if ((handle = prom_open(fname)) == -1) {
515e3218c43Smartin 		DPRINTF(("devopen: open of %s failed\n", fname));
516e3218c43Smartin 		if (pp && savedpart) {
517e3218c43Smartin 			if (try == 0) {
518e3218c43Smartin 				pp[0] = '\0';
519e3218c43Smartin 				try = 1;
520e3218c43Smartin 			} else {
521e3218c43Smartin 				pp[0] = ':';
522e3218c43Smartin 				pp[1] = savedpart;
523e3218c43Smartin 				pp = NULL;
524e3218c43Smartin 				savedpart = '\0';
525e3218c43Smartin 			}
526e3218c43Smartin 			goto open_again;
527e3218c43Smartin 		}
528e144281cSmrg 		return ENXIO;
529e144281cSmrg 	}
530e3218c43Smartin 	DPRINTF(("devopen: %s is now open\n", fname));
531*be9f90e8Smartin 
532*be9f90e8Smartin 	if (get_target_unit)
533*be9f90e8Smartin 		device_target_unit(fname, handle);
534*be9f90e8Smartin 
535c363a9cbScegger 	memset(&ofdev, 0, sizeof ofdev);
536e144281cSmrg 	ofdev.handle = handle;
5370ed481bcSmartin 	if (strcmp(b.buf, "block") == 0 || strcmp(b.buf, "scsi") == 0) {
538e144281cSmrg 		ofdev.type = OFDEV_DISK;
539e144281cSmrg 		ofdev.bsize = DEV_BSIZE;
540e144281cSmrg 		/* First try to find a disklabel without MBR partitions */
541e3218c43Smartin 		DPRINTF(("devopen: trying to read disklabel\n"));
542e144281cSmrg 		if (strategy(&ofdev, F_READ,
543c95f237aStsutsui 			     LABELSECTOR, DEV_BSIZE, b.buf, &readsize) != 0
544c95f237aStsutsui 		    || readsize != DEV_BSIZE
5456bcd1bdfSmartin 		    || (errmsg = getdisklabel(b.buf, &label))) {
5462e897a5cSmartin 			if (errmsg) {
5472e897a5cSmartin 				DPRINTF(("devopen: getdisklabel returned %s\n",
5482e897a5cSmartin 					errmsg));
5492e897a5cSmartin 			}
550e144281cSmrg 			/* Else try MBR partitions */
5516bcd1bdfSmartin 			errmsg = search_label(&ofdev, 0, b.buf, &label, 0);
552e144281cSmrg 			if (errmsg) {
553068c31feSgrant 				printf("devopen: search_label returned %s\n", errmsg);
554e144281cSmrg 				error = ERDLAB;
555e144281cSmrg 			}
556e144281cSmrg 			if (error && error != ERDLAB)
557e144281cSmrg 				goto bad;
558e144281cSmrg 		}
559e144281cSmrg 
560e144281cSmrg 		if (error == ERDLAB) {
561e144281cSmrg 			/* No, label, just use complete disk */
562e144281cSmrg 			ofdev.partoff = 0;
563e3218c43Smartin 			if (pp && savedpart) {
564e3218c43Smartin 				pp[1] = savedpart;
565e3218c43Smartin 				prom_close(handle);
566e3218c43Smartin 				if ((handle = prom_open(fname)) == -1) {
567e3218c43Smartin 					DPRINTF(("devopen: open of %s failed\n",
568e3218c43Smartin 						fname));
569e3218c43Smartin 					return ENXIO;
570e3218c43Smartin 				}
571e3218c43Smartin 				ofdev.handle = handle;
572e3218c43Smartin 				DPRINTF(("devopen: back to original device %s\n",
573e3218c43Smartin 					fname));
574e3218c43Smartin 			}
575e144281cSmrg 		} else {
576e144281cSmrg 			part = partition ? partition - 'a' : 0;
577e144281cSmrg 			ofdev.partoff = label.d_partitions[part].p_offset;
5783bf07950Snakayama 			DPRINTF(("devopen: setting partition %d offset %lx\n",
579e3218c43Smartin 			       part, ofdev.partoff));
5803a0d6097Smrg 			if (label.d_partitions[part].p_fstype == FS_RAID) {
5813a0d6097Smrg 				ofdev.partoff += RF_PROTECTED_SECTORS;
582e3218c43Smartin 				DPRINTF(("devopen: found RAID partition, "
5833bf07950Snakayama 				    "adjusting offset to %lx\n", ofdev.partoff));
5843a0d6097Smrg 			}
585e144281cSmrg 		}
586e144281cSmrg 
587e3218c43Smartin 		nfsys = 0;
588cec53020Smrg 		of->f_dev = ofdevsw;
589e144281cSmrg 		of->f_devdata = &ofdev;
590e144281cSmrg #ifdef SPARC_BOOT_UFS
591feea5ba2Seeh 		memcpy(&file_system[nfsys++], &file_system_ufs[0], sizeof file_system[0]);
592feea5ba2Seeh 		memcpy(&file_system[nfsys++], &file_system_ufs[1], sizeof file_system[0]);
593feea5ba2Seeh 		memcpy(&file_system[nfsys++], &file_system_ufs[2], sizeof file_system[0]);
594feea5ba2Seeh 		memcpy(&file_system[nfsys++], &file_system_ufs[3], sizeof file_system[0]);
595e144281cSmrg #endif
596c068dc64Smartin #ifdef SPARC_BOOT_CD9660
597feea5ba2Seeh 		memcpy(&file_system[nfsys++], &file_system_cd9660, sizeof file_system[0]);
598e144281cSmrg #endif
599e3218c43Smartin 		DPRINTF(("devopen: return 0\n"));
600e144281cSmrg 		return 0;
601e144281cSmrg 	}
602e144281cSmrg #ifdef NETBOOT
6036bcd1bdfSmartin 	if (!strcmp(b.buf, "network")) {
604c95f237aStsutsui 		if ((error = net_open(&ofdev)) != 0)
605e144281cSmrg 			goto bad;
60617740d28Smlelstv 
60717740d28Smlelstv 		ofdev.type = OFDEV_NET;
60817740d28Smlelstv 		of->f_dev = ofdevsw;
609deb09ce5Smartin 		of->f_devdata = &ofdev;
61017740d28Smlelstv 
61117740d28Smlelstv 		if (!strncmp(*file,"/tftp:",6)) {
61217740d28Smlelstv 			*file += 6;
613e2cb8590Scegger 			memcpy(&file_system[0], &file_system_tftp, sizeof file_system[0]);
6148aa95513Stsutsui 			if (net_tftp_bootp((int **)&of->f_devdata)) {
61517740d28Smlelstv 				net_close(&ofdev);
61617740d28Smlelstv 				goto bad;
61717740d28Smlelstv 			}
6189df63719Smartin 			root_fs_quickseekable = false;
61917740d28Smlelstv 		} else {
620e2cb8590Scegger 			memcpy(&file_system[0], &file_system_nfs, sizeof file_system[0]);
621c95f237aStsutsui 			if ((error = net_mountroot()) != 0) {
62217740d28Smlelstv 				net_close(&ofdev);
62317740d28Smlelstv 				goto bad;
62417740d28Smlelstv 			}
62517740d28Smlelstv 		}
62617740d28Smlelstv 		nfsys = 1;
627e144281cSmrg 		return 0;
628e144281cSmrg 	}
629e144281cSmrg #endif
630e144281cSmrg 	error = EFTYPE;
631e144281cSmrg bad:
632e3218c43Smartin 	DPRINTF(("devopen: error %d, cannot open device\n", error));
63397aa1417Scdi 	prom_close(handle);
634e144281cSmrg 	ofdev.handle = -1;
635e144281cSmrg 	return error;
636e144281cSmrg }
637