xref: /titanic_52/usr/src/uts/sun4u/serengeti/os/serengeti.c (revision 8c754b1b0941ce71249cc956888b3470525b995f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/time.h>
30 #include <sys/cpuvar.h>
31 #include <sys/dditypes.h>
32 #include <sys/ddipropdefs.h>
33 #include <sys/ddi_impldefs.h>
34 #include <sys/sunddi.h>
35 #include <sys/esunddi.h>
36 #include <sys/sunndi.h>
37 #include <sys/platform_module.h>
38 #include <sys/errno.h>
39 #include <sys/conf.h>
40 #include <sys/modctl.h>
41 #include <sys/promif.h>
42 #include <sys/promimpl.h>
43 #include <sys/prom_plat.h>
44 #include <sys/cmn_err.h>
45 #include <sys/sysmacros.h>
46 #include <sys/mem_cage.h>
47 #include <sys/kobj.h>
48 #include <sys/utsname.h>
49 #include <sys/cpu_sgnblk_defs.h>
50 #include <sys/atomic.h>
51 #include <sys/kdi_impl.h>
52 
53 #include <sys/sgsbbc.h>
54 #include <sys/sgsbbc_iosram.h>
55 #include <sys/sgsbbc_iosram_priv.h>
56 #include <sys/sgsbbc_mailbox.h>
57 #include <sys/sgsgn.h>
58 #include <sys/sgcn.h>
59 #include <sys/serengeti.h>
60 #include <sys/sgfrutypes.h>
61 #include <sys/machsystm.h>
62 #include <sys/sbd_ioctl.h>
63 #include <sys/sbd.h>
64 #include <sys/sbdp_mem.h>
65 
66 #include <sys/memnode.h>
67 #include <vm/vm_dep.h>
68 #include <vm/page.h>
69 
70 #include <sys/cheetahregs.h>
71 #include <sys/plat_ecc_unum.h>
72 #include <sys/plat_ecc_dimm.h>
73 
74 #include <sys/lgrp.h>
75 
76 static int sg_debug = 0;
77 
78 #ifdef DEBUG
79 #define	DCMNERR if (sg_debug) cmn_err
80 #else
81 #define	DCMNERR
82 #endif
83 
84 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
85 
86 /* local functions */
87 static void cpu_sgn_update(ushort_t sgn, uchar_t state,
88     uchar_t sub_state, int cpuid);
89 
90 
91 /*
92  * Local data.
93  *
94  * iosram_write_ptr is a pointer to iosram_write().  Because of
95  * kernel dynamic linking, we can't get to the function by name,
96  * but we can look up its address, and store it in this variable
97  * instead.
98  *
99  * We include the extern for iosram_write() here not because we call
100  * it, but to force compilation errors if its prototype doesn't
101  * match the prototype of iosram_write_ptr.
102  *
103  * The same issues apply to iosram_read() and iosram_read_ptr.
104  */
105 /*CSTYLED*/
106 extern int   iosram_write     (int, uint32_t, caddr_t, uint32_t);
107 static int (*iosram_write_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
108 /*CSTYLED*/
109 extern int   iosram_read     (int, uint32_t, caddr_t, uint32_t);
110 static int (*iosram_read_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
111 
112 
113 /*
114  * Variable to indicate if the date should be obtained from the SC or not.
115  */
116 int todsg_use_sc = FALSE;	/* set the false at the beginning */
117 
118 /*
119  * Preallocation of spare tsb's for DR
120  *
121  * We don't allocate spares for Wildcat since TSBs should come
122  * out of memory local to the node.
123  */
124 #define	IOMMU_PER_SCHIZO	2
125 int serengeti_tsb_spares = (SG_MAX_IO_BDS * SG_SCHIZO_PER_IO_BD *
126 	IOMMU_PER_SCHIZO);
127 
128 /*
129  * sg_max_ncpus is the maximum number of CPUs supported on Serengeti.
130  * sg_max_ncpus is set to be smaller than NCPU to reduce the amount of
131  * memory the logs take up until we have a dynamic log memory allocation
132  * solution.
133  */
134 int sg_max_ncpus = (24 * 2);    /* (max # of processors * # of cores/proc) */
135 
136 /*
137  * variables to control mailbox message timeouts.
138  * These can be patched via /etc/system or mdb.
139  */
140 int	sbbc_mbox_default_timeout = MBOX_DEFAULT_TIMEOUT;
141 int	sbbc_mbox_min_timeout = MBOX_MIN_TIMEOUT;
142 
143 /* cached 'chosen' node_id */
144 pnode_t chosen_nodeid = (pnode_t)0;
145 
146 static void (*sg_ecc_taskq_func)(sbbc_ecc_mbox_t *) = NULL;
147 static int (*sg_ecc_mbox_func)(sbbc_ecc_mbox_t *) = NULL;
148 
149 /*
150  * Table that maps memory slices to a specific memnode.
151  */
152 int slice_to_memnode[SG_MAX_SLICE];
153 
154 plat_dimm_sid_board_t	domain_dimm_sids[SG_MAX_CPU_BDS];
155 
156 
157 int
158 set_platform_tsb_spares()
159 {
160 	return (MIN(serengeti_tsb_spares, MAX_UPA));
161 }
162 
163 #pragma weak mmu_init_large_pages
164 
165 void
166 set_platform_defaults(void)
167 {
168 	extern int watchdog_enable;
169 	extern uint64_t xc_tick_limit_scale;
170 	extern void mmu_init_large_pages(size_t);
171 
172 #ifdef DEBUG
173 	char *todsg_name = "todsg";
174 	ce_verbose_memory = 2;
175 	ce_verbose_other = 2;
176 #endif /* DEBUG */
177 
178 	watchdog_enable = TRUE;
179 	watchdog_available = TRUE;
180 
181 	cpu_sgn_func = cpu_sgn_update;
182 
183 #ifdef DEBUG
184 	/* tod_module_name should be set to "todsg" from OBP property */
185 	if (tod_module_name && (strcmp(tod_module_name, todsg_name) == 0))
186 		prom_printf("Using todsg driver\n");
187 	else {
188 		prom_printf("Force using todsg driver\n");
189 		tod_module_name = todsg_name;
190 	}
191 #endif /* DEBUG */
192 
193 	/* Serengeti does not support forthdebug */
194 	forthdebug_supported = 0;
195 
196 
197 	/*
198 	 * Some DR operations require the system to be sync paused.
199 	 * Sync pause on Serengeti could potentially take up to 4
200 	 * seconds to complete depending on the load on the SC.  To
201 	 * avoid send_mond panics during such operations, we need to
202 	 * increase xc_tick_limit to a larger value on Serengeti by
203 	 * setting xc_tick_limit_scale to 5.
204 	 */
205 	xc_tick_limit_scale = 5;
206 
207 	if ((mmu_page_sizes == max_mmu_page_sizes) &&
208 	    (mmu_ism_pagesize != DEFAULT_ISM_PAGESIZE)) {
209 		if (&mmu_init_large_pages)
210 			mmu_init_large_pages(mmu_ism_pagesize);
211 	}
212 }
213 
214 void
215 load_platform_modules(void)
216 {
217 	if (modload("misc", "pcihp") < 0) {
218 		cmn_err(CE_NOTE, "pcihp driver failed to load");
219 	}
220 }
221 
222 /*ARGSUSED*/
223 int
224 plat_cpu_poweron(struct cpu *cp)
225 {
226 	int (*serengeti_cpu_poweron)(struct cpu *) = NULL;
227 
228 	serengeti_cpu_poweron =
229 	    (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweron", 0);
230 
231 	if (serengeti_cpu_poweron == NULL)
232 		return (ENOTSUP);
233 	else
234 		return ((serengeti_cpu_poweron)(cp));
235 }
236 
237 /*ARGSUSED*/
238 int
239 plat_cpu_poweroff(struct cpu *cp)
240 {
241 	int (*serengeti_cpu_poweroff)(struct cpu *) = NULL;
242 
243 	serengeti_cpu_poweroff =
244 	    (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweroff", 0);
245 
246 	if (serengeti_cpu_poweroff == NULL)
247 		return (ENOTSUP);
248 	else
249 		return ((serengeti_cpu_poweroff)(cp));
250 }
251 
252 #ifdef DEBUG
253 pgcnt_t serengeti_cage_size_limit;
254 #endif
255 
256 /* Preferred minimum cage size (expressed in pages)... for DR */
257 pgcnt_t serengeti_minimum_cage_size = 0;
258 
259 void
260 set_platform_cage_params(void)
261 {
262 	extern pgcnt_t total_pages;
263 	extern struct memlist *phys_avail;
264 
265 	if (kernel_cage_enable) {
266 		pgcnt_t preferred_cage_size;
267 
268 		preferred_cage_size =
269 		    MAX(serengeti_minimum_cage_size, total_pages / 256);
270 #ifdef DEBUG
271 		if (serengeti_cage_size_limit)
272 			preferred_cage_size = serengeti_cage_size_limit;
273 #endif
274 		/*
275 		 * Post copies obp into the lowest slice.  This requires the
276 		 * cage to grow upwards
277 		 */
278 		kcage_range_init(phys_avail, KCAGE_UP, preferred_cage_size);
279 	}
280 
281 	/* Only note when the cage is off since it should always be on. */
282 	if (!kcage_on)
283 		cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED");
284 }
285 
286 #define	ALIGN(x, a)	((a) == 0 ? (uint64_t)(x) : \
287 	(((uint64_t)(x) + (uint64_t)(a) - 1l) & ~((uint64_t)(a) - 1l)))
288 
289 void
290 update_mem_bounds(int brd, uint64_t base, uint64_t sz)
291 {
292 	uint64_t	end;
293 	int		mnode;
294 
295 	end = base + sz - 1;
296 
297 	/*
298 	 * First see if this board already has a memnode associated
299 	 * with it.  If not, see if this slice has a memnode.  This
300 	 * covers the cases where a single slice covers multiple
301 	 * boards (cross-board interleaving) and where a single
302 	 * board has multiple slices (1+GB DIMMs).
303 	 */
304 	if ((mnode = plat_lgrphand_to_mem_node(brd)) == -1) {
305 		if ((mnode = slice_to_memnode[PA_2_SLICE(base)]) == -1)
306 			mnode = mem_node_alloc();
307 		plat_assign_lgrphand_to_mem_node(brd, mnode);
308 	}
309 
310 	/*
311 	 * Align base at 16GB boundary
312 	 */
313 	base = ALIGN(base, (1ul << PA_SLICE_SHIFT));
314 
315 	while (base < end) {
316 		slice_to_memnode[PA_2_SLICE(base)] = mnode;
317 		base += (1ul << PA_SLICE_SHIFT);
318 	}
319 }
320 
321 /*
322  * Dynamically detect memory slices in the system by decoding
323  * the cpu memory decoder registers at boot time.
324  */
325 void
326 plat_fill_mc(pnode_t nodeid)
327 {
328 	uint64_t	mc_addr, mask;
329 	uint64_t	mc_decode[SG_MAX_BANKS_PER_MC];
330 	uint64_t	base, size;
331 	uint32_t	regs[4];
332 	int		len;
333 	int		local_mc;
334 	int		portid;
335 	int		boardid;
336 	int		i;
337 
338 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
339 	    (portid == -1))
340 		return;
341 
342 	/*
343 	 * Decode the board number from the MC portid
344 	 */
345 	boardid = SG_PORTID_TO_BOARD_NUM(portid);
346 
347 	/*
348 	 * The "reg" property returns 4 32-bit values. The first two are
349 	 * combined to form a 64-bit address.  The second two are for a
350 	 * 64-bit size, but we don't actually need to look at that value.
351 	 */
352 	len = prom_getproplen(nodeid, "reg");
353 	if (len != (sizeof (uint32_t) * 4)) {
354 		prom_printf("Warning: malformed 'reg' property\n");
355 		return;
356 	}
357 	if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0)
358 		return;
359 	mc_addr = ((uint64_t)regs[0]) << 32;
360 	mc_addr |= (uint64_t)regs[1];
361 
362 	/*
363 	 * Figure out whether the memory controller we are examining
364 	 * belongs to this CPU or a different one.
365 	 */
366 	if (portid == cpunodes[CPU->cpu_id].portid)
367 		local_mc = 1;
368 	else
369 		local_mc = 0;
370 
371 	for (i = 0; i < SG_MAX_BANKS_PER_MC; i++) {
372 		mask = SG_REG_2_OFFSET(i);
373 
374 		/*
375 		 * If the memory controller is local to this CPU, we use
376 		 * the special ASI to read the decode registers.
377 		 * Otherwise, we load the values from a magic address in
378 		 * I/O space.
379 		 */
380 		if (local_mc)
381 			mc_decode[i] = lddmcdecode(mask & MC_OFFSET_MASK);
382 		else
383 			mc_decode[i] = lddphysio((mc_addr | mask));
384 
385 		if (mc_decode[i] >> MC_VALID_SHIFT) {
386 			/*
387 			 * The memory decode register is a bitmask field,
388 			 * so we can decode that into both a base and
389 			 * a span.
390 			 */
391 			base = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT;
392 			size = MC_UK2SPAN(mc_decode[i]);
393 			update_mem_bounds(boardid, base, size);
394 		}
395 	}
396 }
397 
398 /*
399  * This routine is run midway through the boot process.  By the time we get
400  * here, we know about all the active CPU boards in the system, and we have
401  * extracted information about each board's memory from the memory
402  * controllers.  We have also figured out which ranges of memory will be
403  * assigned to which memnodes, so we walk the slice table to build the table
404  * of memnodes.
405  */
406 /* ARGSUSED */
407 void
408 plat_build_mem_nodes(u_longlong_t *list, size_t  nelems)
409 {
410 	int	slice;
411 	pfn_t	basepfn;
412 	pgcnt_t	npgs;
413 
414 	mem_node_pfn_shift = PFN_SLICE_SHIFT;
415 	mem_node_physalign = (1ull << PA_SLICE_SHIFT);
416 
417 	for (slice = 0; slice < SG_MAX_SLICE; slice++) {
418 		if (slice_to_memnode[slice] == -1)
419 			continue;
420 		basepfn = (uint64_t)slice << PFN_SLICE_SHIFT;
421 		npgs = 1ull << PFN_SLICE_SHIFT;
422 		mem_node_add_slice(basepfn, basepfn + npgs - 1);
423 	}
424 }
425 
426 int
427 plat_pfn_to_mem_node(pfn_t pfn)
428 {
429 	int node;
430 
431 	node = slice_to_memnode[PFN_2_SLICE(pfn)];
432 
433 	return (node);
434 }
435 
436 /*
437  * Serengeti support for lgroups.
438  *
439  * On Serengeti, an lgroup platform handle == board number.
440  *
441  * Mappings between lgroup handles and memnodes are managed
442  * in addition to mappings between memory slices and memnodes
443  * to support cross-board interleaving as well as multiple
444  * slices per board (e.g. >1GB DIMMs). The initial mapping
445  * of memnodes to lgroup handles is determined at boot time.
446  * A DR addition of memory adds a new mapping. A DR copy-rename
447  * swaps mappings.
448  */
449 
450 /*
451  * Macro for extracting the board number from the CPU id
452  */
453 #define	CPUID_TO_BOARD(id)	(((id) >> 2) & 0x7)
454 
455 /*
456  * Return the platform handle for the lgroup containing the given CPU
457  *
458  * For Serengeti, lgroup platform handle == board number
459  */
460 lgrp_handle_t
461 plat_lgrp_cpu_to_hand(processorid_t id)
462 {
463 	return (CPUID_TO_BOARD(id));
464 }
465 
466 /*
467  * Platform specific lgroup initialization
468  */
469 void
470 plat_lgrp_init(void)
471 {
472 	int i;
473 	extern uint32_t lgrp_expand_proc_thresh;
474 	extern uint32_t lgrp_expand_proc_diff;
475 
476 	/*
477 	 * Initialize lookup tables to invalid values so we catch
478 	 * any illegal use of them.
479 	 */
480 	for (i = 0; i < SG_MAX_SLICE; i++) {
481 		slice_to_memnode[i] = -1;
482 	}
483 
484 	/*
485 	 * Set tuneables for Serengeti architecture
486 	 *
487 	 * lgrp_expand_proc_thresh is the minimum load on the lgroups
488 	 * this process is currently running on before considering
489 	 * expanding threads to another lgroup.
490 	 *
491 	 * lgrp_expand_proc_diff determines how much less the remote lgroup
492 	 * must be loaded before expanding to it.
493 	 *
494 	 * Bandwidth is maximized on Serengeti by spreading load across
495 	 * the machine. The impact to inter-thread communication isn't
496 	 * too costly since remote latencies are relatively low.  These
497 	 * values equate to one CPU's load and so attempt to spread the
498 	 * load out across as many lgroups as possible one CPU at a time.
499 	 */
500 	lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX;
501 	lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX;
502 }
503 
504 /*
505  * Platform notification of lgroup (re)configuration changes
506  */
507 /*ARGSUSED*/
508 void
509 plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg)
510 {
511 	update_membounds_t	*umb;
512 	lgrp_config_mem_rename_t lmr;
513 	lgrp_handle_t		shand, thand;
514 	int			snode, tnode;
515 
516 	switch (evt) {
517 
518 	case LGRP_CONFIG_MEM_ADD:
519 		umb = (update_membounds_t *)arg;
520 		update_mem_bounds(umb->u_board, umb->u_base, umb->u_len);
521 
522 		break;
523 
524 	case LGRP_CONFIG_MEM_DEL:
525 		/* We don't have to do anything */
526 		break;
527 
528 	case LGRP_CONFIG_MEM_RENAME:
529 		/*
530 		 * During a DR copy-rename operation, all of the memory
531 		 * on one board is moved to another board -- but the
532 		 * addresses/pfns and memnodes don't change. This means
533 		 * the memory has changed locations without changing identity.
534 		 *
535 		 * Source is where we are copying from and target is where we
536 		 * are copying to.  After source memnode is copied to target
537 		 * memnode, the physical addresses of the target memnode are
538 		 * renamed to match what the source memnode had.  Then target
539 		 * memnode can be removed and source memnode can take its
540 		 * place.
541 		 *
542 		 * To do this, swap the lgroup handle to memnode mappings for
543 		 * the boards, so target lgroup will have source memnode and
544 		 * source lgroup will have empty target memnode which is where
545 		 * its memory will go (if any is added to it later).
546 		 *
547 		 * Then source memnode needs to be removed from its lgroup
548 		 * and added to the target lgroup where the memory was living
549 		 * but under a different name/memnode.  The memory was in the
550 		 * target memnode and now lives in the source memnode with
551 		 * different physical addresses even though it is the same
552 		 * memory.
553 		 */
554 		shand = arg & 0xffff;
555 		thand = (arg & 0xffff0000) >> 16;
556 		snode = plat_lgrphand_to_mem_node(shand);
557 		tnode = plat_lgrphand_to_mem_node(thand);
558 
559 		plat_assign_lgrphand_to_mem_node(thand, snode);
560 		plat_assign_lgrphand_to_mem_node(shand, tnode);
561 
562 		/*
563 		 * Remove source memnode of copy rename from its lgroup
564 		 * and add it to its new target lgroup
565 		 */
566 		lmr.lmem_rename_from = shand;
567 		lmr.lmem_rename_to = thand;
568 
569 		lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode,
570 		    (uintptr_t)&lmr);
571 
572 		break;
573 
574 	default:
575 		break;
576 	}
577 }
578 
579 /*
580  * Return latency between "from" and "to" lgroups
581  *
582  * This latency number can only be used for relative comparison
583  * between lgroups on the running system, cannot be used across platforms,
584  * and may not reflect the actual latency.  It is platform and implementation
585  * specific, so platform gets to decide its value.  It would be nice if the
586  * number was at least proportional to make comparisons more meaningful though.
587  * NOTE: The numbers below are supposed to be load latencies for uncached
588  * memory divided by 10.
589  */
590 int
591 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
592 {
593 	/*
594 	 * Return min remote latency when there are more than two lgroups
595 	 * (root and child) and getting latency between two different lgroups
596 	 * or root is involved
597 	 */
598 	if (lgrp_optimizations() && (from != to ||
599 	    from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
600 		return (28);
601 	else
602 		return (23);
603 }
604 
605 /* ARGSUSED */
606 void
607 plat_freelist_process(int mnode)
608 {
609 }
610 
611 /*
612  * Find dip for chosen IOSRAM
613  */
614 dev_info_t *
615 find_chosen_dip(void)
616 {
617 	dev_info_t	*dip;
618 	char		master_sbbc[MAXNAMELEN];
619 	pnode_t		nodeid;
620 	uint_t		tunnel;
621 
622 	/*
623 	 * find the /chosen SBBC node, prom interface will handle errors
624 	 */
625 	nodeid = prom_chosennode();
626 
627 	/*
628 	 * get the 'iosram' property from the /chosen node
629 	 */
630 	if (prom_getprop(nodeid, IOSRAM_CHOSEN_PROP, (caddr_t)&tunnel) <= 0) {
631 		SBBC_ERR(CE_PANIC, "No iosram property found! \n");
632 	}
633 
634 	if (prom_phandle_to_path((phandle_t)tunnel, master_sbbc,
635 	    sizeof (master_sbbc)) < 0) {
636 		SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
637 		    tunnel);
638 	}
639 
640 	chosen_nodeid = nodeid;
641 
642 	/*
643 	 * load and attach the sgsbbc driver.
644 	 * This will also attach all the sgsbbc driver instances
645 	 */
646 	if (i_ddi_attach_hw_nodes("sgsbbc") != DDI_SUCCESS) {
647 		cmn_err(CE_WARN, "sgsbbc failed to load\n");
648 	}
649 
650 	/* translate a path name to a dev_info_t */
651 	dip = e_ddi_hold_devi_by_path(master_sbbc, 0);
652 	if ((dip == NULL) || (ddi_get_nodeid(dip) != tunnel)) {
653 		cmn_err(CE_PANIC, "i_ddi_path_to_devi(%x) failed for SBBC\n",
654 		    tunnel);
655 	}
656 
657 	/* make sure devi_ref is ZERO */
658 	ndi_rele_devi(dip);
659 
660 	DCMNERR(CE_CONT, "Chosen IOSRAM is at %s \n", master_sbbc);
661 
662 	return (dip);
663 }
664 
665 void
666 load_platform_drivers(void)
667 {
668 	int ret;
669 
670 	/*
671 	 * Load and attach the mc-us3 memory driver.
672 	 */
673 	if (i_ddi_attach_hw_nodes("mc-us3") != DDI_SUCCESS)
674 		cmn_err(CE_WARN, "mc-us3 failed to load");
675 	else
676 		(void) ddi_hold_driver(ddi_name_to_major("mc-us3"));
677 
678 	/*
679 	 * Initialize the chosen IOSRAM before its clients
680 	 * are loaded.
681 	 */
682 	(void) find_chosen_dip();
683 
684 	/*
685 	 * Ideally, we'd do this in set_platform_defaults(), but
686 	 * at that point it's too early to look up symbols.
687 	 */
688 	iosram_write_ptr = (int (*)(int, uint32_t, caddr_t, uint32_t))
689 	    modgetsymvalue("iosram_write", 0);
690 
691 	if (iosram_write_ptr == NULL) {
692 		DCMNERR(CE_WARN, "load_platform_defaults: iosram_write()"
693 		    " not found; signatures will not be updated\n");
694 	} else {
695 		/*
696 		 * The iosram read ptr is only needed if we can actually
697 		 * write CPU signatures, so only bother setting it if we
698 		 * set a valid write pointer, above.
699 		 */
700 		iosram_read_ptr = (int (*)(int, uint32_t, caddr_t, uint32_t))
701 		    modgetsymvalue("iosram_read", 0);
702 
703 		if (iosram_read_ptr == NULL)
704 			DCMNERR(CE_WARN, "load_platform_defaults: iosram_read()"
705 			    " not found\n");
706 	}
707 
708 	/*
709 	 * Set todsg_use_sc to TRUE so that we will be getting date
710 	 * from the SC.
711 	 */
712 	todsg_use_sc = TRUE;
713 
714 	/*
715 	 * Now is a good time to activate hardware watchdog (if one exists).
716 	 */
717 	mutex_enter(&tod_lock);
718 	if (watchdog_enable)
719 		ret = tod_ops.tod_set_watchdog_timer(watchdog_timeout_seconds);
720 	mutex_exit(&tod_lock);
721 	if (ret != 0)
722 		printf("Hardware watchdog enabled\n");
723 
724 	/*
725 	 * Load and attach the schizo pci bus nexus driver.
726 	 */
727 	if (i_ddi_attach_hw_nodes("pcisch") != DDI_SUCCESS)
728 		cmn_err(CE_WARN, "pcisch failed to load");
729 
730 	plat_ecc_init();
731 }
732 
733 /*
734  * No platform drivers on this platform
735  */
736 char *platform_module_list[] = {
737 	(char *)0
738 };
739 
740 /*ARGSUSED*/
741 void
742 plat_tod_fault(enum tod_fault_type tod_bad)
743 {
744 }
745 int
746 plat_max_boards()
747 {
748 	return (SG_MAX_BDS);
749 }
750 int
751 plat_max_io_units_per_board()
752 {
753 	return (SG_MAX_IO_PER_BD);
754 }
755 int
756 plat_max_cmp_units_per_board()
757 {
758 	return (SG_MAX_CMPS_PER_BD);
759 }
760 int
761 plat_max_cpu_units_per_board()
762 {
763 	return (SG_MAX_CPUS_PER_BD);
764 }
765 
766 int
767 plat_max_mc_units_per_board()
768 {
769 	return (SG_MAX_CMPS_PER_BD); /* each CPU die has a memory controller */
770 }
771 
772 int
773 plat_max_mem_units_per_board()
774 {
775 	return (SG_MAX_MEM_PER_BD);
776 }
777 
778 int
779 plat_max_cpumem_boards(void)
780 {
781 	return (SG_MAX_CPU_BDS);
782 }
783 
784 int
785 set_platform_max_ncpus(void)
786 {
787 	return (sg_max_ncpus);
788 }
789 
790 void
791 plat_dmv_params(uint_t *hwint, uint_t *swint)
792 {
793 	*hwint = MAX_UPA;
794 	*swint = 0;
795 }
796 
797 /*
798  * Our nodename has been set, pass it along to the SC.
799  */
800 void
801 plat_nodename_set(void)
802 {
803 	sbbc_msg_t	req;	/* request */
804 	sbbc_msg_t	resp;	/* response */
805 	int		rv;	/* return value from call to mbox */
806 	struct nodename_info {
807 		int32_t	namelen;
808 		char	nodename[_SYS_NMLN];
809 	} nni;
810 	int (*sg_mbox)(sbbc_msg_t *, sbbc_msg_t *, time_t) = NULL;
811 
812 	/*
813 	 * find the symbol for the mailbox routine
814 	 */
815 	sg_mbox = (int (*)(sbbc_msg_t *, sbbc_msg_t *, time_t))
816 		modgetsymvalue("sbbc_mbox_request_response", 0);
817 
818 	if (sg_mbox == NULL) {
819 		cmn_err(CE_NOTE, "!plat_nodename_set: sg_mbox not found\n");
820 		return;
821 	}
822 
823 	/*
824 	 * construct the message telling the SC our nodename
825 	 */
826 	(void) strcpy(nni.nodename, utsname.nodename);
827 	nni.namelen = (int32_t)strlen(nni.nodename);
828 
829 	req.msg_type.type = INFO_MBOX;
830 	req.msg_type.sub_type = INFO_MBOX_NODENAME;
831 	req.msg_status = 0;
832 	req.msg_len = (int)(nni.namelen + sizeof (nni.namelen));
833 	req.msg_bytes = 0;
834 	req.msg_buf = (caddr_t)&nni;
835 	req.msg_data[0] = 0;
836 	req.msg_data[1] = 0;
837 
838 	/*
839 	 * initialize the response back from the SC
840 	 */
841 	resp.msg_type.type = INFO_MBOX;
842 	resp.msg_type.sub_type = INFO_MBOX_NODENAME;
843 	resp.msg_status = 0;
844 	resp.msg_len = 0;
845 	resp.msg_bytes = 0;
846 	resp.msg_buf = (caddr_t)0;
847 	resp.msg_data[0] = 0;
848 	resp.msg_data[1] = 0;
849 
850 	/*
851 	 * ship it and check for success
852 	 */
853 	rv = (sg_mbox)(&req, &resp, sbbc_mbox_default_timeout);
854 
855 	if (rv != 0) {
856 		cmn_err(CE_NOTE, "!plat_nodename_set: sg_mbox retval %d\n", rv);
857 	} else if (resp.msg_status != 0) {
858 		cmn_err(CE_NOTE, "!plat_nodename_set: msg_status %d\n",
859 			resp.msg_status);
860 	} else {
861 		DCMNERR(CE_NOTE, "!plat_nodename_set was successful\n");
862 
863 		/*
864 		 * It is necessary to exchange the capability bitmap
865 		 * with SC before sending any ecc error information and
866 		 * indictment. We are calling the plat_ecc_capability_send()
867 		 * here just after sending the nodename successfully.
868 		 */
869 		rv = plat_ecc_capability_send();
870 		if (rv == 0) {
871 			DCMNERR(CE_NOTE, "!plat_ecc_capability_send was"
872 			    " successful\n");
873 		}
874 	}
875 }
876 
877 /*
878  * flag to allow users switch between using OBP's
879  * prom_get_unum() and mc-us3 driver's p2get_mem_unum()
880  * (for main memory errors only).
881  */
882 int sg_use_prom_get_unum = 0;
883 
884 /*
885  * Debugging flag: set to 1 to call into obp for get_unum, or set it to 0
886  * to call into the unum cache system.  This is the E$ equivalent of
887  * sg_use_prom_get_unum.
888  */
889 int sg_use_prom_ecache_unum = 0;
890 
891 /* used for logging ECC errors to the SC */
892 #define	SG_MEMORY_ECC	1
893 #define	SG_ECACHE_ECC	2
894 #define	SG_UNKNOWN_ECC	(-1)
895 
896 /*
897  * plat_get_mem_unum() generates a string identifying either the
898  * memory or E$ DIMM(s) during error logging. Depending on whether
899  * the error is E$ or memory related, the appropriate support
900  * routine is called to assist in the string generation.
901  *
902  * - For main memory errors we can use the mc-us3 drivers p2getunum()
903  *   (or prom_get_unum() for debugging purposes).
904  *
905  * - For E$ errors we call sg_get_ecacheunum() to generate the unum (or
906  *   prom_serengeti_get_ecacheunum() for debugging purposes).
907  */
908 
909 static int
910 sg_prom_get_unum(int synd_code, uint64_t paddr, char *buf, int buflen,
911     int *lenp)
912 {
913 	if ((prom_get_unum(synd_code, (unsigned long long)paddr,
914 	    buf, buflen, lenp)) != 0)
915 		return (EIO);
916 	else if (*lenp <= 1)
917 		return (EINVAL);
918 	else
919 		return (0);
920 }
921 
922 /*ARGSUSED*/
923 int
924 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
925     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
926 {
927 	/*
928 	 * unum_func will either point to the memory drivers p2get_mem_unum()
929 	 * or to prom_get_unum() for memory errors.
930 	 */
931 	int (*unum_func)(int synd_code, uint64_t paddr, char *buf,
932 	    int buflen, int *lenp) = p2get_mem_unum;
933 
934 	/*
935 	 * check if it's a Memory or an Ecache error.
936 	 */
937 	if (flt_in_memory) {
938 		/*
939 		 * It's a main memory error.
940 		 *
941 		 * For debugging we allow the user to switch between
942 		 * using OBP's get_unum and the memory driver's get_unum
943 		 * so we create a pointer to the functions and switch
944 		 * depending on the sg_use_prom_get_unum flag.
945 		 */
946 		if (sg_use_prom_get_unum) {
947 			DCMNERR(CE_NOTE, "Using prom_get_unum from OBP");
948 			return (sg_prom_get_unum(synd_code,
949 			    P2ALIGN(flt_addr, 8), buf, buflen, lenp));
950 		} else if (unum_func != NULL) {
951 			return (unum_func(synd_code, P2ALIGN(flt_addr, 8),
952 			    buf, buflen, lenp));
953 		} else {
954 			return (ENOTSUP);
955 		}
956 	} else if (flt_status & ECC_ECACHE) {
957 		/*
958 		 * It's an E$ error.
959 		 */
960 		if (sg_use_prom_ecache_unum) {
961 			/*
962 			 * We call to OBP to handle this.
963 			 */
964 			DCMNERR(CE_NOTE,
965 			    "Using prom_serengeti_get_ecacheunum from OBP");
966 			if (prom_serengeti_get_ecacheunum(flt_bus_id,
967 			    P2ALIGN(flt_addr, 8), buf, buflen, lenp) != 0) {
968 				return (EIO);
969 			}
970 		} else {
971 			return (sg_get_ecacheunum(flt_bus_id, flt_addr,
972 			    buf, buflen, lenp));
973 		}
974 	} else {
975 		return (ENOTSUP);
976 	}
977 
978 	return (0);
979 }
980 
981 /*
982  * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3
983  * driver giving each platform the opportunity to add platform
984  * specific label information to the unum for ECC error logging purposes.
985  */
986 void
987 plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
988 {
989 	char	new_unum[UNUM_NAMLEN] = "";
990 	int	node = SG_PORTID_TO_NODEID(mcid);
991 	int	board = SG_CPU_BD_PORTID_TO_BD_NUM(mcid);
992 	int	position = SG_PORTID_TO_CPU_POSN(mcid);
993 
994 	/*
995 	 * The mc-us3 driver deals with logical banks but for unum
996 	 * purposes we need to use physical banks so that the correct
997 	 * dimm can be physically located. Logical banks 0 and 2
998 	 * make up physical bank 0. Logical banks 1 and 3 make up
999 	 * physical bank 1. Here we do the necessary conversion.
1000 	 */
1001 	bank = (bank % 2);
1002 
1003 	if (dimm == -1) {
1004 		SG_SET_FRU_NAME_NODE(new_unum, node);
1005 		SG_SET_FRU_NAME_CPU_BOARD(new_unum, board);
1006 		SG_SET_FRU_NAME_MODULE(new_unum, position);
1007 		SG_SET_FRU_NAME_BANK(new_unum, bank);
1008 
1009 	} else {
1010 		SG_SET_FRU_NAME_NODE(new_unum, node);
1011 		SG_SET_FRU_NAME_CPU_BOARD(new_unum, board);
1012 		SG_SET_FRU_NAME_MODULE(new_unum, position);
1013 		SG_SET_FRU_NAME_BANK(new_unum, bank);
1014 		SG_SET_FRU_NAME_DIMM(new_unum, dimm);
1015 
1016 		strcat(new_unum, " ");
1017 		strcat(new_unum, unum);
1018 	}
1019 
1020 	strcpy(unum, new_unum);
1021 }
1022 
1023 int
1024 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
1025 {
1026 	int	node = SG_PORTID_TO_NODEID(cpuid);
1027 	int	board = SG_CPU_BD_PORTID_TO_BD_NUM(cpuid);
1028 
1029 	if (snprintf(buf, buflen, "/N%d/%s%d", node,
1030 	    SG_HPU_TYPE_CPU_BOARD_ID, board) >= buflen) {
1031 		return (ENOSPC);
1032 	} else {
1033 		*lenp = strlen(buf);
1034 		return (0);
1035 	}
1036 }
1037 
1038 /*
1039  * We log all ECC events to the SC so we send a mailbox
1040  * message to the SC passing it the relevant data.
1041  * ECC mailbox messages are sent via a taskq mechanism to
1042  * prevent impaired system performance during ECC floods.
1043  * Indictments have already passed through a taskq, so they
1044  * are not queued here.
1045  */
1046 int
1047 plat_send_ecc_mailbox_msg(plat_ecc_message_type_t msg_type, void *datap)
1048 {
1049 	sbbc_ecc_mbox_t	*msgp;
1050 	size_t		msg_size;
1051 	uint16_t	msg_subtype;
1052 	int		sleep_flag, log_error;
1053 
1054 	if (sg_ecc_taskq_func == NULL) {
1055 		sg_ecc_taskq_func = (void (*)(sbbc_ecc_mbox_t *))
1056 		    modgetsymvalue("sbbc_mbox_queue_ecc_event", 0);
1057 		if (sg_ecc_taskq_func == NULL) {
1058 			cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
1059 			    "sbbc_mbox_queue_ecc_event not found");
1060 			return (ENODEV);
1061 		}
1062 	}
1063 	if (sg_ecc_mbox_func == NULL) {
1064 		sg_ecc_mbox_func = (int (*)(sbbc_ecc_mbox_t *))
1065 		    modgetsymvalue("sbbc_mbox_ecc_output", 0);
1066 		if (sg_ecc_mbox_func == NULL) {
1067 			cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
1068 			    "sbbc_mbox_ecc_output not found");
1069 			return (ENODEV);
1070 		}
1071 	}
1072 
1073 	/*
1074 	 * Initialize the request and response structures
1075 	 */
1076 	switch (msg_type) {
1077 	case PLAT_ECC_ERROR_MESSAGE:
1078 		msg_subtype = INFO_MBOX_ERROR_ECC;
1079 		msg_size = sizeof (plat_ecc_error_data_t);
1080 		sleep_flag = KM_NOSLEEP;
1081 		log_error = 1;
1082 		break;
1083 	case PLAT_ECC_ERROR2_MESSAGE:
1084 		msg_subtype = INFO_MBOX_ECC;
1085 		msg_size = sizeof (plat_ecc_error2_data_t);
1086 		sleep_flag = KM_NOSLEEP;
1087 		log_error = 1;
1088 		break;
1089 	case PLAT_ECC_INDICTMENT_MESSAGE:
1090 		msg_subtype = INFO_MBOX_ERROR_INDICT;
1091 		msg_size = sizeof (plat_ecc_indictment_data_t);
1092 		sleep_flag = KM_SLEEP;
1093 		log_error = 0;
1094 		break;
1095 	case PLAT_ECC_INDICTMENT2_MESSAGE:
1096 		msg_subtype = INFO_MBOX_ECC;
1097 		msg_size = sizeof (plat_ecc_indictment2_data_t);
1098 		sleep_flag = KM_SLEEP;
1099 		log_error = 0;
1100 		break;
1101 	case PLAT_ECC_CAPABILITY_MESSAGE:
1102 		msg_subtype = INFO_MBOX_ECC_CAP;
1103 		msg_size = sizeof (plat_capability_data_t) +
1104 		    strlen(utsname.release) + strlen(utsname.version) + 2;
1105 		sleep_flag = KM_SLEEP;
1106 		log_error = 0;
1107 		break;
1108 	case PLAT_ECC_DIMM_SID_MESSAGE:
1109 		msg_subtype = INFO_MBOX_ECC;
1110 		msg_size = sizeof (plat_dimm_sid_request_data_t);
1111 		sleep_flag = KM_SLEEP;
1112 		log_error = 0;
1113 		break;
1114 	default:
1115 		return (EINVAL);
1116 	}
1117 
1118 	msgp = (sbbc_ecc_mbox_t	*)kmem_zalloc(sizeof (sbbc_ecc_mbox_t),
1119 		sleep_flag);
1120 	if (msgp == NULL) {
1121 		cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
1122 				"unable to allocate sbbc_ecc_mbox");
1123 		return (ENOMEM);
1124 	}
1125 
1126 	msgp->ecc_log_error = log_error;
1127 
1128 	msgp->ecc_req.msg_type.type = INFO_MBOX;
1129 	msgp->ecc_req.msg_type.sub_type = msg_subtype;
1130 	msgp->ecc_req.msg_status = 0;
1131 	msgp->ecc_req.msg_len = (int)msg_size;
1132 	msgp->ecc_req.msg_bytes = 0;
1133 	msgp->ecc_req.msg_buf = (caddr_t)kmem_zalloc(msg_size, sleep_flag);
1134 	msgp->ecc_req.msg_data[0] = 0;
1135 	msgp->ecc_req.msg_data[1] = 0;
1136 
1137 	if (msgp->ecc_req.msg_buf == NULL) {
1138 		cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
1139 				"unable to allocate request msg_buf");
1140 		kmem_free((void *)msgp, sizeof (sbbc_ecc_mbox_t));
1141 		return (ENOMEM);
1142 	}
1143 	bcopy(datap, (void *)msgp->ecc_req.msg_buf, msg_size);
1144 
1145 	/*
1146 	 * initialize the response back from the SC
1147 	 */
1148 	msgp->ecc_resp.msg_type.type = INFO_MBOX;
1149 	msgp->ecc_resp.msg_type.sub_type = msg_subtype;
1150 	msgp->ecc_resp.msg_status = 0;
1151 	msgp->ecc_resp.msg_len = 0;
1152 	msgp->ecc_resp.msg_bytes = 0;
1153 	msgp->ecc_resp.msg_buf = NULL;
1154 	msgp->ecc_resp.msg_data[0] = 0;
1155 	msgp->ecc_resp.msg_data[1] = 0;
1156 
1157 	switch (msg_type) {
1158 	case PLAT_ECC_ERROR_MESSAGE:
1159 	case PLAT_ECC_ERROR2_MESSAGE:
1160 		/*
1161 		 * For Error Messages, we go through a taskq.
1162 		 * Queue up the message for processing
1163 		 */
1164 		(*sg_ecc_taskq_func)(msgp);
1165 		return (0);
1166 
1167 	case PLAT_ECC_CAPABILITY_MESSAGE:
1168 		/*
1169 		 * For indictment and capability messages, we've already gone
1170 		 * through the taskq, so we can call the mailbox routine
1171 		 * directly.  Find the symbol for the routine that sends
1172 		 * the mailbox msg
1173 		 */
1174 		msgp->ecc_resp.msg_len = (int)msg_size;
1175 		msgp->ecc_resp.msg_buf = (caddr_t)kmem_zalloc(msg_size,
1176 		    sleep_flag);
1177 		/* FALLTHRU */
1178 
1179 	case PLAT_ECC_INDICTMENT_MESSAGE:
1180 	case PLAT_ECC_INDICTMENT2_MESSAGE:
1181 		return ((*sg_ecc_mbox_func)(msgp));
1182 
1183 	case PLAT_ECC_DIMM_SID_MESSAGE:
1184 		msgp->ecc_resp.msg_len = sizeof (plat_dimm_sid_board_data_t);
1185 		msgp->ecc_resp.msg_buf = (caddr_t)kmem_zalloc(
1186 		    sizeof (plat_dimm_sid_board_data_t), sleep_flag);
1187 		return ((*sg_ecc_mbox_func)(msgp));
1188 
1189 	default:
1190 		ASSERT(0);
1191 		return (EINVAL);
1192 	}
1193 }
1194 
1195 /*
1196  * m is redundant on serengeti as the multiplier is always 4
1197  */
1198 /*ARGSUSED*/
1199 int
1200 plat_make_fru_cpuid(int sb, int m, int proc)
1201 {
1202 	return (MAKE_CPUID(sb, proc));
1203 }
1204 
1205 /*
1206  * board number for a given proc
1207  */
1208 int
1209 plat_make_fru_boardnum(int proc)
1210 {
1211 	return (SG_CPU_BD_PORTID_TO_BD_NUM(proc));
1212 }
1213 
1214 static
1215 void
1216 cpu_sgn_update(ushort_t sig, uchar_t state, uchar_t sub_state, int cpuid)
1217 {
1218 	uint32_t signature = CPU_SIG_BLD(sig, state, sub_state);
1219 	sig_state_t current_sgn;
1220 	int i;
1221 
1222 	if (iosram_write_ptr == NULL) {
1223 		/*
1224 		 * If the IOSRAM write pointer isn't set, we won't be able
1225 		 * to write signatures to ANYTHING, so we may as well just
1226 		 * write out an error message (if desired) and exit this
1227 		 * routine now...
1228 		 */
1229 		DCMNERR(CE_WARN,
1230 		    "cpu_sgn_update: iosram_write() not found;"
1231 		    " cannot write signature 0x%x for CPU(s) or domain\n",
1232 		    signature);
1233 		return;
1234 	}
1235 
1236 
1237 	/*
1238 	 * Differentiate a panic reboot from a non-panic reboot in the
1239 	 * setting of the substate of the signature.
1240 	 *
1241 	 * If the new substate is REBOOT and we're rebooting due to a panic,
1242 	 * then set the new substate to a special value indicating a panic
1243 	 * reboot, SIGSUBST_PANIC_REBOOT.
1244 	 *
1245 	 * A panic reboot is detected by a current (previous) domain signature
1246 	 * state of SIGST_EXIT, and a new signature substate of SIGSUBST_REBOOT.
1247 	 * The domain signature state SIGST_EXIT is used as the panic flow
1248 	 * progresses.
1249 	 *
1250 	 * At the end of the panic flow, the reboot occurs but we should now
1251 	 * one that was involuntary, something that may be quite useful to know
1252 	 * at OBP level.
1253 	 */
1254 	if (sub_state == SIGSUBST_REBOOT) {
1255 		if (iosram_read_ptr == NULL) {
1256 			DCMNERR(CE_WARN,
1257 			    "cpu_sgn_update: iosram_read() not found;"
1258 			    " could not check current domain signature\n");
1259 		} else {
1260 			(void) (*iosram_read_ptr)(SBBC_SIGBLCK_KEY,
1261 				SG_SGNBLK_DOMAINSIG_OFFSET,
1262 				(char *)&current_sgn, sizeof (current_sgn));
1263 			if (current_sgn.state_t.state == SIGST_EXIT)
1264 				signature = CPU_SIG_BLD(sig, state,
1265 					SIGSUBST_PANIC_REBOOT);
1266 		}
1267 	}
1268 
1269 	/*
1270 	 * cpuid == -1 indicates that the operation applies to all cpus.
1271 	 */
1272 	if (cpuid >= 0) {
1273 		(void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
1274 			SG_SGNBLK_CPUSIG_OFFSET(cpuid), (char *)&signature,
1275 			sizeof (signature));
1276 	} else {
1277 		for (i = 0; i < NCPU; i++) {
1278 			if (cpu[i] == NULL || !(cpu[i]->cpu_flags &
1279 				(CPU_EXISTS|CPU_QUIESCED))) {
1280 				continue;
1281 			}
1282 			(void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
1283 				SG_SGNBLK_CPUSIG_OFFSET(i), (char *)&signature,
1284 				sizeof (signature));
1285 		}
1286 	}
1287 
1288 	if (state == SIGST_OFFLINE || state == SIGST_DETACHED) {
1289 		return;
1290 	}
1291 
1292 	(void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
1293 		SG_SGNBLK_DOMAINSIG_OFFSET, (char *)&signature,
1294 		sizeof (signature));
1295 }
1296 
1297 void
1298 startup_platform(void)
1299 {
1300 }
1301 
1302 /*
1303  * A routine to convert a number (represented as a string) to
1304  * the integer value it represents.
1305  */
1306 
1307 static int
1308 isdigit(int ch)
1309 {
1310 	return (ch >= '0' && ch <= '9');
1311 }
1312 
1313 #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
1314 
1315 static int
1316 strtoi(char *p, char **pos)
1317 {
1318 	int n;
1319 	int c, neg = 0;
1320 
1321 	if (!isdigit(c = *p)) {
1322 		while (isspace(c))
1323 			c = *++p;
1324 		switch (c) {
1325 			case '-':
1326 				neg++;
1327 				/* FALLTHROUGH */
1328 			case '+':
1329 			c = *++p;
1330 		}
1331 		if (!isdigit(c)) {
1332 			if (pos != NULL)
1333 				*pos = p;
1334 			return (0);
1335 		}
1336 	}
1337 	for (n = '0' - c; isdigit(c = *++p); ) {
1338 		n *= 10; /* two steps to avoid unnecessary overflow */
1339 		n += '0' - c; /* accum neg to avoid surprises at MAX */
1340 	}
1341 	if (pos != NULL)
1342 		*pos = p;
1343 	return (neg ? n : -n);
1344 }
1345 
1346 /*
1347  * Get the three parts of the Serengeti PROM version.
1348  * Used for feature readiness tests.
1349  *
1350  * Return 0 if version extracted successfully, -1 otherwise.
1351  */
1352 
1353 int
1354 sg_get_prom_version(int *sysp, int *intfp, int *bldp)
1355 {
1356 	int plen;
1357 	char vers[512];
1358 	static pnode_t node;
1359 	static char version[] = "version";
1360 	char *verp, *ep;
1361 
1362 	node = prom_finddevice("/openprom");
1363 	if (node == OBP_BADNODE)
1364 		return (-1);
1365 
1366 	plen = prom_getproplen(node, version);
1367 	if (plen <= 0 || plen >= sizeof (vers))
1368 		return (-1);
1369 	(void) prom_getprop(node, version, vers);
1370 	vers[plen] = '\0';
1371 
1372 	/* Make sure it's an OBP flashprom */
1373 	if (vers[0] != 'O' && vers[1] != 'B' && vers[2] != 'P') {
1374 		cmn_err(CE_WARN, "sg_get_prom_version: "
1375 		    "unknown <version> string in </openprom>\n");
1376 		return (-1);
1377 	}
1378 	verp = &vers[4];
1379 
1380 	*sysp = strtoi(verp, &ep);
1381 	if (ep == verp || *ep != '.')
1382 		return (-1);
1383 	verp = ep + 1;
1384 
1385 	*intfp = strtoi(verp, &ep);
1386 	if (ep == verp || *ep != '.')
1387 		return (-1);
1388 	verp = ep + 1;
1389 
1390 	*bldp = strtoi(verp, &ep);
1391 	if (ep == verp || (*ep != '\0' && !isspace(*ep)))
1392 		return (-1);
1393 	return (0);
1394 }
1395 
1396 /*
1397  * Return 0 if system board Dynamic Reconfiguration
1398  * is supported by the firmware, -1 otherwise.
1399  */
1400 int
1401 sg_prom_sb_dr_check(void)
1402 {
1403 	static int prom_res = 1;
1404 
1405 	if (prom_res == 1) {
1406 		int sys, intf, bld;
1407 		int rv;
1408 
1409 		rv = sg_get_prom_version(&sys, &intf, &bld);
1410 		if (rv == 0 && sys == 5 &&
1411 		    (intf >= 12 || (intf == 11 && bld >= 200))) {
1412 			prom_res = 0;
1413 		} else {
1414 			prom_res = -1;
1415 		}
1416 	}
1417 	return (prom_res);
1418 }
1419 
1420 /*
1421  * Return 0 if cPCI Dynamic Reconfiguration
1422  * is supported by the firmware, -1 otherwise.
1423  */
1424 int
1425 sg_prom_cpci_dr_check(void)
1426 {
1427 	/*
1428 	 * The version check is currently the same as for
1429 	 * system boards. Since the two DR sub-systems are
1430 	 * independent, this could change.
1431 	 */
1432 	return (sg_prom_sb_dr_check());
1433 }
1434 
1435 /*
1436  * KDI functions - used by the in-situ kernel debugger (kmdb) to perform
1437  * platform-specific operations.  These functions execute when the world is
1438  * stopped, and as such cannot make any blocking calls, hold locks, etc.
1439  * promif functions are a special case, and may be used.
1440  */
1441 
1442 /*
1443  * Our implementation of this KDI op updates the CPU signature in the system
1444  * controller.  Note that we set the signature to OBP_SIG, rather than DBG_SIG.
1445  * The Forth words we execute will, among other things, transform our OBP_SIG
1446  * into DBG_SIG.  They won't function properly if we try to use DBG_SIG.
1447  */
1448 static void
1449 sg_system_claim(void)
1450 {
1451 	prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
1452 }
1453 
1454 static void
1455 sg_system_release(void)
1456 {
1457 	prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
1458 }
1459 
1460 static void
1461 sg_console_claim(void)
1462 {
1463 	prom_serengeti_set_console_input(SGCN_OBP_STR);
1464 }
1465 
1466 static void
1467 sg_console_release(void)
1468 {
1469 	prom_serengeti_set_console_input(SGCN_CLNT_STR);
1470 }
1471 
1472 void
1473 plat_kdi_init(kdi_t *kdi)
1474 {
1475 	kdi->pkdi_system_claim = sg_system_claim;
1476 	kdi->pkdi_system_release = sg_system_release;
1477 	kdi->pkdi_console_claim = sg_console_claim;
1478 	kdi->pkdi_console_release = sg_console_release;
1479 }
1480