ac.c revision 7656:2621e50fdf4a
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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28#include <sys/types.h>
29#include <sys/conf.h>
30#include <sys/ddi.h>
31#include <sys/sunddi.h>
32#include <sys/ddi_impldefs.h>
33#include <sys/obpdefs.h>
34#include <sys/cmn_err.h>
35#include <sys/errno.h>
36#include <sys/kmem.h>
37#include <sys/debug.h>
38#include <sys/sysmacros.h>
39#include <sys/machsystm.h>
40#include <vm/hat_sfmmu.h>
41#include <sys/autoconf.h>
42#include <sys/open.h>
43#include <sys/stat.h>
44#include <sys/modctl.h>
45#include <sys/fhc.h>
46#include <sys/ac.h>
47#include <sys/cpu_module.h>
48#include <sys/x_call.h>
49#include <sys/fpu/fpusystm.h>
50#include <sys/lgrp.h>
51
52/* Useful debugging Stuff */
53#include <sys/nexusdebug.h>
54
55/*
56 * Function prototypes
57 */
58
59static int ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
60		void **result);
61static int ac_attach(dev_info_t *, ddi_attach_cmd_t);
62static int ac_detach(dev_info_t *, ddi_detach_cmd_t);
63static int ac_open(dev_t *, int, int, cred_t *);
64static int ac_close(dev_t, int, int, cred_t *);
65static int ac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
66
67static void ac_add_kstats(struct ac_soft_state *);
68static void ac_del_kstats(struct ac_soft_state *);
69static int ac_misc_kstat_update(kstat_t *, int);
70static void ac_add_picN_kstats(dev_info_t *dip);
71static int ac_counters_kstat_update(kstat_t *, int);
72static void ac_get_memory_status(struct ac_soft_state *, enum ac_bank_id);
73static void ac_eval_memory_status(struct ac_soft_state *, enum ac_bank_id);
74static void ac_ecache_flush(uint64_t, uint64_t);
75static int ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
76static int ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
77static int ac_reset_timeout(int rw);
78static void ac_timeout(void *);
79static int ac_enter_transition(void);
80static void ac_exit_transition(void);
81
82
83int ac_add_memory(ac_cfga_pkt_t *);
84int ac_del_memory(ac_cfga_pkt_t *);
85int ac_mem_stat(ac_cfga_pkt_t *, int);
86int ac_mem_test_start(ac_cfga_pkt_t *, int);
87int ac_mem_test_stop(ac_cfga_pkt_t *, int);
88int ac_mem_test_read(ac_cfga_pkt_t *, int);
89int ac_mem_test_write(ac_cfga_pkt_t *, int);
90void ac_mem_test_stop_on_close(uint_t, uint_t);
91/*
92 * ac audit message events
93 */
94typedef enum {
95	AC_AUDIT_OSTATE_CONFIGURE,
96	AC_AUDIT_OSTATE_UNCONFIGURE,
97	AC_AUDIT_OSTATE_SUCCEEDED,
98	AC_AUDIT_OSTATE_CONFIGURE_FAILED,
99	AC_AUDIT_OSTATE_UNCONFIGURE_FAILED
100} ac_audit_evt_t;
101static void ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt);
102static char *ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event);
103
104/* The memory ioctl interface version of this driver. */
105static ac_mem_version_t ac_mem_version = AC_MEM_ADMIN_VERSION;
106
107static int ac_mem_exercise(ac_cfga_pkt_t *, int);
108
109/*
110 * Configuration data structures
111 */
112static struct cb_ops ac_cb_ops = {
113	ac_open,			/* open */
114	ac_close,			/* close */
115	nulldev,			/* strategy */
116	nulldev,			/* print */
117	nodev,				/* dump */
118	nulldev,			/* read */
119	nulldev,			/* write */
120	ac_ioctl,			/* ioctl */
121	nodev,				/* devmap */
122	nodev,				/* mmap */
123	nodev,				/* segmap */
124	nochpoll,			/* poll */
125	ddi_prop_op,			/* cb_prop_op */
126	0,				/* streamtab */
127	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
128	CB_REV,				/* rev */
129	nodev,				/* cb_aread */
130	nodev				/* cb_awrite */
131};
132
133static struct dev_ops ac_ops = {
134	DEVO_REV,			/* devo_rev, */
135	0,				/* refcnt */
136	ac_info,			/* getinfo */
137	nulldev,			/* identify */
138	nulldev,			/* probe */
139	ac_attach,			/* attach */
140	ac_detach,			/* detach */
141	nulldev,			/* reset */
142	&ac_cb_ops,			/* cb_ops */
143	(struct bus_ops *)0,		/* bus_ops */
144	nulldev,			/* power */
145	ddi_quiesce_not_needed,			/* quiesce */
146};
147
148/*
149 * Driver globals
150 */
151void *acp;				/* ac soft state hook */
152static kstat_t	*ac_picN_ksp[AC_NUM_PICS];	/* performance picN kstats */
153static int	ac_attachcnt = 0;	/* number of instances attached */
154static kmutex_t ac_attachcnt_mutex;	/* ac_attachcnt lock - attach/detach */
155static kmutex_t ac_hot_plug_mode_mutex;
156static timeout_id_t	ac_hot_plug_timeout;
157static int		ac_hot_plug_timeout_interval = 10;
158
159#define	AC_GETSOFTC(I) \
160	((struct ac_soft_state *)ddi_get_soft_state(acp, (I)))
161
162extern struct mod_ops mod_driverops;
163
164static struct modldrv modldrv = {
165	&mod_driverops,		/* Type of module.  This one is a driver */
166	"AC Leaf",		/* name of module */
167	&ac_ops,		/* driver ops */
168};
169
170static struct modlinkage modlinkage = {
171	MODREV_1,
172	(void *)&modldrv,
173	NULL
174};
175
176#ifndef lint
177char _depends_on[] = "drv/fhc";
178#endif	/* lint */
179
180/*
181 * These are the module initialization routines.
182 */
183
184int
185_init(void)
186{
187	int error;
188
189	if ((error = ddi_soft_state_init(&acp, sizeof (struct ac_soft_state),
190	    1)) != 0)
191		return (error);
192
193	if ((error = mod_install(&modlinkage)) != 0) {
194		ddi_soft_state_fini(&acp);
195		return (error);
196	}
197	/* Initialize global mutex */
198	mutex_init(&ac_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
199	mutex_init(&ac_hot_plug_mode_mutex, NULL, MUTEX_DRIVER, NULL);
200	return (0);
201}
202
203int
204_fini(void)
205{
206	int error;
207
208	if ((error = mod_remove(&modlinkage)) == 0) {
209		ddi_soft_state_fini(&acp);
210		mutex_destroy(&ac_attachcnt_mutex);
211		mutex_destroy(&ac_hot_plug_mode_mutex);
212	}
213	return (error);
214}
215
216int
217_info(struct modinfo *modinfop)
218{
219	return (mod_info(&modlinkage, modinfop));
220}
221
222/* ARGSUSED */
223static int
224ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
225{
226	dev_t	dev;
227	int	instance;
228
229	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
230		dev = (dev_t)arg;
231		instance = AC_GETINSTANCE(getminor(dev));
232		*result = (void *)(uintptr_t)instance;
233		return (DDI_SUCCESS);
234	}
235	return (DDI_FAILURE);
236}
237
238static int
239ac_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
240{
241	int instance;
242	struct ac_soft_state *softsp;
243	struct bd_list *list = NULL;
244
245	switch (cmd) {
246	case DDI_ATTACH:
247		break;
248
249	case DDI_RESUME:
250		return (DDI_SUCCESS);
251
252	default:
253		return (DDI_FAILURE);
254	}
255
256	instance = ddi_get_instance(devi);
257
258	if (ddi_soft_state_zalloc(acp, instance) != DDI_SUCCESS) {
259		cmn_err(CE_WARN, "ddi_soft_state_zalloc failed for ac%d",
260		    instance);
261		return (DDI_FAILURE);
262	}
263
264	softsp = ddi_get_soft_state(acp, instance);
265
266	/* Set the dip in the soft state */
267	softsp->dip = devi;
268
269	/* Get the board number from this nodes parent */
270	softsp->pdip = ddi_get_parent(softsp->dip);
271	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
272	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
273		cmn_err(CE_WARN, "ac%d: unable to retrieve %s property",
274		    instance, OBP_BOARDNUM);
275		goto bad;
276	}
277
278	DPRINTF(AC_ATTACH_DEBUG, ("ac%d: devi= 0x%p\n,"
279	    " softsp=0x%p\n", instance, devi, softsp));
280
281	/* map in the registers for this device. */
282	if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0)) {
283		cmn_err(CE_WARN, "ac%d: unable to map registers", instance);
284		goto bad;
285	}
286
287	/* Setup the pointers to the hardware registers */
288	softsp->ac_id = (uint32_t *)softsp->ac_base;
289	softsp->ac_memctl = (uint64_t *)((char *)softsp->ac_base +
290	    AC_OFF_MEMCTL);
291	softsp->ac_memdecode0 = (uint64_t *)((char *)softsp->ac_base +
292	    AC_OFF_MEMDEC0);
293	softsp->ac_memdecode1 = (uint64_t *)((char *)softsp->ac_base +
294	    AC_OFF_MEMDEC1);
295	softsp->ac_counter = (uint64_t *)((char *)softsp->ac_base +
296	    AC_OFF_CNTR);
297	softsp->ac_mccr = (uint32_t *)((char *)softsp->ac_base +
298	    AC_OFF_MCCR);
299
300	/* nothing to suspend/resume here */
301	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
302	    "pm-hardware-state", "no-suspend-resume");
303
304	/* setup the the AC counter registers to allow for hotplug. */
305	list = fhc_bdlist_lock(softsp->board);
306
307	if (list == NULL) {
308		cmn_err(CE_PANIC, "ac%d: Board %d not found in database",
309		    instance, softsp->board);
310	}
311
312	/* set the AC rev into the bd list structure */
313	list->sc.ac_compid = *softsp->ac_id;
314
315	list->ac_softsp = softsp;
316
317	if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
318		/* Create the minor nodes */
319		if (ddi_create_minor_node(devi, NAME_BANK0, S_IFCHR,
320		    (AC_PUTINSTANCE(instance) | 0),
321		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
322			cmn_err(CE_WARN, "ac%d: \"%s\" "
323			    "ddi_create_minor_node failed", instance,
324			    NAME_BANK0);
325		}
326		if (ddi_create_minor_node(devi, NAME_BANK1, S_IFCHR,
327		    (AC_PUTINSTANCE(instance) | 1),
328		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
329			cmn_err(CE_WARN, "ac%d: \"%s\" "
330			    "ddi_create_minor_node failed", instance,
331			    NAME_BANK0);
332		}
333
334		/* purge previous fhc pa database entries */
335		fhc_del_memloc(softsp->board);
336
337		/* Inherit Memory Bank Status */
338		ac_get_memory_status(softsp, Bank0);
339		ac_get_memory_status(softsp, Bank1);
340		/* Final Memory Bank Status evaluation and messaging */
341		ac_eval_memory_status(softsp, Bank0);
342		ac_eval_memory_status(softsp, Bank1);
343	}
344
345	fhc_bdlist_unlock();
346
347	/* create the kstats for this device. */
348	ac_add_kstats(softsp);
349
350	ddi_report_dev(devi);
351
352	return (DDI_SUCCESS);
353
354bad:
355	ddi_soft_state_free(acp, instance);
356	return (DDI_FAILURE);
357}
358
359/* ARGSUSED */
360static int
361ac_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
362{
363	int instance;
364	struct ac_soft_state *softsp;
365	struct bd_list *list;
366
367	/* get the instance of this devi */
368	instance = ddi_get_instance(devi);
369
370	/* get the soft state pointer for this device node */
371	softsp = ddi_get_soft_state(acp, instance);
372
373	switch (cmd) {
374	case DDI_SUSPEND:
375		return (DDI_SUCCESS);
376
377	case DDI_DETACH:
378		list = fhc_bdlist_lock(softsp->board);
379
380		if (fhc_bd_detachable(softsp->board))
381			break;
382		else
383			fhc_bdlist_unlock();
384		/* FALLTHROUGH */
385
386	default:
387		return (DDI_FAILURE);
388	}
389
390	ASSERT(list->ac_softsp == softsp);
391
392	if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
393		int cpui;
394
395		/*
396		 * Test to see if memory is in use on a CPU/MEM board.
397		 * In the case of a DR operation this condition
398		 * will have been assured when the board was unconfigured.
399		 */
400		if (softsp->bank[Bank0].busy != 0 ||
401		    softsp->bank[Bank0].ostate == SYSC_CFGA_OSTATE_CONFIGURED ||
402		    softsp->bank[Bank1].busy != 0 ||
403		    softsp->bank[Bank1].ostate == SYSC_CFGA_OSTATE_CONFIGURED) {
404			fhc_bdlist_unlock();
405			return (DDI_FAILURE);
406		}
407		/*
408		 * CPU busy test is done by the DR sequencer before
409		 * device detach called.
410		 */
411
412		/*
413		 * Flush all E-caches to remove references to this
414		 * board's memory.
415		 *
416		 * Do this one CPU at a time to avoid stalls and timeouts
417		 * due to all CPUs flushing concurrently.
418		 * xc_one returns silently for non-existant CPUs.
419		 */
420		for (cpui = 0; cpui < NCPU; cpui++)
421			xc_one(cpui, ac_ecache_flush, 0, 0);
422	}
423
424	list->ac_softsp = NULL;
425
426	/* delete the kstat for this driver. */
427	ac_del_kstats(softsp);
428
429	/* unmap the registers */
430	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0);
431
432	fhc_bdlist_unlock();
433
434	/* Remove the minor nodes. */
435	ddi_remove_minor_node(devi, NULL);
436
437	/* free the soft state structure */
438	ddi_soft_state_free(acp, instance);
439	ddi_prop_remove_all(devi);
440
441	return (DDI_SUCCESS);
442}
443
444/* ARGSUSED */
445static int
446ac_open(dev_t *devp, int flag, int otyp, cred_t *credp)
447{
448	int instance;
449	dev_t dev;
450	struct ac_soft_state *softsp;
451	struct bd_list *board;
452	int vis;
453
454	dev = *devp;
455	instance = AC_GETINSTANCE(getminor(dev));
456	softsp = AC_GETSOFTC(instance);
457
458	/* Is the instance attached? */
459	if (softsp == NULL) {
460#ifdef DEBUG
461		cmn_err(CE_WARN, "ac%d device not attached", instance);
462#endif /* DEBUG */
463		return (ENXIO);
464	}
465
466	/*
467	 * If the board is not configured, hide the memory APs
468	 */
469	board = fhc_bdlist_lock(softsp->board);
470	vis = (board != NULL) && MEM_BOARD_VISIBLE(board);
471	fhc_bdlist_unlock();
472
473	if (!vis)
474		return (ENXIO);
475
476	/* verify that otyp is appropriate */
477	if (otyp != OTYP_CHR) {
478		return (EINVAL);
479	}
480
481	return (DDI_SUCCESS);
482}
483
484/* ARGSUSED */
485static int
486ac_close(dev_t devt, int flag, int otyp, cred_t *credp)
487{
488	struct ac_soft_state *softsp;
489	int instance;
490
491	instance = AC_GETINSTANCE(getminor(devt));
492	softsp = AC_GETSOFTC(instance);
493	ASSERT(softsp != NULL);
494	ac_mem_test_stop_on_close(softsp->board, AC_GETBANK(getminor(devt)));
495	return (DDI_SUCCESS);
496}
497
498static int
499ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
500{
501#ifdef _MULTI_DATAMODEL
502	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
503		ac_cfga_cmd32_t ac_cmd32;
504
505		if (ddi_copyin((void *)arg, &ac_cmd32,
506		    sizeof (ac_cfga_cmd32_t), flag) != 0) {
507			return (EFAULT);
508		}
509		pkt->cmd_cfga.force = ac_cmd32.force;
510		pkt->cmd_cfga.test = ac_cmd32.test;
511		pkt->cmd_cfga.arg = ac_cmd32.arg;
512		pkt->cmd_cfga.errtype = ac_cmd32.errtype;
513		pkt->cmd_cfga.outputstr =
514		    (char *)(uintptr_t)ac_cmd32.outputstr;
515		pkt->cmd_cfga.private =
516		    (void *)(uintptr_t)ac_cmd32.private;
517	} else
518#endif /* _MULTI_DATAMODEL */
519	if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
520	    sizeof (ac_cfga_cmd_t), flag) != 0) {
521		return (EFAULT);
522	}
523	pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
524	return (0);
525}
526
527static int
528ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
529{
530	int ret = TRUE;
531
532#ifdef _MULTI_DATAMODEL
533	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
534
535		if (ddi_copyout(&(pkt->cmd_cfga.errtype),
536		    (void *)&(((ac_cfga_cmd32_t *)arg)->errtype),
537		    sizeof (ac_err_t), flag) != 0) {
538			ret = FALSE;
539		}
540	} else
541#endif
542	if (ddi_copyout(&(pkt->cmd_cfga.errtype),
543	    (void *)&(((ac_cfga_cmd_t *)arg)->errtype),
544	    sizeof (ac_err_t), flag) != 0) {
545		ret = FALSE;
546	}
547
548	if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
549	    (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
550	    SYSC_OUTPUT_LEN, flag) != 0))) {
551			ret = FALSE;
552	}
553
554	kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
555	return (ret);
556}
557
558/* ARGSUSED */
559static int
560ac_ioctl(
561	dev_t devt,
562	int cmd,
563	intptr_t arg,
564	int flag,
565	cred_t *cred_p,
566	int *rval_p)
567{
568	struct ac_soft_state *softsp;
569	ac_cfga_pkt_t cfga_pkt, *pkt;
570	int instance;
571	int retval;
572
573	instance = AC_GETINSTANCE(getminor(devt));
574	softsp = AC_GETSOFTC(instance);
575	if (softsp == NULL) {
576#ifdef DEBUG
577		cmn_err(CE_NOTE, "ac%d device not attached", instance);
578#endif /* DEBUG */
579		return (ENXIO);
580	}
581
582	/*
583	 * Dispose of the easy ones first.
584	 */
585	switch (cmd) {
586	case AC_MEM_ADMIN_VER:
587		/*
588		 * Specify the revision of this ioctl interface driver.
589		 */
590		if (ddi_copyout(&ac_mem_version, (void *)arg,
591		    sizeof (ac_mem_version_t), flag) != 0)
592			return (EFAULT);
593		return (DDI_SUCCESS);
594
595	case AC_MEM_CONFIGURE:
596	case AC_MEM_UNCONFIGURE:
597	case AC_MEM_STAT:
598	case AC_MEM_TEST_START:
599	case AC_MEM_TEST_STOP:
600	case AC_MEM_TEST_READ:
601	case AC_MEM_TEST_WRITE:
602	case AC_MEM_EXERCISE:
603		break;
604
605	default:
606		return (ENOTTY);
607	}
608	if (cmd != AC_MEM_STAT && !fpu_exists) {
609		return (ENOTSUP);
610	}
611
612	pkt = &cfga_pkt;
613	if ((retval = ac_pkt_init(pkt, arg, flag)) != 0)
614		return (retval);
615	pkt->softsp = softsp;
616	pkt->bank = AC_GETBANK(getminor(devt));
617
618	switch (cmd) {
619	case AC_MEM_CONFIGURE:
620		if ((flag & FWRITE) == 0) {
621			retval = EBADF;
622			break;
623		}
624
625		if (pkt->cmd_cfga.private != NULL) {
626			retval = EINVAL;
627			break;
628		}
629		ac_policy_audit_messages(AC_AUDIT_OSTATE_CONFIGURE, pkt);
630		retval = ac_add_memory(pkt);
631		if (!retval)
632			ac_policy_audit_messages(
633			    AC_AUDIT_OSTATE_SUCCEEDED, pkt);
634		else
635			ac_policy_audit_messages(
636			    AC_AUDIT_OSTATE_CONFIGURE_FAILED, pkt);
637		break;
638
639	case AC_MEM_UNCONFIGURE:
640		if ((flag & FWRITE) == 0) {
641			retval = EBADF;
642			break;
643		}
644
645		if (pkt->cmd_cfga.private != NULL) {
646			retval = EINVAL;
647			break;
648		}
649		ac_policy_audit_messages(AC_AUDIT_OSTATE_UNCONFIGURE, pkt);
650		retval = ac_del_memory(pkt);
651		if (!retval) {
652			ac_policy_audit_messages(
653			    AC_AUDIT_OSTATE_SUCCEEDED, pkt);
654		} else
655			ac_policy_audit_messages(
656			    AC_AUDIT_OSTATE_UNCONFIGURE_FAILED, pkt);
657		break;
658
659	case AC_MEM_STAT:
660		/*
661		 * Query usage of a bank of memory.
662		 */
663		retval = ac_mem_stat(pkt, flag);
664		break;
665
666	case AC_MEM_TEST_START:
667		if ((flag & FWRITE) == 0) {
668			retval = EBADF;
669			break;
670		}
671
672		retval = ac_mem_test_start(pkt, flag);
673		break;
674
675	case AC_MEM_TEST_STOP:
676		if ((flag & FWRITE) == 0) {
677			retval = EBADF;
678			break;
679		}
680
681		retval =  ac_mem_test_stop(pkt, flag);
682		break;
683
684	case AC_MEM_TEST_READ:
685		/*
686		 * read a 'page' (or less) of memory safely.
687		 */
688		if ((flag & FWRITE) == 0) {
689			retval = EBADF;
690			break;
691		}
692
693		retval = ac_mem_test_read(pkt, flag);
694		break;
695
696	case AC_MEM_TEST_WRITE:
697		/*
698		 * write a 'page' (or less) of memory safely.
699		 */
700		if ((flag & FWRITE) == 0) {
701			retval = EBADF;
702			break;
703		}
704
705		retval = ac_mem_test_write(pkt, flag);
706		break;
707
708	case AC_MEM_EXERCISE:
709		retval = ac_mem_exercise(pkt, flag);
710		break;
711
712	default:
713		ASSERT(0);
714		retval = ENOTTY;
715		break;
716	}
717
718	if (ac_pkt_fini(pkt, arg, flag) != TRUE)
719		retval = EFAULT;
720
721	return (retval);
722}
723
724static void
725ac_add_kstats(struct ac_soft_state *softsp)
726{
727	struct kstat *ac_ksp, *ac_counters_ksp;
728	struct ac_kstat *ac_named_ksp;
729	struct kstat_named *ac_counters_named_data;
730
731	/*
732	 * create the unix-misc kstat for address controller
733	 * using the board number as the instance.
734	 */
735	if ((ac_ksp = kstat_create("unix", softsp->board,
736	    AC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
737	    sizeof (struct ac_kstat) / sizeof (kstat_named_t),
738	    KSTAT_FLAG_PERSISTENT)) == NULL) {
739		cmn_err(CE_WARN, "ac%d: kstat_create failed",
740		    ddi_get_instance(softsp->dip));
741		return;
742	}
743
744	ac_named_ksp = (struct ac_kstat *)(ac_ksp->ks_data);
745
746	/* initialize the named kstats */
747	kstat_named_init(&ac_named_ksp->ac_memctl,
748	    MEMCTL_KSTAT_NAMED,
749	    KSTAT_DATA_UINT64);
750
751	kstat_named_init(&ac_named_ksp->ac_memdecode0,
752	    MEMDECODE0_KSTAT_NAMED,
753	    KSTAT_DATA_UINT64);
754
755	kstat_named_init(&ac_named_ksp->ac_memdecode1,
756	    MEMDECODE1_KSTAT_NAMED,
757	    KSTAT_DATA_UINT64);
758
759	kstat_named_init(&ac_named_ksp->ac_mccr,
760	    MCCR_KSTAT_NAMED,
761	    KSTAT_DATA_UINT32);
762
763	kstat_named_init(&ac_named_ksp->ac_counter,
764	    CNTR_KSTAT_NAMED,
765	    KSTAT_DATA_UINT64);
766
767	kstat_named_init(&ac_named_ksp->ac_bank0_status,
768	    BANK_0_KSTAT_NAMED,
769	    KSTAT_DATA_CHAR);
770
771	kstat_named_init(&ac_named_ksp->ac_bank1_status,
772	    BANK_1_KSTAT_NAMED,
773	    KSTAT_DATA_CHAR);
774
775	ac_ksp->ks_update = ac_misc_kstat_update;
776	ac_ksp->ks_private = (void *)softsp;
777	softsp->ac_ksp = ac_ksp;
778	kstat_install(ac_ksp);
779
780	/*
781	 * Create the picN kstats if we are the first instance
782	 * to attach. We use ac_attachcnt as a count of how
783	 * many instances have attached. This is protected by
784	 * a mutex.
785	 */
786	mutex_enter(&ac_attachcnt_mutex);
787	if (ac_attachcnt == 0)
788		ac_add_picN_kstats(softsp->dip);
789
790	ac_attachcnt ++;
791	mutex_exit(&ac_attachcnt_mutex);
792
793	/*
794	 * Create the "counter" kstat for each AC instance.
795	 * This provides access to the %pcr and %pic
796	 * registers for that instance.
797	 *
798	 * The size of this kstat is AC_NUM_PICS + 1 for %pcr
799	 */
800	if ((ac_counters_ksp = kstat_create("ac",
801	    ddi_get_instance(softsp->dip), "counters",
802	    "bus", KSTAT_TYPE_NAMED, AC_NUM_PICS + 1,
803	    KSTAT_FLAG_WRITABLE)) == NULL) {
804
805		cmn_err(CE_WARN, "ac%d counters: kstat_create failed",
806		    ddi_get_instance(softsp->dip));
807		return;
808	}
809	ac_counters_named_data =
810	    (struct kstat_named *)(ac_counters_ksp->ks_data);
811
812	/* initialize the named kstats */
813	kstat_named_init(&ac_counters_named_data[0],
814	    "pcr", KSTAT_DATA_UINT64);
815
816	kstat_named_init(&ac_counters_named_data[1],
817	    "pic0", KSTAT_DATA_UINT64);
818
819	kstat_named_init(&ac_counters_named_data[2],
820	    "pic1", KSTAT_DATA_UINT64);
821
822	ac_counters_ksp->ks_update = ac_counters_kstat_update;
823	ac_counters_ksp->ks_private = (void *)softsp;
824	kstat_install(ac_counters_ksp);
825
826	/* update the sofstate */
827	softsp->ac_counters_ksp = ac_counters_ksp;
828}
829
830/*
831 * called from ac_add_kstats() to create a kstat for each %pic
832 * that the AC supports. These (read-only) kstats export the
833 * event names and %pcr masks that each %pic supports.
834 *
835 * if we fail to create any of these kstats we must remove any
836 * that we have already created and return;
837 *
838 * NOTE: because all AC's use the same events we only need to
839 *       create the picN kstats once. All instances can use
840 *       the same picN kstats.
841 *
842 *       The flexibility exists to allow each device specify it's
843 *       own events by creating picN kstats with the instance number
844 *       set to ddi_get_instance(softsp->dip).
845 *
846 *       When searching for a picN kstat for a device you should
847 *       first search for a picN kstat using the instance number
848 *       of the device you are interested in. If that fails you
849 *       should use the first picN kstat found for that device.
850 */
851static void
852ac_add_picN_kstats(dev_info_t *dip)
853{
854	typedef struct ac_event_mask {
855		char *event_name;
856		uint64_t pcr_mask;
857	} ac_event_mask_t;
858
859	/*
860	 * AC Performance Events.
861	 *
862	 * We declare an array of event-names and event-masks.
863	 */
864	ac_event_mask_t ac_events_arr[] = {
865		{"mem_bank0_rds", 0x1}, {"mem_bank0_wrs", 0x2},
866		{"mem_bank0_stall", 0x3}, {"mem_bank1_rds", 0x4},
867		{"mem_bank1_wrs", 0x5}, {"mem_bank1_stall", 0x6},
868		{"clock_cycles", 0x7}, {"addr_pkts", 0x8},
869		{"data_pkts", 0x9}, {"flow_ctl_cyc", 0xa},
870		{"fast_arb_pkts", 0xb}, {"bus_cont_cyc", 0xc},
871		{"data_bus_can", 0xd}, {"ac_addr_pkts", 0xe},
872		{"ac_data_pkts", 0xf}, {"rts_pkts", 0x10},
873		{"rtsa_pkts", 0x11}, {"rto_pkts", 0x12},
874		{"rs_pkts", 0x13}, {"wb_pkts", 0x14},
875		{"ws_pkts", 0x15}, {"rio_pkts", 0x16},
876		{"rbio_pkts", 0x17}, {"wio_pkts", 0x18},
877		{"wbio_pkts", 0x19}, {"upa_a_rds_m", 0x1a},
878		{"upa_a_rdo_v", 0x1b}, {"upa_b_rds_m", 0x1c},
879		{"upa_b_rdo_v", 0x1d}, {"upa_a_preqs_fr", 0x20},
880		{"upa_a_sreqs_to", 0x21}, {"upa_a_preqs_to", 0x22},
881		{"upa_a_rds_fr", 0x23}, {"upa_a_rdsa_fr", 0x24},
882		{"upa_a_rdo_fr", 0x25}, {"upa_a_rdd_fr", 0x26},
883		{"upa_a_rio_rbio", 0x27}, {"upa_a_wio_wbio", 0x28},
884		{"upa_a_cpb_to", 0x29}, {"upa_a_inv_to", 0x2a},
885		{"upa_a_hits_buff", 0x2b}, {"upa_a_wb", 0x2c},
886		{"upa_a_wi", 0x2d}, {"upa_b_preqs_fr", 0x30},
887		{"upa_b_sreqs_to", 0x31}, {"upa_b_preqs_to", 0x32},
888		{"upa_b_rds_fr", 0x33}, {"upa_b_rdsa_fr", 0x34},
889		{"upa_b_rdo_fr", 0x35}, {"upa_b_rdd_fr", 0x36},
890		{"upa_b_rio_rbio", 0x37}, {"upa_b_wio_wbio", 0x38},
891		{"upa_b_cpb_to", 0x39}, {"upa_b_inv_to", 0x3a},
892		{"upa_b_hits_buff", 0x3b}, {"upa_b_wb", 0x3c},
893		{"upa_b_wi", 0x3d}
894	};
895
896#define	AC_NUM_EVENTS sizeof (ac_events_arr) / sizeof (ac_events_arr[0])
897
898	/*
899	 * array of clear masks for each pic.
900	 * These masks are used to clear the %pcr bits for
901	 * each pic.
902	 */
903	ac_event_mask_t ac_clear_pic[AC_NUM_PICS] = {
904		/* pic0 */
905		{"clear_pic", (uint64_t)~(0x3f)},
906		/* pic1 */
907		{"clear_pic", (uint64_t)~(0x3f << 8)}
908	};
909
910	struct kstat_named *ac_pic_named_data;
911	int  		event, pic;
912	char 		pic_name[30];
913	int		instance = ddi_get_instance(dip);
914	int		pic_shift = 0;
915
916	for (pic = 0; pic < AC_NUM_PICS; pic++) {
917		/*
918		 * create the picN kstat. The size of this kstat is
919		 * AC_NUM_EVENTS + 1 for the clear_event_mask
920		 */
921		(void) sprintf(pic_name, "pic%d", pic);	/* pic0, pic1 ... */
922		if ((ac_picN_ksp[pic] = kstat_create("ac",
923		    instance, pic_name, "bus", KSTAT_TYPE_NAMED,
924		    AC_NUM_EVENTS + 1, NULL)) == NULL) {
925
926				cmn_err(CE_WARN, "ac %s: kstat_create failed",
927				    pic_name);
928
929				/* remove pic0 kstat if pic1 create fails */
930				if (pic == 1) {
931					kstat_delete(ac_picN_ksp[0]);
932					ac_picN_ksp[0] = NULL;
933				}
934				return;
935		}
936		ac_pic_named_data =
937		    (struct kstat_named *)(ac_picN_ksp[pic]->ks_data);
938
939		/*
940		 * when we are storing pcr_masks we need to shift bits
941		 * left by 8 for pic1 events.
942		 */
943		if (pic == 1)
944			pic_shift = 8;
945
946		/*
947		 * for each picN event we need to write a kstat record
948		 * (name = EVENT, value.ui64 = PCR_MASK)
949		 */
950		for (event = 0; event < AC_NUM_EVENTS; event ++) {
951
952			/* pcr_mask */
953			ac_pic_named_data[event].value.ui64 =
954			    ac_events_arr[event].pcr_mask << pic_shift;
955
956			/* event-name */
957			kstat_named_init(&ac_pic_named_data[event],
958			    ac_events_arr[event].event_name,
959			    KSTAT_DATA_UINT64);
960		}
961
962		/*
963		 * we add the clear_pic event and mask as the last
964		 * record in the kstat
965		 */
966		/* pcr mask */
967		ac_pic_named_data[AC_NUM_EVENTS].value.ui64 =
968		    ac_clear_pic[pic].pcr_mask;
969
970		/* event-name */
971		kstat_named_init(&ac_pic_named_data[AC_NUM_EVENTS],
972		    ac_clear_pic[pic].event_name,
973		    KSTAT_DATA_UINT64);
974
975		kstat_install(ac_picN_ksp[pic]);
976	}
977}
978
979
980static void
981ac_del_kstats(struct ac_soft_state *softsp)
982{
983	struct kstat *ac_ksp;
984	int pic;
985
986	/* remove "misc" kstat */
987	ac_ksp = softsp->ac_ksp;
988	softsp->ac_ksp = NULL;
989	if (ac_ksp != NULL) {
990		ASSERT(ac_ksp->ks_private == (void *)softsp);
991		kstat_delete(ac_ksp);
992	}
993
994	/* remove "bus" kstat */
995	ac_ksp = softsp->ac_counters_ksp;
996	softsp->ac_counters_ksp = NULL;
997	if (ac_ksp != NULL) {
998		ASSERT(ac_ksp->ks_private == (void *)softsp);
999		kstat_delete(ac_ksp);
1000	}
1001
1002	/*
1003	 * if we are the last instance to detach we need to
1004	 * remove the picN kstats. We use ac_attachcnt as a
1005	 * count of how many instances are still attached. This
1006	 * is protected by a mutex.
1007	 */
1008	mutex_enter(&ac_attachcnt_mutex);
1009	ac_attachcnt --;
1010	if (ac_attachcnt == 0) {
1011		for (pic = 0; pic < AC_NUM_PICS; pic++) {
1012			if (ac_picN_ksp[pic] != (kstat_t *)NULL) {
1013				kstat_delete(ac_picN_ksp[pic]);
1014				ac_picN_ksp[pic] = NULL;
1015			}
1016		}
1017	}
1018	mutex_exit(&ac_attachcnt_mutex);
1019}
1020
1021static enum ac_bank_status
1022ac_kstat_stat(sysc_cfga_rstate_t rst, sysc_cfga_ostate_t ost)
1023{
1024	switch (rst) {
1025	case SYSC_CFGA_RSTATE_EMPTY:
1026		return (StNoMem);
1027	case SYSC_CFGA_RSTATE_DISCONNECTED:
1028		return (StBad);
1029	case SYSC_CFGA_RSTATE_CONNECTED:
1030		switch (ost) {
1031		case SYSC_CFGA_OSTATE_UNCONFIGURED:
1032			return (StSpare);
1033		case SYSC_CFGA_OSTATE_CONFIGURED:
1034			return (StActive);
1035		default:
1036			return (StUnknown);
1037		}
1038	default:
1039		return (StUnknown);
1040	}
1041}
1042
1043static enum ac_bank_condition
1044ac_kstat_cond(sysc_cfga_cond_t cond)
1045{
1046	switch (cond) {
1047	case SYSC_CFGA_COND_UNKNOWN:
1048		return (ConUnknown);
1049	case SYSC_CFGA_COND_OK:
1050		return (ConOK);
1051	case SYSC_CFGA_COND_FAILING:
1052		return (ConFailing);
1053	case SYSC_CFGA_COND_FAILED:
1054		return (ConFailed);
1055	case SYSC_CFGA_COND_UNUSABLE:
1056		return (ConBad);
1057	default:
1058		return (ConUnknown);
1059	}
1060}
1061
1062static int
1063ac_misc_kstat_update(kstat_t *ksp, int rw)
1064{
1065	struct ac_kstat *acksp;
1066	struct ac_soft_state *softsp;
1067
1068	acksp = (struct ac_kstat *)ksp->ks_data;
1069	softsp = (struct ac_soft_state *)ksp->ks_private;
1070	/* Need the NULL check in case kstat is about to be deleted. */
1071	ASSERT(softsp->ac_ksp == NULL || ksp == softsp->ac_ksp);
1072
1073	/* this is a read-only kstat. Bail out on a write */
1074	if (rw == KSTAT_WRITE) {
1075		return (EACCES);
1076	} else {
1077		/*
1078		 * copy the current state of the hardware into the
1079		 * kstat structure.
1080		 */
1081		acksp->ac_memctl.value.ui64 = *softsp->ac_memctl;
1082		acksp->ac_memdecode0.value.ui64 = *softsp->ac_memdecode0;
1083		acksp->ac_memdecode1.value.ui64 = *softsp->ac_memdecode1;
1084		acksp->ac_mccr.value.ui32 = *softsp->ac_mccr;
1085		acksp->ac_counter.value.ui64 = *softsp->ac_counter;
1086		acksp->ac_bank0_status.value.c[0] =
1087		    ac_kstat_stat(softsp->bank[0].rstate,
1088		    softsp->bank[0].ostate);
1089		acksp->ac_bank0_status.value.c[1] =
1090		    ac_kstat_cond(softsp->bank[0].condition);
1091		acksp->ac_bank1_status.value.c[0] =
1092		    ac_kstat_stat(softsp->bank[1].rstate,
1093		    softsp->bank[1].ostate);
1094		acksp->ac_bank1_status.value.c[1] =
1095		    ac_kstat_cond(softsp->bank[1].condition);
1096	}
1097	return (0);
1098}
1099
1100static int
1101ac_counters_kstat_update(kstat_t *ksp, int rw)
1102{
1103	struct kstat_named *ac_counters_data;
1104	struct ac_soft_state *softsp;
1105	uint64_t pic_register;
1106
1107	ac_counters_data = (struct kstat_named *)ksp->ks_data;
1108	softsp = (struct ac_soft_state *)ksp->ks_private;
1109
1110	/*
1111	 * We need to start/restart the ac_timeout that will
1112	 * return the AC counters to hot-plug mode after the
1113	 * ac_hot_plug_timeout_interval has expired. We tell
1114	 * ac_reset_timeout() whether this is a kstat_read or a
1115	 * kstat_write call. If this fails we reject the kstat
1116	 * operation.
1117	 */
1118	if (ac_reset_timeout(rw) != 0)
1119		return (-1);
1120
1121
1122	if (rw == KSTAT_WRITE) {
1123		/*
1124		 * Write the %pcr value to the softsp->ac_mccr.
1125		 * This interface does not support writing to the
1126		 * %pic.
1127		 */
1128		*softsp->ac_mccr =
1129		    (uint32_t)ac_counters_data[0].value.ui64;
1130	} else {
1131		/*
1132		 * Read %pcr and %pic register values and write them
1133		 * into counters kstat.
1134		 */
1135
1136		/* pcr */
1137		ac_counters_data[0].value.ui64 = *softsp->ac_mccr;
1138
1139		pic_register = *softsp->ac_counter;
1140		/*
1141		 * ac pic register:
1142		 *  (63:32) = pic1
1143		 *  (31:00) = pic0
1144		 */
1145
1146		/* pic0 */
1147		ac_counters_data[1].value.ui64 =
1148		    AC_COUNTER_TO_PIC0(pic_register);
1149		/* pic1 */
1150		ac_counters_data[2].value.ui64 =
1151		    AC_COUNTER_TO_PIC1(pic_register);
1152	}
1153	return (0);
1154}
1155
1156/*
1157 * Decode the memory state given to us and plug it into the soft state
1158 */
1159static void
1160ac_get_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1161{
1162	char	*property = (id == Bank0) ? AC_BANK0_STATUS : AC_BANK1_STATUS;
1163	char	*propval;
1164	int	proplen;
1165	uint64_t memdec = (id == Bank0) ?
1166	    *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1167	uint_t		grp_size;
1168
1169	softsp->bank[id].busy = 0;
1170	softsp->bank[id].status_change = ddi_get_time();
1171
1172	if (GRP_SIZE_IS_SET(memdec)) {
1173		grp_size = GRP_SPANMB(memdec);
1174
1175		/* determine the memory bank size (in MB) */
1176		softsp->bank[id].real_size = softsp->bank[id].use_size =
1177		    (id == Bank0) ? (grp_size / INTLV0(*softsp->ac_memctl)) :
1178		    (grp_size / INTLV1(*softsp->ac_memctl));
1179	} else {
1180		softsp->bank[id].real_size = softsp->bank[id].use_size = 0;
1181	}
1182
1183	/*
1184	 * decode the memory bank property.  set condition based
1185	 * on the values.
1186	 */
1187	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
1188	    DDI_PROP_DONTPASS, property, (caddr_t)&propval, &proplen) ==
1189	    DDI_PROP_SUCCESS) {
1190		if (strcmp(propval, AC_BANK_NOMEM) == 0) {
1191			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1192			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1193			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1194		} else if (strcmp(propval, AC_BANK_OK) == 0) {
1195			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1196			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1197			softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1198		} else if (strcmp(propval, AC_BANK_SPARE) == 0) {
1199			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1200			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1201			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1202		} else if (strcmp(propval, AC_BANK_FAILED) == 0) {
1203			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1204			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1205			softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1206		} else {
1207			cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1208			    "unknown %smemory state [%s]",
1209			    ddi_get_instance(softsp->dip), softsp->board, id,
1210			    (memdec & AC_MEM_VALID) ? "connected " : "",
1211			    propval);
1212			if (memdec & AC_MEM_VALID) {
1213				softsp->bank[id].rstate =
1214				    SYSC_CFGA_RSTATE_CONNECTED;
1215				softsp->bank[id].ostate =
1216				    SYSC_CFGA_OSTATE_CONFIGURED;
1217				softsp->bank[id].condition =
1218				    SYSC_CFGA_COND_OK;
1219			} else {
1220				softsp->bank[id].rstate =
1221				    SYSC_CFGA_RSTATE_DISCONNECTED;
1222				softsp->bank[id].ostate =
1223				    SYSC_CFGA_OSTATE_UNCONFIGURED;
1224				softsp->bank[id].condition =
1225				    SYSC_CFGA_COND_UNUSABLE;
1226			}
1227		}
1228
1229		kmem_free(propval, proplen);
1230	} else {
1231		/* we don't have the property, deduce the state of memory */
1232		if (memdec & AC_MEM_VALID) {
1233			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1234			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1235			softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1236		} else {
1237			/* could be an i/o board... */
1238			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1239			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1240			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1241		}
1242	}
1243
1244	/* we assume that all other bank statuses are NOT valid */
1245	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1246		if ((memdec & AC_MEM_VALID) != 0) {
1247			uint64_t	base_pa;
1248
1249			ASSERT((*softsp->ac_memctl & AC_CSR_REFEN) != 0);
1250			/* register existence in the memloc database */
1251			base_pa = GRP_REALBASE(memdec);
1252			fhc_add_memloc(softsp->board, base_pa, grp_size);
1253		}
1254	}
1255}
1256
1257static void
1258ac_eval_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1259{
1260	uint64_t memdec = (id == Bank0) ?
1261	    *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1262	uint64_t	base_pa;
1263
1264	/*
1265	 * Downgrade the status of any bank that did not get
1266	 * programmed.
1267	 */
1268	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED &&
1269	    softsp->bank[id].ostate == SYSC_CFGA_OSTATE_UNCONFIGURED &&
1270	    (memdec & AC_MEM_VALID) == 0) {
1271		cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1272		    "spare memory bank not valid - it was ",
1273		    ddi_get_instance(softsp->dip), softsp->board, id);
1274		cmn_err(CE_WARN, "misconfigured by the system "
1275		    "firmware.  Disabling...");
1276		softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1277		softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1278		softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1279	}
1280	/*
1281	 * Log a message about good banks.
1282	 */
1283	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1284		ASSERT((memdec & AC_MEM_VALID) != 0);
1285		base_pa = GRP_REALBASE(memdec);
1286
1287		cmn_err(CE_CONT, "?ac%d board %d bank %d: "
1288		    "base 0x%" PRIx64 " size %dmb rstate %d "
1289		    "ostate %d condition %d\n",
1290		    ddi_get_instance(softsp->dip),
1291		    softsp->board, id, base_pa, softsp->bank[id].real_size,
1292		    softsp->bank[id].rstate, softsp->bank[id].ostate,
1293		    softsp->bank[id].condition);
1294	}
1295}
1296
1297/*ARGSUSED*/
1298static void
1299ac_ecache_flush(uint64_t a, uint64_t b)
1300{
1301	cpu_flush_ecache();
1302}
1303
1304static char *
1305ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event)
1306{
1307	char *type_str;
1308
1309	switch (ostate) {
1310	case SYSC_CFGA_OSTATE_UNCONFIGURED:
1311		switch (event) {
1312		case AC_AUDIT_OSTATE_UNCONFIGURE:
1313			type_str = "unconfiguring";
1314			break;
1315		case AC_AUDIT_OSTATE_SUCCEEDED:
1316		case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1317			type_str = "unconfigured";
1318			break;
1319		default:
1320			type_str = "unconfigure?";
1321			break;
1322		}
1323		break;
1324	case SYSC_CFGA_OSTATE_CONFIGURED:
1325		switch (event) {
1326		case AC_AUDIT_OSTATE_CONFIGURE:
1327			type_str = "configuring";
1328			break;
1329		case AC_AUDIT_OSTATE_SUCCEEDED:
1330		case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1331			type_str = "configured";
1332			break;
1333		default:
1334			type_str = "configure?";
1335			break;
1336		}
1337		break;
1338
1339	default:
1340		type_str = "undefined occupant state";
1341		break;
1342	}
1343	return (type_str);
1344}
1345
1346static void
1347ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt)
1348{
1349	struct ac_soft_state *softsp = pkt->softsp;
1350
1351	switch (event) {
1352		case AC_AUDIT_OSTATE_CONFIGURE:
1353			cmn_err(CE_NOTE,
1354			    "%s memory bank %d in slot %d",
1355			    ac_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
1356			    event), pkt->bank,
1357			    softsp->board);
1358			break;
1359		case AC_AUDIT_OSTATE_UNCONFIGURE:
1360			cmn_err(CE_NOTE,
1361			    "%s memory bank %d in slot %d",
1362			    ac_ostate_typestr(
1363			    SYSC_CFGA_OSTATE_UNCONFIGURED,
1364			    event), pkt->bank,
1365			    softsp->board);
1366			break;
1367		case AC_AUDIT_OSTATE_SUCCEEDED:
1368			cmn_err(CE_NOTE,
1369			    "memory bank %d in slot %d is %s",
1370			    pkt->bank, softsp->board,
1371			    ac_ostate_typestr(
1372			    softsp->bank[pkt->bank].ostate,
1373			    event));
1374			break;
1375		case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1376			cmn_err(CE_NOTE,
1377			"memory bank %d in slot %d not %s",
1378			    pkt->bank,
1379			    softsp->board,
1380			    ac_ostate_typestr(
1381			    SYSC_CFGA_OSTATE_CONFIGURED,
1382			    event));
1383			break;
1384		case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1385			cmn_err(CE_NOTE,
1386			    "memory bank %d in slot %d not %s",
1387			    pkt->bank,
1388			    softsp->board,
1389			    ac_ostate_typestr(
1390			    SYSC_CFGA_OSTATE_UNCONFIGURED,
1391			    event));
1392			break;
1393		default:
1394			cmn_err(CE_NOTE,
1395			    "unknown audit of memory bank %d in slot %d",
1396			    pkt->bank, softsp->board);
1397			break;
1398	}
1399}
1400
1401#include <vm/page.h>
1402#include <vm/hat.h>
1403
1404static int
1405ac_mem_exercise(ac_cfga_pkt_t *pkt, int flag)
1406{
1407	struct ac_mem_info *mem_info;
1408	pfn_t base;
1409	pgcnt_t npgs;
1410
1411	mem_info = &pkt->softsp->bank[pkt->bank];
1412	if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1413		uint64_t base_pa, bank_size;
1414		uint64_t decode;
1415
1416		decode = (pkt->bank == Bank0) ?
1417		    *pkt->softsp->ac_memdecode0 : *pkt->softsp->ac_memdecode1;
1418		base_pa = GRP_REALBASE(decode);
1419		bank_size = GRP_UK2SPAN(decode);
1420
1421		base = base_pa >> PAGESHIFT;
1422		npgs = bank_size >> PAGESHIFT;
1423	} else {
1424		base = 0;
1425		npgs = 0;
1426	}
1427	switch (pkt->cmd_cfga.arg) {
1428	case AC_MEMX_RELOCATE_ALL: {
1429		pfn_t pfn, pglim;
1430		struct ac_memx_relocate_stats rstat;
1431
1432		if (npgs == 0 ||
1433		    mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
1434			return (EINVAL);
1435		}
1436		if (mem_info->busy != FALSE) {
1437			return (EBUSY);
1438		}
1439		bzero(&rstat, sizeof (rstat));
1440		rstat.base = (uint_t)base;
1441		rstat.npgs = (uint_t)npgs;
1442		pglim = base + npgs;
1443		for (pfn = base; pfn < pglim; pfn++) {
1444			page_t *pp, *pp_repl;
1445
1446		retry:
1447			pp = page_numtopp_nolock(pfn);
1448			if (pp != NULL) {
1449				if (!page_trylock(pp, SE_EXCL)) {
1450					pp = NULL;
1451					rstat.nolock++;
1452				}
1453				if (pp != NULL && page_pptonum(pp) != pfn) {
1454					page_unlock(pp);
1455					goto retry;
1456				}
1457			} else {
1458				rstat.nopaget++;
1459			}
1460			if (pp != NULL && PP_ISFREE(pp)) {
1461				page_unlock(pp);
1462				rstat.isfree++;
1463				pp = NULL;
1464			}
1465			if (pp != NULL) {
1466				spgcnt_t npgs;
1467				int result;
1468
1469				pp_repl = NULL;
1470				result = page_relocate(&pp, &pp_repl, 1, 1,
1471				    &npgs, NULL);
1472				if (result == 0) {
1473					while (npgs-- > 0) {
1474						page_t *tpp;
1475
1476						ASSERT(pp_repl != NULL);
1477						tpp = pp_repl;
1478						page_sub(&pp_repl, tpp);
1479						page_unlock(tpp);
1480					}
1481
1482					rstat.reloc++;
1483				} else {
1484					page_unlock(pp);
1485					rstat.noreloc++;
1486				}
1487			}
1488		}
1489		if (pkt->cmd_cfga.private != NULL && ddi_copyout(&rstat,
1490		    pkt->cmd_cfga.private, sizeof (rstat), flag) != 0)
1491			return (EFAULT);
1492		return (DDI_SUCCESS);
1493	}
1494
1495	default:
1496		return (EINVAL);
1497	}
1498}
1499
1500static int
1501ac_reset_timeout(int rw)
1502{
1503	mutex_enter(&ac_hot_plug_mode_mutex);
1504
1505	if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1506	    (rw == KSTAT_READ)) {
1507		/*
1508		 * We are in hot-plug mode. A kstat_read is not
1509		 * going to affect this. return 0 to allow the
1510		 * kstat_read to continue.
1511		 */
1512		mutex_exit(&ac_hot_plug_mode_mutex);
1513		return (0);
1514
1515	} else if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1516	    (rw == KSTAT_WRITE)) {
1517		/*
1518		 * There are no pending timeouts and we have received a
1519		 * kstat_write request so we must be transitioning
1520		 * from "hot-plug" mode to non "hot-plug" mode.
1521		 * Try to lock all boards before allowing the kstat_write.
1522		 */
1523		if (ac_enter_transition() == TRUE)
1524			fhc_bdlist_unlock();
1525		else {
1526			/* cannot lock boards so fail */
1527			mutex_exit(&ac_hot_plug_mode_mutex);
1528			return (-1);
1529		}
1530
1531		/*
1532		 * We need to display a Warning about hot-plugging any
1533		 * boards. This message is only needed when we are
1534		 * transitioning out of "hot-plug" mode.
1535		 */
1536		cmn_err(CE_WARN, "This machine is being taken out of "
1537		    "hot-plug mode.");
1538		cmn_err(CE_CONT, "Do not attempt to hot-plug boards "
1539		    "or power supplies in this system until further notice.");
1540
1541	} else if (ac_hot_plug_timeout != (timeout_id_t)NULL) {
1542		/*
1543		 * There is a pending timeout so we must already be
1544		 * in non "hot-plug" mode. It doesn't matter if the
1545		 * kstat request is a read or a write.
1546		 *
1547		 * We need to cancel the existing timeout.
1548		 */
1549		(void) untimeout(ac_hot_plug_timeout);
1550		ac_hot_plug_timeout = NULL;
1551	}
1552
1553	/*
1554	 * create a new timeout.
1555	 */
1556	ac_hot_plug_timeout = timeout(ac_timeout, NULL,
1557	    drv_usectohz(ac_hot_plug_timeout_interval * 1000000));
1558
1559	mutex_exit(&ac_hot_plug_mode_mutex);
1560	return (0);
1561}
1562
1563static void
1564ac_timeout(void *arg)
1565{
1566	struct ac_soft_state *softsp;
1567	fhc_bd_t	*board;
1568
1569#ifdef lint
1570	arg = arg;
1571#endif /* lint */
1572
1573	ac_hot_plug_timeout = (timeout_id_t)NULL;
1574
1575	(void) fhc_bdlist_lock(-1);
1576
1577	/*
1578	 * Foreach ac in the board list we need to
1579	 * re-program the pcr into "hot-plug" mode.
1580	 * We also program the pic register with the
1581	 * bus pause timing
1582	 */
1583	board = fhc_bd_first();
1584	while (board != NULL) {
1585		softsp = board->ac_softsp;
1586		if (softsp == NULL) {
1587			/*
1588			 * This board must not have an AC.
1589			 * Skip it and move on.
1590			 */
1591			board = fhc_bd_next(board);
1592			continue;
1593		}
1594		/* program the pcr into hot-plug mode */
1595		*softsp->ac_mccr = AC_CLEAR_PCR(*softsp->ac_mccr);
1596		*softsp->ac_mccr = AC_SET_HOT_PLUG(*softsp->ac_mccr);
1597
1598		/* program the pic with the bus pause time value */
1599		*softsp->ac_counter = AC_SET_PIC_BUS_PAUSE(softsp->board);
1600
1601		/* get the next board */
1602		board = fhc_bd_next(board);
1603	}
1604
1605	ac_exit_transition();
1606
1607	fhc_bdlist_unlock();
1608
1609	/*
1610	 * It is now safe to start hot-plugging again. We need
1611	 * to display a message.
1612	 */
1613	cmn_err(CE_NOTE, "This machine is now in hot-plug mode.");
1614	cmn_err(CE_CONT, "Board and power supply hot-plug operations "
1615	    "can be resumed.");
1616}
1617
1618/*
1619 * This function will acquire the lock and set the in_transition
1620 * bit for all the slots.  If the slots are being used,
1621 * we return FALSE; else set in_transition and return TRUE.
1622 */
1623static int
1624ac_enter_transition(void)
1625{
1626	fhc_bd_t	*list;
1627	sysc_cfga_stat_t *sysc_stat_lk;
1628
1629	/* mutex lock the structure */
1630	(void) fhc_bdlist_lock(-1);
1631
1632	list = fhc_bd_clock();
1633
1634	/* change the in_transition bit */
1635	sysc_stat_lk = &list->sc;
1636	if (sysc_stat_lk->in_transition == TRUE) {
1637		fhc_bdlist_unlock();
1638		return (FALSE);
1639	} else {
1640		sysc_stat_lk->in_transition = TRUE;
1641		return (TRUE);
1642	}
1643}
1644
1645/*
1646 * clear the in_transition bit for all the slots.
1647 */
1648static void
1649ac_exit_transition(void)
1650{
1651	fhc_bd_t	*list;
1652	sysc_cfga_stat_t *sysc_stat_lk;
1653
1654	ASSERT(fhc_bdlist_locked());
1655
1656	list = fhc_bd_clock();
1657
1658	sysc_stat_lk = &list->sc;
1659	ASSERT(sysc_stat_lk->in_transition == TRUE);
1660	sysc_stat_lk->in_transition = FALSE;
1661}
1662