xref: /illumos-gate/usr/src/uts/sun4u/sunfire/io/ac.c (revision a07094369b21309434206d9b3601d162693466fc)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/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 };
147 
148 /*
149  * Driver globals
150  */
151 void *acp;				/* ac soft state hook */
152 static kstat_t	*ac_picN_ksp[AC_NUM_PICS];	/* performance picN kstats */
153 static int	ac_attachcnt = 0;	/* number of instances attached */
154 static kmutex_t ac_attachcnt_mutex;	/* ac_attachcnt lock - attach/detach */
155 static kmutex_t ac_hot_plug_mode_mutex;
156 static timeout_id_t	ac_hot_plug_timeout;
157 static 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 
162 extern struct mod_ops mod_driverops;
163 
164 static struct modldrv modldrv = {
165 	&mod_driverops,		/* Type of module.  This one is a driver */
166 	"AC Leaf v%I%",		/* name of module */
167 	&ac_ops,		/* driver ops */
168 };
169 
170 static struct modlinkage modlinkage = {
171 	MODREV_1,
172 	(void *)&modldrv,
173 	NULL
174 };
175 
176 #ifndef lint
177 char _depends_on[] = "drv/fhc";
178 #endif	/* lint */
179 
180 /*
181  * These are the module initialization routines.
182  */
183 
184 int
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 
203 int
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 
216 int
217 _info(struct modinfo *modinfop)
218 {
219 	return (mod_info(&modlinkage, modinfop));
220 }
221 
222 /* ARGSUSED */
223 static int
224 ac_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 
238 static int
239 ac_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 
354 bad:
355 	ddi_soft_state_free(acp, instance);
356 	return (DDI_FAILURE);
357 }
358 
359 /* ARGSUSED */
360 static int
361 ac_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 */
445 static int
446 ac_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 */
485 static int
486 ac_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 
498 static int
499 ac_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 
527 static int
528 ac_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 */
559 static int
560 ac_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 
724 static void
725 ac_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  */
851 static void
852 ac_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 
980 static void
981 ac_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 
1021 static enum ac_bank_status
1022 ac_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 
1043 static enum ac_bank_condition
1044 ac_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 
1062 static int
1063 ac_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 
1100 static int
1101 ac_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  */
1159 static void
1160 ac_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 
1257 static void
1258 ac_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*/
1298 static void
1299 ac_ecache_flush(uint64_t a, uint64_t b)
1300 {
1301 	cpu_flush_ecache();
1302 }
1303 
1304 static char *
1305 ac_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 
1346 static void
1347 ac_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 
1404 static int
1405 ac_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 
1500 static int
1501 ac_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 
1563 static void
1564 ac_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  */
1623 static int
1624 ac_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  */
1648 static void
1649 ac_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