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