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