1*6dfc32acSmiod /* $OpenBSD: autoconf.c,v 1.151 2024/05/17 20:05:08 miod Exp $ */
2284584b0Sjason /* $NetBSD: autoconf.c,v 1.51 2001/07/24 19:32:11 eeh Exp $ */
3284584b0Sjason
4284584b0Sjason /*
5284584b0Sjason * Copyright (c) 1996
6284584b0Sjason * The President and Fellows of Harvard College. All rights reserved.
7284584b0Sjason * Copyright (c) 1992, 1993
8284584b0Sjason * The Regents of the University of California. All rights reserved.
9284584b0Sjason *
10284584b0Sjason * This software was developed by the Computer Systems Engineering group
11284584b0Sjason * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12284584b0Sjason * contributed to Berkeley.
13284584b0Sjason *
14284584b0Sjason * All advertising materials mentioning features or use of this software
15284584b0Sjason * must display the following acknowledgement:
16284584b0Sjason * This product includes software developed by Harvard University.
17284584b0Sjason * This product includes software developed by the University of
18284584b0Sjason * California, Lawrence Berkeley Laboratory.
19284584b0Sjason *
20284584b0Sjason * Redistribution and use in source and binary forms, with or without
21284584b0Sjason * modification, are permitted provided that the following conditions
22284584b0Sjason * are met:
23284584b0Sjason * 1. Redistributions of source code must retain the above copyright
24284584b0Sjason * notice, this list of conditions and the following disclaimer.
25284584b0Sjason * 2. Redistributions in binary form must reproduce the above copyright
26284584b0Sjason * notice, this list of conditions and the following disclaimer in the
27284584b0Sjason * documentation and/or other materials provided with the distribution.
2829295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
29284584b0Sjason * may be used to endorse or promote products derived from this software
30284584b0Sjason * without specific prior written permission.
31284584b0Sjason *
32284584b0Sjason * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33284584b0Sjason * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34284584b0Sjason * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35284584b0Sjason * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36284584b0Sjason * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37284584b0Sjason * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38284584b0Sjason * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39284584b0Sjason * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40284584b0Sjason * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41284584b0Sjason * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42284584b0Sjason * SUCH DAMAGE.
43284584b0Sjason *
44284584b0Sjason * @(#)autoconf.c 8.4 (Berkeley) 10/1/93
45284584b0Sjason */
46284584b0Sjason
4757949900Sdlg #include "mpath.h"
4857949900Sdlg
49284584b0Sjason #include <sys/param.h>
50284584b0Sjason #include <sys/systm.h>
51284584b0Sjason #include <sys/buf.h>
52284584b0Sjason #include <sys/disklabel.h>
53284584b0Sjason #include <sys/device.h>
54284584b0Sjason #include <sys/disk.h>
55284584b0Sjason #include <sys/conf.h>
56284584b0Sjason #include <sys/reboot.h>
57284584b0Sjason #include <sys/socket.h>
58284584b0Sjason #include <sys/malloc.h>
59284584b0Sjason #include <sys/queue.h>
60284584b0Sjason #include <sys/msgbuf.h>
61284584b0Sjason
62284584b0Sjason #include <net/if.h>
63284584b0Sjason
64284584b0Sjason #include <dev/cons.h>
6562ab431fSkettenis #include <dev/clock_subr.h>
66284584b0Sjason
67284584b0Sjason #include <uvm/uvm_extern.h>
68284584b0Sjason
69284584b0Sjason #include <machine/bus.h>
70237fd37fSstsp #include <machine/boot_flag.h>
71284584b0Sjason #include <machine/autoconf.h>
722c4be14aSkettenis #include <machine/hypervisor.h>
73e4edc0c7Skettenis #include <machine/mdesc.h>
74284584b0Sjason #include <machine/openfirm.h>
75284584b0Sjason #include <machine/sparc64.h>
76284584b0Sjason #include <machine/cpu.h>
77284584b0Sjason #include <machine/pmap.h>
78a62eb7c4Skettenis #include <machine/trap.h>
792c4be14aSkettenis #include <sparc64/sparc64/cache.h>
80b57f54d2Skettenis #include <sparc64/dev/vbusvar.h>
81b57f54d2Skettenis #include <sparc64/dev/cbusvar.h>
82284584b0Sjason
83237fd37fSstsp #include <stand/boot/bootarg.h>
84237fd37fSstsp
85284584b0Sjason #include <dev/ata/atavar.h>
86284584b0Sjason #include <dev/pci/pcivar.h>
87284584b0Sjason #include <dev/sbus/sbusvar.h>
88284584b0Sjason
890300c697Sjason #include <scsi/scsi_all.h>
900300c697Sjason #include <scsi/scsiconf.h>
9157949900Sdlg #if NMPATH > 0
9257949900Sdlg #include <scsi/mpathvar.h>
9357949900Sdlg #endif
940300c697Sjason
95284584b0Sjason #ifdef DDB
96284584b0Sjason #include <machine/db_machdep.h>
97284584b0Sjason #include <ddb/db_sym.h>
98284584b0Sjason #include <ddb/db_extern.h>
99284584b0Sjason #endif
100284584b0Sjason
101237fd37fSstsp #include "softraid.h"
102237fd37fSstsp #if NSOFTRAID > 0
103237fd37fSstsp #include <sys/sensors.h>
104237fd37fSstsp #include <dev/softraidvar.h>
105237fd37fSstsp
106237fd37fSstsp /* XXX */
107237fd37fSstsp #undef DPRINTF
108237fd37fSstsp #undef DNPRINTF
109237fd37fSstsp #endif
110237fd37fSstsp
111284584b0Sjason int printspl = 0;
112284584b0Sjason
113284584b0Sjason /*
114284584b0Sjason * The following several variables are related to
115284584b0Sjason * the configuration process, and are used in initializing
116284584b0Sjason * the machine.
117284584b0Sjason */
118284584b0Sjason int stdinnode; /* node ID of ROM's console input device */
119284584b0Sjason int fbnode; /* node ID of ROM's console output device */
120284584b0Sjason int optionsnode; /* node ID of ROM's options */
121284584b0Sjason
122284584b0Sjason static int rootnode;
123284584b0Sjason
124c5632f19Sjason static char *str2hex(char *, long *);
125c4071fd1Smillert static int mbprint(void *, const char *);
126c4071fd1Smillert int mainbus_match(struct device *, void *, void *);
127c4071fd1Smillert static void mainbus_attach(struct device *, struct device *, void *);
12804235f00Skettenis int get_ncpus(void);
129284584b0Sjason
1300300c697Sjason struct device *booted_device;
131404b377eSkettenis struct bootpath bootpath[16];
132284584b0Sjason int nbootpath;
133fb1ca35cSkettenis int bootnode;
134c4071fd1Smillert static void bootpath_build(void);
135c4071fd1Smillert static void bootpath_print(struct bootpath *);
136fb1ca35cSkettenis void bootpath_nodes(struct bootpath *, int);
137284584b0Sjason
138237fd37fSstsp struct openbsd_bootdata obd __attribute__((section(".openbsd.bootdata")));
139237fd37fSstsp
140c4071fd1Smillert void nail_bootdev(struct device *, struct bootpath *);
1410300c697Sjason
142284584b0Sjason /* Global interrupt mappings for all device types. Match against the OBP
143284584b0Sjason * 'device_type' property.
144284584b0Sjason */
145284584b0Sjason struct intrmap intrmap[] = {
146284584b0Sjason { "block", PIL_FD }, /* Floppy disk */
147284584b0Sjason { "serial", PIL_SER }, /* zs */
148284584b0Sjason { "scsi", PIL_SCSI },
1493a39115dSbrad { "scsi-2", PIL_SCSI },
150284584b0Sjason { "network", PIL_NET },
151284584b0Sjason { "display", PIL_VIDEO },
152284584b0Sjason { "audio", PIL_AUD },
153284584b0Sjason { "ide", PIL_SCSI },
154284584b0Sjason /* The following devices don't have device types: */
155284584b0Sjason { "SUNW,CS4231", PIL_AUD },
156284584b0Sjason { NULL, 0 }
157284584b0Sjason };
158284584b0Sjason
1590ddf3f06Skettenis #ifdef SUN4V
1600ddf3f06Skettenis void sun4v_soft_state_init(void);
1610ddf3f06Skettenis void sun4v_set_soft_state(int, const char *);
1620ddf3f06Skettenis
1630ddf3f06Skettenis #define __align32 __attribute__((__aligned__(32)))
1640ddf3f06Skettenis char sun4v_soft_state_booting[] __align32 = "OpenBSD booting";
1650ddf3f06Skettenis char sun4v_soft_state_running[] __align32 = "OpenBSD running";
16601555c0fSkettenis
16701555c0fSkettenis void sun4v_interrupt_init(void);
168090b5ccfSkettenis void sun4v_sdio_init(void);
1690ddf3f06Skettenis #endif
17025b7217fSjason
171d00b7f60Smiod extern void us_tlb_flush_pte(vaddr_t, uint64_t);
172d00b7f60Smiod extern void us3_tlb_flush_pte(vaddr_t, uint64_t);
173d00b7f60Smiod extern void sun4v_tlb_flush_pte(vaddr_t, uint64_t);
174d00b7f60Smiod extern void us_tlb_flush_ctx(uint64_t);
175d00b7f60Smiod extern void us3_tlb_flush_ctx(uint64_t);
176d00b7f60Smiod extern void sun4v_tlb_flush_ctx(uint64_t);
177d00b7f60Smiod
178d00b7f60Smiod void (*sp_tlb_flush_pte)(vaddr_t, uint64_t) = us_tlb_flush_pte;
179d00b7f60Smiod void (*sp_tlb_flush_ctx)(uint64_t) = us_tlb_flush_ctx;
180d00b7f60Smiod
181284584b0Sjason #ifdef DEBUG
182284584b0Sjason #define ACDB_BOOTDEV 0x1
183284584b0Sjason #define ACDB_PROBE 0x2
184284584b0Sjason int autoconf_debug = 0x0;
185284584b0Sjason #define DPRINTF(l, s) do { if (autoconf_debug & l) printf s; } while (0)
186284584b0Sjason #else
187284584b0Sjason #define DPRINTF(l, s)
188284584b0Sjason #endif
189284584b0Sjason
190284584b0Sjason /*
191284584b0Sjason * Convert hex ASCII string to a value. Returns updated pointer.
192284584b0Sjason * Depends on ASCII order (this *is* machine-dependent code, you know).
193284584b0Sjason */
194284584b0Sjason static char *
str2hex(char * str,long * vp)195c5632f19Sjason str2hex(char *str, long *vp)
196284584b0Sjason {
197c5632f19Sjason long v;
198c5632f19Sjason int c;
199c5632f19Sjason
200c5632f19Sjason if (*str == 'w') {
201c5632f19Sjason for (v = 1;; v++) {
202c5632f19Sjason if (str[v] >= '0' && str[v] <= '9')
203c5632f19Sjason continue;
204c5632f19Sjason if (str[v] >= 'a' && str[v] <= 'f')
205c5632f19Sjason continue;
206c5632f19Sjason if (str[v] >= 'A' && str[v] <= 'F')
207c5632f19Sjason continue;
208c5632f19Sjason if (str[v] == '\0' || str[v] == ',')
209c5632f19Sjason break;
210c5632f19Sjason *vp = 0;
211c5632f19Sjason return (str + v);
212c5632f19Sjason }
213c5632f19Sjason str++;
214c5632f19Sjason }
215284584b0Sjason
216284584b0Sjason for (v = 0;; v = v * 16 + c, str++) {
217284584b0Sjason c = *(u_char *)str;
218284584b0Sjason if (c <= '9') {
219284584b0Sjason if ((c -= '0') < 0)
220284584b0Sjason break;
221284584b0Sjason } else if (c <= 'F') {
222284584b0Sjason if ((c -= 'A' - 10) < 10)
223284584b0Sjason break;
224284584b0Sjason } else if (c <= 'f') {
225284584b0Sjason if ((c -= 'a' - 10) < 10)
226284584b0Sjason break;
227284584b0Sjason } else
228284584b0Sjason break;
229284584b0Sjason }
230284584b0Sjason *vp = v;
231284584b0Sjason return (str);
232284584b0Sjason }
233284584b0Sjason
23406fa7dd9Skettenis /*
23506fa7dd9Skettenis * Hunt through the device tree for CPUs. There should be no need to
23606fa7dd9Skettenis * go more than four levels deep; an UltraSPARC-IV on Seregeti shows
23706fa7dd9Skettenis * up as /ssm@0,0/cmp@0,0/cpu@0 and a SPARC64-VI will show up as
23806fa7dd9Skettenis * /cmp@0,0/core@0/cpu@0.
23906fa7dd9Skettenis */
24004235f00Skettenis int
get_ncpus(void)24104235f00Skettenis get_ncpus(void)
24204235f00Skettenis {
24306fa7dd9Skettenis int node, child, stack[4], depth, ncpus;
24404235f00Skettenis char buf[32];
24504235f00Skettenis
24606fa7dd9Skettenis stack[0] = findroot();
24706fa7dd9Skettenis depth = 0;
24804235f00Skettenis
24904235f00Skettenis ncpus = 0;
25006fa7dd9Skettenis for (;;) {
25106fa7dd9Skettenis node = stack[depth];
25206fa7dd9Skettenis
25306fa7dd9Skettenis if (node == 0 || node == -1) {
25406fa7dd9Skettenis if (--depth < 0)
255663f3520Sderaadt goto done;
25606fa7dd9Skettenis
25706fa7dd9Skettenis stack[depth] = OF_peer(stack[depth]);
25804235f00Skettenis continue;
25904235f00Skettenis }
26004235f00Skettenis
26106fa7dd9Skettenis if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
26206fa7dd9Skettenis strcmp(buf, "cpu") == 0)
26304235f00Skettenis ncpus++;
26404235f00Skettenis
26506fa7dd9Skettenis child = OF_child(node);
26606fa7dd9Skettenis if (child != 0 && child != -1 && depth < 3)
26706fa7dd9Skettenis stack[++depth] = child;
26806fa7dd9Skettenis else
26906fa7dd9Skettenis stack[depth] = OF_peer(stack[depth]);
27004235f00Skettenis }
27104235f00Skettenis
272663f3520Sderaadt done:
273663f3520Sderaadt ncpusfound = ncpus;
274663f3520Sderaadt #ifdef MULTIPROCESSOR
275663f3520Sderaadt return (ncpus);
27604235f00Skettenis #else
27704235f00Skettenis return (1);
27804235f00Skettenis #endif
27904235f00Skettenis }
280f626355dSkettenis
281284584b0Sjason /*
282284584b0Sjason * locore.s code calls bootstrap() just before calling main().
283284584b0Sjason *
284284584b0Sjason * What we try to do is as follows:
285284584b0Sjason *
286284584b0Sjason * 1) We will try to re-allocate the old message buffer.
287284584b0Sjason *
288284584b0Sjason * 2) We will then get the list of the total and available
289284584b0Sjason * physical memory and available virtual memory from the
290284584b0Sjason * prom.
291284584b0Sjason *
292284584b0Sjason * 3) We will pass the list to pmap_bootstrap to manage them.
293284584b0Sjason *
294284584b0Sjason * We will try to run out of the prom until we get to cpu_init().
295284584b0Sjason */
296284584b0Sjason void
bootstrap(int nctx)297ba134ca3Sstsp bootstrap(int nctx)
298284584b0Sjason {
299284584b0Sjason extern int end; /* End of kernel */
300f0ec91c2Skettenis struct trapvec *romtba;
301b4c7a3a8Skettenis #if defined(SUN4US) || defined(SUN4V)
30290572c87Skettenis char buf[32];
30390572c87Skettenis #endif
304462ff407Skettenis int impl = 0;
30504235f00Skettenis int ncpus;
306284584b0Sjason
307baf89de9Skettenis /* Initialize the PROM console so printf will not panic. */
308baf89de9Skettenis (*cn_tab->cn_init)(cn_tab);
309baf89de9Skettenis
310284584b0Sjason /*
311284584b0Sjason * Initialize ddb first and register OBP callbacks.
312284584b0Sjason * We can do this because ddb_init() does not allocate anything,
313d0b398a2Sjmc * just initializes some pointers to important things
314284584b0Sjason * like the symtab.
315284584b0Sjason *
316284584b0Sjason * By doing this first and installing the OBP callbacks
317284584b0Sjason * we get to do symbolic debugging of pmap_bootstrap().
318284584b0Sjason */
319284584b0Sjason #ifdef DDB
3206ecd5bf4Sjason db_machine_init();
321284584b0Sjason ddb_init();
322284584b0Sjason /* This can only be installed on an 64-bit system cause otherwise our stack is screwed */
323284584b0Sjason OF_set_symbol_lookup(OF_sym2val, OF_val2sym);
324284584b0Sjason #endif
325284584b0Sjason
326b4c7a3a8Skettenis #if defined (SUN4US) || defined(SUN4V)
327b4c7a3a8Skettenis if (OF_getprop(findroot(), "compatible", buf, sizeof(buf)) > 0) {
328b4c7a3a8Skettenis if (strcmp(buf, "sun4us") == 0)
329b4c7a3a8Skettenis cputyp = CPU_SUN4US;
330b4c7a3a8Skettenis if (strcmp(buf, "sun4v") == 0)
33190572c87Skettenis cputyp = CPU_SUN4V;
332b4c7a3a8Skettenis }
33390572c87Skettenis #endif
33490572c87Skettenis
335462ff407Skettenis /* We cannot read %ver on sun4v systems. */
336462ff407Skettenis if (CPU_ISSUN4U || CPU_ISSUN4US)
337462ff407Skettenis impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT;
338462ff407Skettenis
339462ff407Skettenis if (impl >= IMPL_CHEETAH) {
340462ff407Skettenis extern vaddr_t dlflush_start;
341462ff407Skettenis vaddr_t *pva;
342462ff407Skettenis u_int32_t insn;
343462ff407Skettenis
344462ff407Skettenis for (pva = &dlflush_start; *pva; pva++) {
345462ff407Skettenis insn = *(u_int32_t *)(*pva);
346462ff407Skettenis insn &= ~(ASI_DCACHE_TAG << 5);
347462ff407Skettenis insn |= (ASI_DCACHE_INVALIDATE << 5);
348462ff407Skettenis *(u_int32_t *)(*pva) = insn;
349462ff407Skettenis flush((void *)(*pva));
350462ff407Skettenis }
351462ff407Skettenis
352462ff407Skettenis cacheinfo.c_dcache_flush_page = us3_dcache_flush_page;
353d00b7f60Smiod sp_tlb_flush_pte = us3_tlb_flush_pte;
354d00b7f60Smiod sp_tlb_flush_ctx = us3_tlb_flush_ctx;
355462ff407Skettenis }
356462ff407Skettenis
357462ff407Skettenis if ((impl >= IMPL_ZEUS && impl <= IMPL_JUPITER) || CPU_ISSUN4V) {
35831b3c1c3Skettenis extern vaddr_t dlflush_start;
3592c4be14aSkettenis vaddr_t *pva;
3602c4be14aSkettenis
3612c4be14aSkettenis for (pva = &dlflush_start; *pva; pva++) {
3622c4be14aSkettenis *(u_int32_t *)(*pva) = 0x01000000; /* nop */
3632c4be14aSkettenis flush((void *)(*pva));
3642c4be14aSkettenis }
3652c4be14aSkettenis
366b4c7a3a8Skettenis cacheinfo.c_dcache_flush_page = no_dcache_flush_page;
367b4c7a3a8Skettenis }
368b4c7a3a8Skettenis
369958674eeSkettenis #ifdef MULTIPROCESSOR
370958674eeSkettenis if (impl >= IMPL_OLYMPUS_C && impl <= IMPL_JUPITER) {
371958674eeSkettenis struct sun4u_patch {
372958674eeSkettenis u_int32_t addr;
373958674eeSkettenis u_int32_t insn;
374958674eeSkettenis } *p;
375958674eeSkettenis
376958674eeSkettenis extern struct sun4u_patch sun4u_mtp_patch;
377958674eeSkettenis extern struct sun4u_patch sun4u_mtp_patch_end;
378958674eeSkettenis
379958674eeSkettenis for (p = &sun4u_mtp_patch; p < &sun4u_mtp_patch_end; p++) {
380958674eeSkettenis *(u_int32_t *)(vaddr_t)p->addr = p->insn;
381958674eeSkettenis flush((void *)(vaddr_t)p->addr);
382958674eeSkettenis }
383958674eeSkettenis }
384958674eeSkettenis #endif
385958674eeSkettenis
386b4c7a3a8Skettenis #ifdef SUN4V
387b4c7a3a8Skettenis if (CPU_ISSUN4V) {
38864958104Skettenis struct sun4v_patch {
38964958104Skettenis u_int32_t addr;
39064958104Skettenis u_int32_t insn;
39131b3c1c3Skettenis } *p;
39264958104Skettenis
39331b3c1c3Skettenis extern struct sun4v_patch sun4v_patch;
39431b3c1c3Skettenis extern struct sun4v_patch sun4v_patch_end;
39531b3c1c3Skettenis
39631b3c1c3Skettenis for (p = &sun4v_patch; p < &sun4v_patch_end; p++) {
39731b3c1c3Skettenis *(u_int32_t *)(vaddr_t)p->addr = p->insn;
39831b3c1c3Skettenis flush((void *)(vaddr_t)p->addr);
39931b3c1c3Skettenis }
40031b3c1c3Skettenis
40131b3c1c3Skettenis #ifdef MULTIPROCESSOR
40264958104Skettenis extern struct sun4v_patch sun4v_mp_patch;
40364958104Skettenis extern struct sun4v_patch sun4v_mp_patch_end;
40464958104Skettenis
40564958104Skettenis for (p = &sun4v_mp_patch; p < &sun4v_mp_patch_end; p++) {
40664958104Skettenis *(u_int32_t *)(vaddr_t)p->addr = p->insn;
40764958104Skettenis flush((void *)(vaddr_t)p->addr);
40864958104Skettenis }
40964958104Skettenis #endif
41064958104Skettenis
411d00b7f60Smiod sp_tlb_flush_pte = sun4v_tlb_flush_pte;
412d00b7f60Smiod sp_tlb_flush_ctx = sun4v_tlb_flush_ctx;
4132c4be14aSkettenis }
4142c4be14aSkettenis #endif
4152c4be14aSkettenis
416f0ec91c2Skettenis /*
417f0ec91c2Skettenis * Copy over the OBP breakpoint trap vector; OpenFirmware 5.x
418f0ec91c2Skettenis * needs it to be able to return to the ok prompt.
419f0ec91c2Skettenis */
420f0ec91c2Skettenis romtba = (struct trapvec *)sparc_rdpr(tba);
421f0ec91c2Skettenis bcopy(&romtba[T_MON_BREAKPOINT], &trapbase[T_MON_BREAKPOINT],
422f0ec91c2Skettenis sizeof(struct trapvec));
423f0ec91c2Skettenis flush((void *)trapbase);
424f0ec91c2Skettenis
42504235f00Skettenis ncpus = get_ncpus();
42604235f00Skettenis pmap_bootstrap(KERNBASE, (u_long)&end, nctx, ncpus);
4270ddf3f06Skettenis
4286a5bfaa2Skettenis if (obd.version == BOOTDATA_VERSION &&
429e653d891Skn obd.len >= BOOTDATA_LEN_BOOTHOWTO)
4306a5bfaa2Skettenis boothowto = obd.boothowto;
4316a5bfaa2Skettenis
4320ddf3f06Skettenis #ifdef SUN4V
4330ddf3f06Skettenis if (CPU_ISSUN4V) {
4340ddf3f06Skettenis sun4v_soft_state_init();
4350ddf3f06Skettenis sun4v_set_soft_state(SIS_TRANSITION, sun4v_soft_state_booting);
43601555c0fSkettenis sun4v_interrupt_init();
437090b5ccfSkettenis sun4v_sdio_init();
4380ddf3f06Skettenis }
4390ddf3f06Skettenis #endif
440284584b0Sjason }
441284584b0Sjason
44245a28fb1Sjason void
bootpath_nodes(struct bootpath * bp,int nbp)443fb1ca35cSkettenis bootpath_nodes(struct bootpath *bp, int nbp)
44445a28fb1Sjason {
445fb1ca35cSkettenis int chosen;
44645a28fb1Sjason int i;
44745a28fb1Sjason char buf[128], *cp, c;
44845a28fb1Sjason
44945a28fb1Sjason chosen = OF_finddevice("/chosen");
45045a28fb1Sjason OF_getprop(chosen, "bootpath", buf, sizeof(buf));
45145a28fb1Sjason cp = buf;
45245a28fb1Sjason
45345a28fb1Sjason for (i = 0; i < nbp; i++, bp++) {
45445a28fb1Sjason if (*cp == '\0')
45545a28fb1Sjason return;
45645a28fb1Sjason while (*cp != '\0' && *cp == '/')
45745a28fb1Sjason cp++;
45845a28fb1Sjason while (*cp && *cp != '/')
45945a28fb1Sjason cp++;
46045a28fb1Sjason c = *cp;
46145a28fb1Sjason *cp = '\0';
462fb1ca35cSkettenis bootnode = bp->node = OF_finddevice(buf);
46345a28fb1Sjason *cp = c;
46445a28fb1Sjason }
46545a28fb1Sjason }
46645a28fb1Sjason
467284584b0Sjason /*
468284584b0Sjason * bootpath_build: build a bootpath. Used when booting a generic
469284584b0Sjason * kernel to find our root device. Newer proms give us a bootpath,
470284584b0Sjason * for older proms we have to create one. An element in a bootpath
471284584b0Sjason * has 4 fields: name (device name), val[0], val[1], and val[2]. Note that:
472284584b0Sjason * Interpretation of val[] is device-dependent. Some examples:
473284584b0Sjason *
474284584b0Sjason * if (val[0] == -1) {
475284584b0Sjason * val[1] is a unit number (happens most often with old proms)
476284584b0Sjason * } else {
477284584b0Sjason * [sbus device] val[0] is a sbus slot, and val[1] is an sbus offset
478284584b0Sjason * [scsi disk] val[0] is target, val[1] is lun, val[2] is partition
479284584b0Sjason * [scsi tape] val[0] is target, val[1] is lun, val[2] is file #
480284584b0Sjason * [pci device] val[0] is device, val[1] is function, val[2] might be partition
481284584b0Sjason * }
482284584b0Sjason *
483284584b0Sjason */
484284584b0Sjason
485284584b0Sjason static void
bootpath_build(void)4860aac5001Snaddy bootpath_build(void)
487284584b0Sjason {
488284584b0Sjason register char *cp, *pp;
489284584b0Sjason register struct bootpath *bp;
490284584b0Sjason register long chosen;
491284584b0Sjason char buf[128];
492284584b0Sjason
493284584b0Sjason bzero((void *)bootpath, sizeof(bootpath));
494284584b0Sjason bp = bootpath;
495284584b0Sjason
496284584b0Sjason /*
497284584b0Sjason * Grab boot path from PROM
498284584b0Sjason */
499284584b0Sjason chosen = OF_finddevice("/chosen");
500284584b0Sjason OF_getprop(chosen, "bootpath", buf, sizeof(buf));
501284584b0Sjason cp = buf;
502284584b0Sjason while (cp != NULL && *cp == '/') {
503284584b0Sjason /* Step over '/' */
504284584b0Sjason ++cp;
505284584b0Sjason /* Extract name */
506284584b0Sjason pp = bp->name;
507284584b0Sjason while (*cp != '@' && *cp != '/' && *cp != '\0')
508284584b0Sjason *pp++ = *cp++;
509284584b0Sjason *pp = '\0';
510284584b0Sjason if (*cp == '@') {
511284584b0Sjason cp = str2hex(++cp, &bp->val[0]);
512284584b0Sjason if (*cp == ',')
513284584b0Sjason cp = str2hex(++cp, &bp->val[1]);
514a59e3f8dSmiod if (*cp == ':') {
515a59e3f8dSmiod /*
516a59e3f8dSmiod * We only store one character here, as we will
517a59e3f8dSmiod * only use this field to compute a partition
518a59e3f8dSmiod * index for block devices. However, it might
519a59e3f8dSmiod * be an ethernet media specification, so be
520a59e3f8dSmiod * sure to skip all letters.
521a59e3f8dSmiod */
522a59e3f8dSmiod bp->val[2] = *++cp - 'a';
523a59e3f8dSmiod while (*cp != '\0' && *cp != '/')
524a59e3f8dSmiod cp++;
525a59e3f8dSmiod }
526284584b0Sjason } else {
527284584b0Sjason bp->val[0] = -1; /* no #'s: assume unit 0, no
5288243e839Sjmc sbus offset/address */
529284584b0Sjason }
530284584b0Sjason ++bp;
531284584b0Sjason ++nbootpath;
532284584b0Sjason }
533284584b0Sjason bp->name[0] = 0;
534284584b0Sjason
535fb1ca35cSkettenis bootpath_nodes(bootpath, nbootpath);
536284584b0Sjason
537284584b0Sjason /* Setup pointer to boot flags */
538284584b0Sjason OF_getprop(chosen, "bootargs", buf, sizeof(buf));
539284584b0Sjason cp = buf;
540284584b0Sjason
541284584b0Sjason /* Find start of boot flags */
542284584b0Sjason while (*cp) {
543284584b0Sjason while(*cp == ' ' || *cp == '\t') cp++;
544284584b0Sjason if (*cp == '-' || *cp == '\0')
545284584b0Sjason break;
546284584b0Sjason while(*cp != ' ' && *cp != '\t' && *cp != '\0') cp++;
547284584b0Sjason
548284584b0Sjason }
549284584b0Sjason if (*cp != '-')
550284584b0Sjason return;
551284584b0Sjason
552284584b0Sjason for (;*++cp;) {
553284584b0Sjason int fl;
554284584b0Sjason
555284584b0Sjason fl = 0;
556284584b0Sjason switch(*cp) {
557284584b0Sjason case 'a':
558284584b0Sjason fl |= RB_ASKNAME;
559284584b0Sjason break;
560284584b0Sjason case 'b':
561284584b0Sjason fl |= RB_HALT;
562284584b0Sjason break;
563284584b0Sjason case 'c':
564284584b0Sjason fl |= RB_CONFIG;
565284584b0Sjason break;
566284584b0Sjason case 'd':
567284584b0Sjason fl |= RB_KDB;
568284584b0Sjason break;
569284584b0Sjason case 's':
570284584b0Sjason fl |= RB_SINGLE;
571284584b0Sjason break;
572284584b0Sjason default:
573284584b0Sjason break;
574284584b0Sjason }
575284584b0Sjason if (!fl) {
576284584b0Sjason printf("unknown option `%c'\n", *cp);
577284584b0Sjason continue;
578284584b0Sjason }
579284584b0Sjason boothowto |= fl;
580284584b0Sjason
581284584b0Sjason /* specialties */
582284584b0Sjason if (*cp == 'd') {
583baf89de9Skettenis #if defined(DDB)
584e97088d6Smpi db_enter();
585284584b0Sjason #else
586284584b0Sjason printf("kernel has no debugger\n");
587284584b0Sjason #endif
588284584b0Sjason }
589284584b0Sjason }
590284584b0Sjason }
591284584b0Sjason
592284584b0Sjason /*
593284584b0Sjason * print out the bootpath
594284584b0Sjason * the %x isn't 0x%x because the Sun EPROMs do it this way, and
595284584b0Sjason * consistency with the EPROMs is probably better here.
596284584b0Sjason */
597284584b0Sjason
598284584b0Sjason static void
bootpath_print(struct bootpath * bp)599ba134ca3Sstsp bootpath_print(struct bootpath *bp)
600284584b0Sjason {
601284584b0Sjason printf("bootpath: ");
602284584b0Sjason while (bp->name[0]) {
603284584b0Sjason if (bp->val[0] == -1)
6041b84c71fSkettenis printf("/%s%lx", bp->name, bp->val[1]);
605284584b0Sjason else
606c5632f19Sjason printf("/%s@%lx,%lx", bp->name, bp->val[0], bp->val[1]);
607284584b0Sjason if (bp->val[2] != 0)
6081b84c71fSkettenis printf(":%c", (int)bp->val[2] + 'a');
609284584b0Sjason bp++;
610284584b0Sjason }
611284584b0Sjason printf("\n");
612284584b0Sjason }
613284584b0Sjason
614284584b0Sjason
615284584b0Sjason /*
616284584b0Sjason * save or read a bootpath pointer from the boothpath store.
617284584b0Sjason *
618284584b0Sjason * XXX. required because of SCSI... we don't have control over the "sd"
619284584b0Sjason * device, so we can't set boot device there. we patch in with
620e5fd22c3Smiod * device_register(), and use this to recover the bootpath.
621284584b0Sjason */
622284584b0Sjason struct bootpath *
bootpath_store(int storep,struct bootpath * bp)623ba134ca3Sstsp bootpath_store(int storep, struct bootpath *bp)
624284584b0Sjason {
625284584b0Sjason static struct bootpath *save;
626284584b0Sjason struct bootpath *retval;
627284584b0Sjason
628284584b0Sjason retval = save;
629284584b0Sjason if (storep)
630284584b0Sjason save = bp;
631284584b0Sjason
632284584b0Sjason return (retval);
633284584b0Sjason }
634284584b0Sjason
635284584b0Sjason /*
636284584b0Sjason * Determine mass storage and memory configuration for a machine.
637284584b0Sjason * We get the PROM's root device and make sure we understand it, then
638f75609fcSmiod * attach it as `mainbus0'.
639284584b0Sjason */
640284584b0Sjason void
cpu_configure(void)6410aac5001Snaddy cpu_configure(void)
642284584b0Sjason {
643e4edc0c7Skettenis #ifdef SUN4V
644465290deSkettenis int pause = 0;
645465290deSkettenis
646465290deSkettenis if (CPU_ISSUN4V) {
647465290deSkettenis const char *prop;
648465290deSkettenis size_t len;
649465290deSkettenis int idx;
650465290deSkettenis
651e4edc0c7Skettenis mdesc_init();
652465290deSkettenis idx = mdesc_find_node("cpu");
653465290deSkettenis prop = mdesc_get_prop_data(idx, "hwcap-list", &len);
654465290deSkettenis if (prop) {
655465290deSkettenis while (len > 0) {
656465290deSkettenis if (strcmp(prop, "pause") == 0)
657465290deSkettenis pause = 1;
658465290deSkettenis len -= strlen(prop) + 1;
659465290deSkettenis prop += strlen(prop) + 1;
660465290deSkettenis }
661465290deSkettenis }
662465290deSkettenis }
663465290deSkettenis
664465290deSkettenis if (pause) {
665465290deSkettenis struct sun4v_patch {
666465290deSkettenis u_int32_t addr;
667465290deSkettenis u_int32_t insn;
668465290deSkettenis } *p;
669465290deSkettenis paddr_t pa;
670465290deSkettenis
671465290deSkettenis extern struct sun4v_patch sun4v_pause_patch;
672465290deSkettenis extern struct sun4v_patch sun4v_pause_patch_end;
673465290deSkettenis
674465290deSkettenis /*
675465290deSkettenis * Use physical addresses to patch since kernel .text
676465290deSkettenis * is already mapped read-only at this point.
677465290deSkettenis */
678465290deSkettenis for (p = &sun4v_pause_patch; p < &sun4v_pause_patch_end; p++) {
679465290deSkettenis pmap_extract(pmap_kernel(), (vaddr_t)p->addr, &pa);
680465290deSkettenis stwa(pa, ASI_PHYS_NON_CACHED, p->insn);
681465290deSkettenis flush((void *)(vaddr_t)p->addr);
682465290deSkettenis }
683465290deSkettenis }
684e4edc0c7Skettenis #endif
685e4edc0c7Skettenis
686237fd37fSstsp if (obd.version == BOOTDATA_VERSION &&
687e653d891Skn obd.len >= BOOTDATA_LEN_BOOTHOWTO) {
688237fd37fSstsp #if NSOFTRAID > 0
689237fd37fSstsp memcpy(sr_bootuuid.sui_id, obd.sr_uuid,
690237fd37fSstsp sizeof(sr_bootuuid.sui_id));
691237fd37fSstsp memcpy(sr_bootkey, obd.sr_maskkey, sizeof(sr_bootkey));
692237fd37fSstsp #endif
693237fd37fSstsp explicit_bzero(obd.sr_maskkey, sizeof(obd.sr_maskkey));
694237fd37fSstsp }
695237fd37fSstsp
696284584b0Sjason /* build the bootpath */
697284584b0Sjason bootpath_build();
698284584b0Sjason
69925b7217fSjason if (boothowto & RB_CONFIG) {
70025b7217fSjason #ifdef BOOT_CONFIG
70125b7217fSjason user_config();
70225b7217fSjason #else
70325b7217fSjason printf("kernel does not support -c; continuing..\n");
70425b7217fSjason #endif
70525b7217fSjason }
70625b7217fSjason
707284584b0Sjason /* block clock interrupts and anything below */
708284584b0Sjason splclock();
709284584b0Sjason /* Enable device interrupts */
710284584b0Sjason setpstate(getpstate()|PSTATE_IE);
711284584b0Sjason
712284584b0Sjason if (config_rootfound("mainbus", NULL) == NULL)
713284584b0Sjason panic("mainbus not configured");
714284584b0Sjason
715284584b0Sjason /* Enable device interrupts */
716284584b0Sjason setpstate(getpstate()|PSTATE_IE);
717284584b0Sjason
718284584b0Sjason (void)spl0();
719e01d3f6aSart cold = 0;
7200ddf3f06Skettenis
7210ddf3f06Skettenis #ifdef SUN4V
7220ddf3f06Skettenis if (CPU_ISSUN4V)
7230ddf3f06Skettenis sun4v_set_soft_state(SIS_NORMAL, sun4v_soft_state_running);
7240ddf3f06Skettenis #endif
725e01d3f6aSart }
726e01d3f6aSart
7270ddf3f06Skettenis #ifdef SUN4V
7280ddf3f06Skettenis
72901555c0fSkettenis #define HSVC_GROUP_INTERRUPT 0x002
7300ddf3f06Skettenis #define HSVC_GROUP_SOFT_STATE 0x003
731090b5ccfSkettenis #define HSVC_GROUP_SDIO 0x108
7320ddf3f06Skettenis
7330ddf3f06Skettenis int sun4v_soft_state_initialized = 0;
7340ddf3f06Skettenis
7350ddf3f06Skettenis void
sun4v_soft_state_init(void)7360ddf3f06Skettenis sun4v_soft_state_init(void)
7370ddf3f06Skettenis {
7380ddf3f06Skettenis uint64_t minor;
7390ddf3f06Skettenis
7400ddf3f06Skettenis if (prom_set_sun4v_api_version(HSVC_GROUP_SOFT_STATE, 1, 0, &minor))
7410ddf3f06Skettenis return;
7420ddf3f06Skettenis
7430ddf3f06Skettenis prom_sun4v_soft_state_supported();
7440ddf3f06Skettenis sun4v_soft_state_initialized = 1;
7450ddf3f06Skettenis }
7460ddf3f06Skettenis
7470ddf3f06Skettenis void
sun4v_set_soft_state(int state,const char * desc)7480ddf3f06Skettenis sun4v_set_soft_state(int state, const char *desc)
7490ddf3f06Skettenis {
7500ddf3f06Skettenis paddr_t pa;
7510ddf3f06Skettenis int err;
7520ddf3f06Skettenis
7530ddf3f06Skettenis if (!sun4v_soft_state_initialized)
7540ddf3f06Skettenis return;
7550ddf3f06Skettenis
7560ddf3f06Skettenis if (!pmap_extract(pmap_kernel(), (vaddr_t)desc, &pa))
757cf04bd29Skrw panic("sun4v_set_soft_state: pmap_extract failed");
7580ddf3f06Skettenis
7590ddf3f06Skettenis err = hv_soft_state_set(state, pa);
7600ddf3f06Skettenis if (err != H_EOK)
7610ddf3f06Skettenis printf("soft_state_set: %d\n", err);
7620ddf3f06Skettenis }
76301555c0fSkettenis
76401555c0fSkettenis void
sun4v_interrupt_init(void)76501555c0fSkettenis sun4v_interrupt_init(void)
76601555c0fSkettenis {
76701555c0fSkettenis uint64_t minor;
76801555c0fSkettenis
76901555c0fSkettenis if (prom_set_sun4v_api_version(HSVC_GROUP_INTERRUPT, 3, 0, &minor))
77001555c0fSkettenis return;
77101555c0fSkettenis
77201555c0fSkettenis sun4v_group_interrupt_major = 3;
77301555c0fSkettenis }
77401555c0fSkettenis
775090b5ccfSkettenis void
sun4v_sdio_init(void)776090b5ccfSkettenis sun4v_sdio_init(void)
777090b5ccfSkettenis {
778090b5ccfSkettenis uint64_t minor;
779090b5ccfSkettenis
780090b5ccfSkettenis if (prom_set_sun4v_api_version(HSVC_GROUP_SDIO, 1, 0, &minor))
781090b5ccfSkettenis return;
782090b5ccfSkettenis
783090b5ccfSkettenis sun4v_group_sdio_major = 1;
784090b5ccfSkettenis }
785090b5ccfSkettenis
7860ddf3f06Skettenis #endif
7870ddf3f06Skettenis
788e01d3f6aSart void
diskconf(void)789e01d3f6aSart diskconf(void)
790e01d3f6aSart {
79125b7217fSjason struct bootpath *bp;
7927dc861caSderaadt struct device *bootdv;
7937dc861caSderaadt
7947dc861caSderaadt bootpath_print(bootpath);
795284584b0Sjason
796284584b0Sjason bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
79725b7217fSjason bootdv = (bp == NULL) ? NULL : bp->dev;
798284584b0Sjason
79957949900Sdlg #if NMPATH > 0
80057949900Sdlg if (bootdv != NULL)
80157949900Sdlg bootdv = mpath_bootdv(bootdv);
80257949900Sdlg #endif
80357949900Sdlg
8047dc861caSderaadt setroot(bootdv, bp->val[2], RB_USERREQ | RB_HALT);
8057dc861caSderaadt dumpconf();
80625b7217fSjason }
807284584b0Sjason
808284584b0Sjason char *
clockfreq(long freq)809ba134ca3Sstsp clockfreq(long freq)
810284584b0Sjason {
811284584b0Sjason char *p;
812284584b0Sjason static char buf[10];
813284584b0Sjason
814284584b0Sjason freq /= 1000;
8152a108914Sho snprintf(buf, sizeof buf, "%ld", freq / 1000);
816284584b0Sjason freq %= 1000;
817284584b0Sjason if (freq) {
818284584b0Sjason freq += 1000; /* now in 1000..1999 */
819284584b0Sjason p = buf + strlen(buf);
8202a108914Sho snprintf(p, buf + sizeof buf - p, "%ld", freq);
821284584b0Sjason *p = '.'; /* now buf = %d.%3d */
822284584b0Sjason }
823284584b0Sjason return (buf);
824284584b0Sjason }
825284584b0Sjason
826284584b0Sjason static int
mbprint(void * aux,const char * name)827ba134ca3Sstsp mbprint(void *aux, const char *name)
828284584b0Sjason {
829284584b0Sjason struct mainbus_attach_args *ma = aux;
830284584b0Sjason
831284584b0Sjason if (name)
8321b7dfce2Skettenis printf("\"%s\" at %s", ma->ma_name, name);
833284584b0Sjason if (ma->ma_address)
834284584b0Sjason printf(" addr 0x%08lx", (u_long)ma->ma_address[0]);
835284584b0Sjason if (ma->ma_pri)
836284584b0Sjason printf(" ipl %d", ma->ma_pri);
837284584b0Sjason return (UNCONF);
838284584b0Sjason }
839284584b0Sjason
840284584b0Sjason int
findroot(void)8410aac5001Snaddy findroot(void)
842284584b0Sjason {
843ba134ca3Sstsp int node;
844284584b0Sjason
845284584b0Sjason if ((node = rootnode) == 0 && (node = OF_peer(0)) == 0)
846284584b0Sjason panic("no PROM root device");
847284584b0Sjason rootnode = node;
848284584b0Sjason return (node);
849284584b0Sjason }
850284584b0Sjason
851284584b0Sjason /*
852284584b0Sjason * Given a `first child' node number, locate the node with the given name.
853284584b0Sjason * Return the node number, or 0 if not found.
854284584b0Sjason */
855284584b0Sjason int
findnode(int first,const char * name)856ba134ca3Sstsp findnode(int first, const char *name)
857284584b0Sjason {
858284584b0Sjason int node;
859284584b0Sjason char buf[32];
860284584b0Sjason
861284584b0Sjason for (node = first; node; node = OF_peer(node)) {
862284584b0Sjason if ((OF_getprop(node, "name", buf, sizeof(buf)) > 0) &&
863284584b0Sjason (strcmp(buf, name) == 0))
864284584b0Sjason return (node);
865284584b0Sjason }
866284584b0Sjason return (0);
867284584b0Sjason }
868284584b0Sjason
869284584b0Sjason int
mainbus_match(struct device * parent,void * cf,void * aux)870ba134ca3Sstsp mainbus_match(struct device *parent, void *cf, void *aux)
871284584b0Sjason {
872284584b0Sjason return (1);
873284584b0Sjason }
874284584b0Sjason
875284584b0Sjason /*
876284584b0Sjason * Attach the mainbus.
877284584b0Sjason *
878c9e42332Smjc * Our main job is to attach the CPU (the root node we got in cpu_configure())
879284584b0Sjason * and iterate down the list of `mainbus devices' (children of that node).
880284584b0Sjason * We also record the `node id' of the default frame buffer, if any.
881284584b0Sjason */
882284584b0Sjason static void
mainbus_attach(struct device * parent,struct device * dev,void * aux)883ba134ca3Sstsp mainbus_attach(struct device *parent, struct device *dev, void *aux)
884284584b0Sjason {
885284584b0Sjason extern struct sparc_bus_dma_tag mainbus_dma_tag;
886eb79e960Shenric extern bus_space_tag_t mainbus_space_tag;
887284584b0Sjason
888284584b0Sjason struct mainbus_attach_args ma;
88925c1a9d6Skettenis char buf[64];
890284584b0Sjason const char *const *ssp, *sp = NULL;
8919079f3edSkettenis int node0, node, rv, len;
892284584b0Sjason
893284584b0Sjason static const char *const openboot_special[] = {
894284584b0Sjason /* ignore these (end with NULL) */
895284584b0Sjason /*
896284584b0Sjason * These are _root_ devices to ignore. Others must be handled
897284584b0Sjason * elsewhere.
898284584b0Sjason */
899284584b0Sjason "virtual-memory",
900284584b0Sjason "aliases",
901284584b0Sjason "memory",
902284584b0Sjason "openprom",
903284584b0Sjason "options",
904284584b0Sjason "packages",
905284584b0Sjason "chosen",
9066f6544cdSmiod "counter-timer",
907284584b0Sjason NULL
908284584b0Sjason };
909284584b0Sjason
91025c1a9d6Skettenis /*
91125c1a9d6Skettenis * Print the "banner-name" property in dmesg. It provides a
91225c1a9d6Skettenis * description of the machine that is generally more
91325c1a9d6Skettenis * informative than the "name" property. However, if the
91425c1a9d6Skettenis * "banner-name" property is missing, fall back on the "name"
91536fd90dcSjsg * property.
91625c1a9d6Skettenis */
91725c1a9d6Skettenis if (OF_getprop(findroot(), "banner-name", buf, sizeof(buf)) > 0 ||
91825c1a9d6Skettenis OF_getprop(findroot(), "name", buf, sizeof(buf)) > 0)
91925c1a9d6Skettenis printf(": %s\n", buf);
92025c1a9d6Skettenis else
92125c1a9d6Skettenis printf("\n");
9228677f810Sgwk
92325c1a9d6Skettenis /*
92425c1a9d6Skettenis * Base the hw.product and hw.vendor strings on the "name"
92525c1a9d6Skettenis * property. They describe the hardware in a much more
92625c1a9d6Skettenis * consistent way than the "banner-property".
92725c1a9d6Skettenis */
92825c1a9d6Skettenis if ((len = OF_getprop(findroot(), "name", buf, sizeof(buf))) > 0) {
92925c1a9d6Skettenis hw_prod = malloc(len, M_DEVBUF, M_NOWAIT);
93025c1a9d6Skettenis if (hw_prod)
93125c1a9d6Skettenis strlcpy(hw_prod, buf, len);
93225c1a9d6Skettenis
93325c1a9d6Skettenis if (strncmp(buf, "SUNW,", 5) == 0)
9348677f810Sgwk hw_vendor = "Sun";
93525c1a9d6Skettenis if (strncmp(buf, "FJSV,", 5) == 0)
93625c1a9d6Skettenis hw_vendor = "Fujitsu";
93725c1a9d6Skettenis if (strncmp(buf, "TAD,", 4) == 0)
93825c1a9d6Skettenis hw_vendor = "Tadpole";
93933be661fSkettenis if (strncmp(buf, "NATE,", 5) == 0)
94033be661fSkettenis hw_vendor = "Naturetech";
941f0aa7c20Sdlg if (strncmp(buf, "ORCL,", 5) == 0)
942f0aa7c20Sdlg hw_vendor = "Oracle";
94325c1a9d6Skettenis
94425c1a9d6Skettenis /*
94525c1a9d6Skettenis * The Momentum Leopard-V advertises itself as
94625c1a9d6Skettenis * SUNW,UltraSPARC-IIi-Engine, but can be
94725c1a9d6Skettenis * distinguished by looking at the "model" property.
94825c1a9d6Skettenis */
94925c1a9d6Skettenis if (OF_getprop(findroot(), "model", buf, sizeof(buf)) > 0 &&
95025c1a9d6Skettenis strncmp(buf, "MOMENTUM,", 9) == 0)
95125c1a9d6Skettenis hw_vendor = "Momentum";
9520833435bSgwk }
953284584b0Sjason
954284584b0Sjason /* Establish the first component of the boot path */
955284584b0Sjason bootpath_store(1, bootpath);
956284584b0Sjason
95704235f00Skettenis /* We configure the CPUs first. */
9588fad7323Skettenis
95904235f00Skettenis node = findroot();
960a42faf19Skettenis for (node0 = OF_child(node); node0; node0 = OF_peer(node0)) {
961a42faf19Skettenis if (OF_getprop(node0, "name", buf, sizeof(buf)) <= 0)
962a42faf19Skettenis continue;
963a42faf19Skettenis }
96404235f00Skettenis
9659079f3edSkettenis for (node = OF_child(node); node; node = OF_peer(node)) {
966fc121a76Skettenis if (!checkstatus(node))
967fc121a76Skettenis continue;
968fc121a76Skettenis
9698fad7323Skettenis /*
9708fad7323Skettenis * UltraSPARC-IV cpus appear as two "cpu" nodes below
9719079f3edSkettenis * a "cmp" node.
9728fad7323Skettenis */
9738fad7323Skettenis if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
9748fad7323Skettenis continue;
97504235f00Skettenis if (strcmp(buf, "cmp") == 0) {
9769079f3edSkettenis bzero(&ma, sizeof(ma));
9779079f3edSkettenis ma.ma_node = node;
9789079f3edSkettenis ma.ma_name = buf;
9799079f3edSkettenis getprop(node, "reg", sizeof(*ma.ma_reg),
9809079f3edSkettenis &ma.ma_nreg, (void **)&ma.ma_reg);
9819079f3edSkettenis config_found(dev, &ma, mbprint);
9829079f3edSkettenis continue;
9838fad7323Skettenis }
9848fad7323Skettenis
98504235f00Skettenis if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
986284584b0Sjason continue;
987284584b0Sjason if (strcmp(buf, "cpu") == 0) {
988284584b0Sjason bzero(&ma, sizeof(ma));
989284584b0Sjason ma.ma_node = node;
990f18899c8Skettenis OF_getprop(node, "name", buf, sizeof(buf));
991f18899c8Skettenis if (strcmp(buf, "cpu") == 0)
992f18899c8Skettenis OF_getprop(node, "compatible", buf, sizeof(buf));
993f18899c8Skettenis ma.ma_name = buf;
994f626355dSkettenis getprop(node, "reg", sizeof(*ma.ma_reg),
995f626355dSkettenis &ma.ma_nreg, (void **)&ma.ma_reg);
996f18899c8Skettenis config_found(dev, &ma, mbprint);
9979079f3edSkettenis continue;
998284584b0Sjason }
999284584b0Sjason }
1000038ea04cSkettenis
1001284584b0Sjason node = findroot(); /* re-init root node */
1002284584b0Sjason
1003284584b0Sjason /* Find the "options" node */
1004284584b0Sjason node0 = OF_child(node);
1005284584b0Sjason optionsnode = findnode(node0, "options");
1006284584b0Sjason if (optionsnode == 0)
1007284584b0Sjason panic("no options in OPENPROM");
1008284584b0Sjason
1009a42faf19Skettenis for (node0 = OF_child(node); node0; node0 = OF_peer(node0)) {
1010a42faf19Skettenis if (OF_getprop(node0, "name", buf, sizeof(buf)) <= 0)
1011a42faf19Skettenis continue;
1012a42faf19Skettenis }
1013a42faf19Skettenis
1014284584b0Sjason /*
1015284584b0Sjason * Configure the devices, in PROM order. Skip
1016284584b0Sjason * PROM entries that are not for devices, or which must be
1017284584b0Sjason * done before we get here.
1018284584b0Sjason */
1019a42faf19Skettenis for (node = OF_child(node); node; node = OF_peer(node)) {
1020284584b0Sjason int portid;
1021284584b0Sjason
1022284584b0Sjason DPRINTF(ACDB_PROBE, ("Node: %x", node));
1023f18899c8Skettenis if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 &&
1024284584b0Sjason strcmp(buf, "cpu") == 0)
1025284584b0Sjason continue;
10269079f3edSkettenis if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
10279079f3edSkettenis strcmp(buf, "cmp") == 0)
10289079f3edSkettenis continue;
1029284584b0Sjason DPRINTF(ACDB_PROBE, (" name %s\n", buf));
1030284584b0Sjason for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
1031284584b0Sjason if (strcmp(buf, sp) == 0)
1032284584b0Sjason break;
1033284584b0Sjason if (sp != NULL)
1034284584b0Sjason continue; /* an "early" device already configured */
1035284584b0Sjason
10365adfdce9Skettenis if (!checkstatus(node))
10375adfdce9Skettenis continue;
10385adfdce9Skettenis
1039284584b0Sjason bzero(&ma, sizeof ma);
1040eb79e960Shenric ma.ma_bustag = mainbus_space_tag;
1041284584b0Sjason ma.ma_dmatag = &mainbus_dma_tag;
1042284584b0Sjason ma.ma_name = buf;
1043284584b0Sjason ma.ma_node = node;
1044284584b0Sjason if (OF_getprop(node, "upa-portid", &portid, sizeof(portid)) !=
1045774c92c2Sjason sizeof(portid)) {
1046774c92c2Sjason if (OF_getprop(node, "portid", &portid,
1047774c92c2Sjason sizeof(portid)) != sizeof(portid))
1048284584b0Sjason portid = -1;
1049774c92c2Sjason }
1050284584b0Sjason ma.ma_upaid = portid;
1051284584b0Sjason
1052284584b0Sjason if (getprop(node, "reg", sizeof(*ma.ma_reg),
1053284584b0Sjason &ma.ma_nreg, (void **)&ma.ma_reg) != 0)
1054284584b0Sjason continue;
1055284584b0Sjason #ifdef DEBUG
1056284584b0Sjason if (autoconf_debug & ACDB_PROBE) {
1057284584b0Sjason if (ma.ma_nreg)
1058284584b0Sjason printf(" reg %08lx.%08lx\n",
1059284584b0Sjason (long)ma.ma_reg->ur_paddr,
1060284584b0Sjason (long)ma.ma_reg->ur_len);
1061284584b0Sjason else
1062284584b0Sjason printf(" no reg\n");
1063284584b0Sjason }
1064284584b0Sjason #endif
1065284584b0Sjason rv = getprop(node, "interrupts", sizeof(*ma.ma_interrupts),
1066284584b0Sjason &ma.ma_ninterrupts, (void **)&ma.ma_interrupts);
1067284584b0Sjason if (rv != 0 && rv != ENOENT) {
1068f8e6c425Stedu free(ma.ma_reg, M_DEVBUF, 0);
1069284584b0Sjason continue;
1070284584b0Sjason }
1071284584b0Sjason #ifdef DEBUG
1072284584b0Sjason if (autoconf_debug & ACDB_PROBE) {
1073284584b0Sjason if (ma.ma_interrupts)
1074284584b0Sjason printf(" interrupts %08x\n",
1075284584b0Sjason *ma.ma_interrupts);
1076284584b0Sjason else
1077284584b0Sjason printf(" no interrupts\n");
1078284584b0Sjason }
1079284584b0Sjason #endif
1080284584b0Sjason rv = getprop(node, "address", sizeof(*ma.ma_address),
1081284584b0Sjason &ma.ma_naddress, (void **)&ma.ma_address);
1082284584b0Sjason if (rv != 0 && rv != ENOENT) {
1083f8e6c425Stedu free(ma.ma_reg, M_DEVBUF, 0);
1084f8e6c425Stedu free(ma.ma_interrupts, M_DEVBUF, 0);
1085284584b0Sjason continue;
1086284584b0Sjason }
1087284584b0Sjason #ifdef DEBUG
1088284584b0Sjason if (autoconf_debug & ACDB_PROBE) {
1089284584b0Sjason if (ma.ma_naddress)
1090284584b0Sjason printf(" address %08x\n",
1091284584b0Sjason *ma.ma_address);
1092284584b0Sjason else
1093284584b0Sjason printf(" no address\n");
1094284584b0Sjason }
1095284584b0Sjason #endif
1096f18899c8Skettenis config_found(dev, &ma, mbprint);
1097f8e6c425Stedu free(ma.ma_reg, M_DEVBUF, 0);
1098f8e6c425Stedu free(ma.ma_interrupts, M_DEVBUF, 0);
1099f8e6c425Stedu free(ma.ma_address, M_DEVBUF, 0);
1100284584b0Sjason }
1101adb3c397Skettenis
1102adb3c397Skettenis extern int prom_cngetc(dev_t);
1103adb3c397Skettenis
1104adb3c397Skettenis /* Attach PROM console if no other console attached. */
1105adb3c397Skettenis if (cn_tab->cn_getc == prom_cngetc) {
1106284584b0Sjason bzero(&ma, sizeof ma);
1107284584b0Sjason ma.ma_name = "pcons";
1108f18899c8Skettenis config_found(dev, &ma, mbprint);
1109adb3c397Skettenis }
111062ab431fSkettenis
111162ab431fSkettenis extern todr_chip_handle_t todr_handle;
111262ab431fSkettenis
111362ab431fSkettenis if (todr_handle == NULL) {
111462ab431fSkettenis bzero(&ma, sizeof ma);
111562ab431fSkettenis ma.ma_name = "prtc";
111662ab431fSkettenis config_found(dev, &ma, mbprint);
111762ab431fSkettenis }
1118284584b0Sjason }
1119284584b0Sjason
1120eb7eaf8dSmpi const struct cfattach mainbus_ca = {
1121284584b0Sjason sizeof(struct device), mainbus_match, mainbus_attach
1122284584b0Sjason };
1123284584b0Sjason
1124284584b0Sjason int
getprop(int node,char * name,size_t size,int * nitem,void ** bufp)1125ba134ca3Sstsp getprop(int node, char *name, size_t size, int *nitem, void **bufp)
1126284584b0Sjason {
1127284584b0Sjason void *buf;
1128284584b0Sjason long len;
1129284584b0Sjason
1130284584b0Sjason *nitem = 0;
1131284584b0Sjason len = getproplen(node, name);
1132284584b0Sjason if (len <= 0)
1133284584b0Sjason return (ENOENT);
1134284584b0Sjason
1135284584b0Sjason if ((len % size) != 0)
1136284584b0Sjason return (EINVAL);
1137284584b0Sjason
1138284584b0Sjason buf = *bufp;
1139284584b0Sjason if (buf == NULL) {
1140284584b0Sjason /* No storage provided, so we allocate some */
114183d5679cSderaadt buf = malloc(len + 1, M_DEVBUF, M_NOWAIT);
1142284584b0Sjason if (buf == NULL)
1143284584b0Sjason return (ENOMEM);
1144284584b0Sjason }
1145284584b0Sjason
1146284584b0Sjason OF_getprop(node, name, buf, len);
1147284584b0Sjason *bufp = buf;
1148284584b0Sjason *nitem = len / size;
1149284584b0Sjason return (0);
1150284584b0Sjason }
1151284584b0Sjason
1152284584b0Sjason
1153284584b0Sjason /*
1154284584b0Sjason * Internal form of proplen(). Returns the property length.
1155284584b0Sjason */
1156284584b0Sjason long
getproplen(int node,char * name)1157ba134ca3Sstsp getproplen(int node, char *name)
1158284584b0Sjason {
1159284584b0Sjason return (OF_getproplen(node, name));
1160284584b0Sjason }
1161284584b0Sjason
1162284584b0Sjason /*
1163284584b0Sjason * Return a string property. There is a (small) limit on the length;
1164284584b0Sjason * the string is fetched into a static buffer which is overwritten on
1165284584b0Sjason * subsequent calls.
1166284584b0Sjason */
1167284584b0Sjason char *
getpropstring(int node,char * name)1168ba134ca3Sstsp getpropstring(int node, char *name)
1169284584b0Sjason {
1170284584b0Sjason static char stringbuf[32];
1171284584b0Sjason
1172284584b0Sjason return (getpropstringA(node, name, stringbuf));
1173284584b0Sjason }
1174284584b0Sjason
1175284584b0Sjason /* Alternative getpropstring(), where caller provides the buffer */
1176284584b0Sjason char *
getpropstringA(int node,char * name,char * buffer)1177ba134ca3Sstsp getpropstringA(int node, char *name, char *buffer)
1178284584b0Sjason {
1179284584b0Sjason int blen;
1180284584b0Sjason
1181284584b0Sjason if (getprop(node, name, 1, &blen, (void **)&buffer) != 0)
1182284584b0Sjason blen = 0;
1183284584b0Sjason
1184284584b0Sjason buffer[blen] = '\0'; /* usually unnecessary */
1185284584b0Sjason return (buffer);
1186284584b0Sjason }
1187284584b0Sjason
1188284584b0Sjason /*
1189284584b0Sjason * Fetch an integer (or pointer) property.
1190284584b0Sjason * The return value is the property, or the default if there was none.
1191284584b0Sjason */
1192284584b0Sjason int
getpropint(int node,char * name,int deflt)1193ba134ca3Sstsp getpropint(int node, char *name, int deflt)
1194284584b0Sjason {
1195284584b0Sjason int intbuf;
1196284584b0Sjason
1197284584b0Sjason if (OF_getprop(node, name, &intbuf, sizeof(intbuf)) != sizeof(intbuf))
1198284584b0Sjason return (deflt);
1199284584b0Sjason
1200284584b0Sjason return (intbuf);
1201284584b0Sjason }
1202284584b0Sjason
1203fa65087eSkettenis int
getpropspeed(int node,char * name)1204ba134ca3Sstsp getpropspeed(int node, char *name)
1205fa65087eSkettenis {
1206fa65087eSkettenis char buf[128];
1207fa65087eSkettenis int i, speed = 0;
1208fa65087eSkettenis
1209fa65087eSkettenis if (OF_getprop(node, name, buf, sizeof(buf)) != -1) {
1210fa65087eSkettenis for (i = 0; i < sizeof(buf); i++) {
1211fa65087eSkettenis if (buf[i] < '0' || buf[i] > '9')
1212fa65087eSkettenis break;
1213fa65087eSkettenis speed *= 10;
1214fa65087eSkettenis speed += buf[i] - '0';
1215fa65087eSkettenis }
1216fa65087eSkettenis }
1217fa65087eSkettenis
1218fa65087eSkettenis if (speed == 0)
1219fa65087eSkettenis speed = 9600;
1220fa65087eSkettenis
1221fa65087eSkettenis return (speed);
1222fa65087eSkettenis }
1223fa65087eSkettenis
1224284584b0Sjason /*
1225284584b0Sjason * OPENPROM functions. These are here mainly to hide the OPENPROM interface
1226284584b0Sjason * from the rest of the kernel.
1227284584b0Sjason */
1228284584b0Sjason int
firstchild(int node)1229ba134ca3Sstsp firstchild(int node)
1230284584b0Sjason {
1231284584b0Sjason
1232284584b0Sjason return OF_child(node);
1233284584b0Sjason }
1234284584b0Sjason
1235284584b0Sjason int
nextsibling(int node)1236ba134ca3Sstsp nextsibling(int node)
1237284584b0Sjason {
1238284584b0Sjason
1239284584b0Sjason return OF_peer(node);
1240284584b0Sjason }
1241284584b0Sjason
12425adfdce9Skettenis int
checkstatus(int node)12435adfdce9Skettenis checkstatus(int node)
12445adfdce9Skettenis {
12455adfdce9Skettenis char buf[32];
12465adfdce9Skettenis
12475adfdce9Skettenis /* If there is no "status" property, assume everything is fine. */
12485adfdce9Skettenis if (OF_getprop(node, "status", buf, sizeof(buf)) <= 0)
12495adfdce9Skettenis return 1;
12505adfdce9Skettenis
12515adfdce9Skettenis /*
12525adfdce9Skettenis * If OpenBoot Diagnostics discovers a problem with a device
12535adfdce9Skettenis * it will mark it with "fail" or "fail-xxx", where "xxx" is
12545adfdce9Skettenis * additional human-readable information about the particular
12555adfdce9Skettenis * fault-condition.
12565adfdce9Skettenis */
12575adfdce9Skettenis if (strcmp(buf, "disabled") == 0 || strncmp(buf, "fail", 4) == 0)
12585adfdce9Skettenis return 0;
12595adfdce9Skettenis
12605adfdce9Skettenis return 1;
12615adfdce9Skettenis }
1262284584b0Sjason
1263ba134ca3Sstsp /* returns 1 if node has given property */
1264284584b0Sjason int
node_has_property(int node,const char * prop)1265ba134ca3Sstsp node_has_property(int node, const char *prop)
1266284584b0Sjason {
1267284584b0Sjason return (OF_getproplen(node, (caddr_t)prop) != -1);
1268284584b0Sjason }
1269284584b0Sjason
1270284584b0Sjason /*
1271284584b0Sjason * Try to figure out where the PROM stores the cursor row & column
1272284584b0Sjason * variables. Returns nonzero on error.
1273284584b0Sjason */
1274284584b0Sjason int
romgetcursoraddr(int ** rowp,int ** colp)1275ba134ca3Sstsp romgetcursoraddr(int **rowp, int **colp)
1276284584b0Sjason {
127788ee6abdSmiod cell_t row = 0, col = 0;
1278965e62f5Sjason
1279965e62f5Sjason OF_interpret("stdout @ is my-self addr line# addr column# ",
1280965e62f5Sjason 2, &col, &row);
1281284584b0Sjason
1282284584b0Sjason /*
1283f75609fcSmiod * We are running on a 64-bit big-endian machine, so these things
1284f75609fcSmiod * point to 64-bit big-endian values. To convert them to pointers
1285f75609fcSmiod * to int, add 4 to the address.
1286284584b0Sjason */
128788ee6abdSmiod if (row == 0 || col == 0)
1288965e62f5Sjason return (-1);
1289965e62f5Sjason *rowp = (int *)(row + 4);
1290965e62f5Sjason *colp = (int *)(col + 4);
1291965e62f5Sjason return (0);
1292284584b0Sjason }
1293284584b0Sjason
1294284584b0Sjason void
callrom(void)12950aac5001Snaddy callrom(void)
1296284584b0Sjason {
1297284584b0Sjason
12982df76cc2Sguenther __asm volatile("wrpr %%g0, 0, %%tl" : );
1299284584b0Sjason OF_enter();
1300284584b0Sjason }
1301284584b0Sjason
1302284584b0Sjason /*
1303284584b0Sjason * find a device matching "name" and unit number
1304284584b0Sjason */
1305284584b0Sjason struct device *
getdevunit(const char * name,int unit)1306*6dfc32acSmiod getdevunit(const char *name, int unit)
1307284584b0Sjason {
13085cf5f4a3Smiod struct device *dev = TAILQ_FIRST(&alldevs);
1309284584b0Sjason char num[10], fullname[16];
1310284584b0Sjason int lunit;
1311284584b0Sjason
1312284584b0Sjason /* compute length of name and decimal expansion of unit number */
13132a108914Sho snprintf(num, sizeof num, "%d", unit);
1314284584b0Sjason lunit = strlen(num);
1315284584b0Sjason if (strlen(name) + lunit >= sizeof(fullname) - 1)
1316284584b0Sjason panic("config_attach: device name too long");
1317284584b0Sjason
13182a108914Sho strlcpy(fullname, name, sizeof fullname);
13192a108914Sho strlcat(fullname, num, sizeof fullname);
1320284584b0Sjason
1321284584b0Sjason while (strcmp(dev->dv_xname, fullname) != 0) {
13225cf5f4a3Smiod if ((dev = TAILQ_NEXT(dev, dv_list)) == NULL)
1323284584b0Sjason return NULL;
1324284584b0Sjason }
1325284584b0Sjason return dev;
1326284584b0Sjason }
13270300c697Sjason
13280300c697Sjason void
device_register(struct device * dev,void * aux)1329fb1ca35cSkettenis device_register(struct device *dev, void *aux)
13300300c697Sjason {
1331fb1ca35cSkettenis struct mainbus_attach_args *ma = aux;
1332fb1ca35cSkettenis struct pci_attach_args *pa = aux;
1333fb1ca35cSkettenis struct sbus_attach_args *sa = aux;
1334b57f54d2Skettenis struct vbus_attach_args *va = aux;
1335b57f54d2Skettenis struct cbus_attach_args *ca = aux;
13360300c697Sjason struct bootpath *bp = bootpath_store(0, NULL);
1337fb1ca35cSkettenis struct device *busdev = dev->dv_parent;
1338fb1ca35cSkettenis const char *devname = dev->dv_cfdata->cf_driver->cd_name;
1339fb1ca35cSkettenis const char *busname;
1340fb1ca35cSkettenis int node = -1;
13410300c697Sjason
13420300c697Sjason /*
1343fb1ca35cSkettenis * There is no point in continuing if we've exhausted all
1344fb1ca35cSkettenis * bootpath components.
13450300c697Sjason */
13460300c697Sjason if (bp == NULL)
13470300c697Sjason return;
13480300c697Sjason
13490300c697Sjason DPRINTF(ACDB_BOOTDEV,
1350fb1ca35cSkettenis ("\n%s: device_register: devname %s(%s) component %s\n",
1351fb1ca35cSkettenis dev->dv_xname, devname, dev->dv_xname, bp->name));
13520300c697Sjason
1353fb1ca35cSkettenis /*
1354fb1ca35cSkettenis * Ignore mainbus0 itself, it certainly is not a boot device.
1355fb1ca35cSkettenis */
1356fb1ca35cSkettenis if (busdev == NULL)
13570300c697Sjason return;
13580300c697Sjason
13590300c697Sjason /*
1360fb1ca35cSkettenis * We don't know the type of 'aux'; it depends on the bus this
1361fb1ca35cSkettenis * device attaches to. We are only interested in certain bus
1362fb1ca35cSkettenis * types; this is only used to find the boot device.
13630300c697Sjason */
1364fb1ca35cSkettenis busname = busdev->dv_cfdata->cf_driver->cd_name;
13656e697324Skettenis if (strcmp(busname, "mainbus") == 0 ||
13666e697324Skettenis strcmp(busname, "ssm") == 0 || strcmp(busname, "upa") == 0)
1367fb1ca35cSkettenis node = ma->ma_node;
1368e8dd11dfSkettenis else if (strcmp(busname, "sbus") == 0 ||
1369e8dd11dfSkettenis strcmp(busname, "dma") == 0 || strcmp(busname, "ledma") == 0)
1370e8dd11dfSkettenis node = sa->sa_node;
1371b57f54d2Skettenis else if (strcmp(busname, "vbus") == 0)
1372b57f54d2Skettenis node = va->va_node;
1373b57f54d2Skettenis else if (strcmp(busname, "cbus") == 0)
1374b57f54d2Skettenis node = ca->ca_node;
1375fb1ca35cSkettenis else if (strcmp(busname, "pci") == 0)
1376fb1ca35cSkettenis node = PCITAG_NODE(pa->pa_tag);
1377fb1ca35cSkettenis
1378fb1ca35cSkettenis if (node == bootnode) {
13794ca9d95fSkettenis if (strcmp(devname, "vdsk") == 0) {
13804ca9d95fSkettenis /*
13814ca9d95fSkettenis * For virtual disks, don't nail the boot
13824ca9d95fSkettenis * device just yet. Instead, we add fake a
13834ca9d95fSkettenis * SCSI target/lun, such that we match it the
13844ca9d95fSkettenis * next time around.
13854ca9d95fSkettenis */
13864ca9d95fSkettenis bp->dev = dev;
13874ca9d95fSkettenis (bp + 1)->val[0] = 0;
13884ca9d95fSkettenis (bp + 1)->val[1] = 0;
13894ca9d95fSkettenis nbootpath++;
13904ca9d95fSkettenis bootpath_store(1, bp + 1);
13914ca9d95fSkettenis return;
13924ca9d95fSkettenis }
13934ca9d95fSkettenis
13940300c697Sjason nail_bootdev(dev, bp);
13950300c697Sjason return;
13960300c697Sjason }
1397fb1ca35cSkettenis
1398fb1ca35cSkettenis if (node == bp->node) {
1399fb1ca35cSkettenis bp->dev = dev;
1400fb1ca35cSkettenis DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n",
1401fb1ca35cSkettenis bp->name, dev->dv_xname));
1402fb1ca35cSkettenis bootpath_store(1, bp + 1);
1403fb1ca35cSkettenis return;
1404fb1ca35cSkettenis }
1405fb1ca35cSkettenis
1406fb1ca35cSkettenis if (strcmp(devname, "scsibus") == 0) {
1407b446ce28Skettenis /*
1408b446ce28Skettenis * Booting from anything but the first (physical) port
1409b446ce28Skettenis * isn't supported by OBP.
1410b446ce28Skettenis */
1411b446ce28Skettenis if (strcmp(bp->name, "fp") == 0 && bp->val[0] == 0) {
1412fb1ca35cSkettenis DPRINTF(ACDB_BOOTDEV, ("\t-- matched component %s to %s\n",
1413fb1ca35cSkettenis bp->name, dev->dv_xname));
1414c5632f19Sjason bootpath_store(1, bp + 1);
1415c5632f19Sjason return;
1416c5632f19Sjason }
1417fb1ca35cSkettenis }
1418fb1ca35cSkettenis
141957949900Sdlg if (strcmp(busname, "scsibus") == 0) {
14200300c697Sjason /*
14210300c697Sjason * A SCSI disk or cd; retrieve target/lun information
14220300c697Sjason * from parent and match with current bootpath component.
14230300c697Sjason * Note that we also have look back past the `scsibus'
14240300c697Sjason * device to determine whether this target is on the
14250300c697Sjason * correct controller in our boot path.
14260300c697Sjason */
1427a0837789Sdlg struct scsi_attach_args *sa = aux;
14280300c697Sjason struct scsi_link *sl = sa->sa_sc_link;
14290300c697Sjason u_int target = bp->val[0];
14300300c697Sjason u_int lun = bp->val[1];
14310300c697Sjason
1432c5632f19Sjason if (bp->val[0] & 0xffffffff00000000 && bp->val[0] != -1) {
14332df63a3eSkn /* Hardware RAID or Fibre channel? */
1434fb1ca35cSkettenis if (bp->val[0] == sl->port_wwn && lun == sl->lun) {
1435c5632f19Sjason nail_bootdev(dev, bp);
1436c5632f19Sjason }
143763effabaSjmatthew
143863effabaSjmatthew /*
143963effabaSjmatthew * sata devices on some controllers don't get
144063effabaSjmatthew * port_wwn filled in, so look at devid too.
144163effabaSjmatthew */
144263effabaSjmatthew if (sl->id && sl->id->d_len == 8 &&
144363effabaSjmatthew sl->id->d_type == DEVID_NAA &&
144463effabaSjmatthew memcmp(sl->id + 1, &bp->val[0], 8) == 0)
144563effabaSjmatthew nail_bootdev(dev, bp);
1446c5632f19Sjason return;
1447c5632f19Sjason }
1448c5632f19Sjason
1449fb1ca35cSkettenis /* Check the controller that this scsibus is on. */
1450f25330fcSkrw if ((bp-1)->dev != sl->bus->sc_dev.dv_parent)
14510300c697Sjason return;
14520300c697Sjason
14530300c697Sjason /*
14540300c697Sjason * Bounds check: we know the target and lun widths.
14550300c697Sjason */
14560b29cb40Skrw if (target >= sl->bus->sb_adapter_buswidth ||
14570b29cb40Skrw lun >= sl->bus->sb_luns) {
14580300c697Sjason printf("SCSI disk bootpath component not accepted: "
14590300c697Sjason "target %u; lun %u\n", target, lun);
14600300c697Sjason return;
14610300c697Sjason }
14620300c697Sjason
1463fb1ca35cSkettenis if (target == sl->target && lun == sl->lun) {
14640300c697Sjason nail_bootdev(dev, bp);
14650300c697Sjason return;
14660300c697Sjason }
1467fb1ca35cSkettenis }
1468fb1ca35cSkettenis
1469fb1ca35cSkettenis if (strcmp("wd", devname) == 0) {
14700300c697Sjason /* IDE disks. */
14710300c697Sjason struct ata_atapi_attach *aa = aux;
1472e34882ceSkettenis u_int channel, drive;
14730300c697Sjason
1474e34882ceSkettenis if (strcmp(bp->name, "ata") == 0 &&
1475e34882ceSkettenis bp->val[0] == aa->aa_channel) {
1476e34882ceSkettenis channel = bp->val[0]; bp++;
1477e34882ceSkettenis drive = bp->val[0];
1478e34882ceSkettenis } else {
1479e34882ceSkettenis channel = bp->val[0] / 2;
1480e34882ceSkettenis drive = bp->val[0] % 2;
1481e34882ceSkettenis }
1482e34882ceSkettenis
1483e34882ceSkettenis if (channel == aa->aa_channel &&
1484e34882ceSkettenis drive == aa->aa_drv_data->drive) {
14850300c697Sjason nail_bootdev(dev, bp);
14860300c697Sjason return;
14870300c697Sjason }
14880300c697Sjason }
14890300c697Sjason }
14900300c697Sjason
14910300c697Sjason void
nail_bootdev(struct device * dev,struct bootpath * bp)1492ba134ca3Sstsp nail_bootdev(struct device *dev, struct bootpath *bp)
14930300c697Sjason {
14940300c697Sjason
14950300c697Sjason if (bp->dev != NULL)
14960300c697Sjason panic("device_register: already got a boot device: %s",
14970300c697Sjason bp->dev->dv_xname);
14980300c697Sjason
14990300c697Sjason /*
15000300c697Sjason * Mark this bootpath component by linking it to the matched
15010300c697Sjason * device. We pick up the device pointer in cpu_rootconf().
15020300c697Sjason */
15030300c697Sjason booted_device = bp->dev = dev;
1504fb1ca35cSkettenis DPRINTF(ACDB_BOOTDEV, ("\t-- found bootdevice: %s\n",dev->dv_xname));
15050300c697Sjason
15060300c697Sjason /*
15070300c697Sjason * Then clear the current bootpath component, so we don't spuriously
15080300c697Sjason * match similar instances on other busses, e.g. a disk on
15090300c697Sjason * another SCSI bus with the same target.
15100300c697Sjason */
15110300c697Sjason bootpath_store(1, NULL);
15120300c697Sjason }
15137dc861caSderaadt
15143ad05d8aSmiod const struct nam2blk nam2blk[] = {
15157dc861caSderaadt { "rd", 5 },
151668b8e131Snaddy { "sd", 7 },
1517894da477Stodd { "vnd", 8 },
151868b8e131Snaddy { "wd", 12 },
151968b8e131Snaddy { "fd", 16 },
152068b8e131Snaddy { "cd", 18 },
152132c041f0Sderaadt { NULL, -1 }
15227dc861caSderaadt };
1523