xref: /titanic_51/usr/src/uts/sun4u/sunfire/io/ac.c (revision 89b43686db1fe9681d80a7cf5662730cb9378cae)
129949e86Sstevel /*
229949e86Sstevel  * CDDL HEADER START
329949e86Sstevel  *
429949e86Sstevel  * The contents of this file are subject to the terms of the
529949e86Sstevel  * Common Development and Distribution License (the "License").
629949e86Sstevel  * You may not use this file except in compliance with the License.
729949e86Sstevel  *
829949e86Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929949e86Sstevel  * or http://www.opensolaris.org/os/licensing.
1029949e86Sstevel  * See the License for the specific language governing permissions
1129949e86Sstevel  * and limitations under the License.
1229949e86Sstevel  *
1329949e86Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1429949e86Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529949e86Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1629949e86Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1729949e86Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1829949e86Sstevel  *
1929949e86Sstevel  * CDDL HEADER END
2029949e86Sstevel  */
2129949e86Sstevel 
2229949e86Sstevel /*
2307d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2429949e86Sstevel  * Use is subject to license terms.
25*89b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
2629949e86Sstevel  */
2729949e86Sstevel 
2829949e86Sstevel 
2929949e86Sstevel #include <sys/types.h>
3029949e86Sstevel #include <sys/conf.h>
3129949e86Sstevel #include <sys/ddi.h>
3229949e86Sstevel #include <sys/sunddi.h>
3329949e86Sstevel #include <sys/ddi_impldefs.h>
3429949e86Sstevel #include <sys/obpdefs.h>
3529949e86Sstevel #include <sys/cmn_err.h>
3629949e86Sstevel #include <sys/errno.h>
3729949e86Sstevel #include <sys/kmem.h>
3829949e86Sstevel #include <sys/debug.h>
3929949e86Sstevel #include <sys/sysmacros.h>
4029949e86Sstevel #include <sys/machsystm.h>
4129949e86Sstevel #include <vm/hat_sfmmu.h>
4229949e86Sstevel #include <sys/autoconf.h>
4329949e86Sstevel #include <sys/open.h>
4429949e86Sstevel #include <sys/stat.h>
4529949e86Sstevel #include <sys/modctl.h>
4629949e86Sstevel #include <sys/fhc.h>
4729949e86Sstevel #include <sys/ac.h>
4829949e86Sstevel #include <sys/cpu_module.h>
4929949e86Sstevel #include <sys/x_call.h>
5029949e86Sstevel #include <sys/fpu/fpusystm.h>
5129949e86Sstevel #include <sys/lgrp.h>
5229949e86Sstevel 
5329949e86Sstevel /* Useful debugging Stuff */
5429949e86Sstevel #include <sys/nexusdebug.h>
5529949e86Sstevel 
5629949e86Sstevel /*
5729949e86Sstevel  * Function prototypes
5829949e86Sstevel  */
5929949e86Sstevel 
6029949e86Sstevel static int ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
6129949e86Sstevel 		void **result);
6229949e86Sstevel static int ac_attach(dev_info_t *, ddi_attach_cmd_t);
6329949e86Sstevel static int ac_detach(dev_info_t *, ddi_detach_cmd_t);
6429949e86Sstevel static int ac_open(dev_t *, int, int, cred_t *);
6529949e86Sstevel static int ac_close(dev_t, int, int, cred_t *);
6629949e86Sstevel static int ac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
6729949e86Sstevel 
6829949e86Sstevel static void ac_add_kstats(struct ac_soft_state *);
6929949e86Sstevel static void ac_del_kstats(struct ac_soft_state *);
7029949e86Sstevel static int ac_misc_kstat_update(kstat_t *, int);
7129949e86Sstevel static void ac_add_picN_kstats(dev_info_t *dip);
7229949e86Sstevel static int ac_counters_kstat_update(kstat_t *, int);
7329949e86Sstevel static void ac_get_memory_status(struct ac_soft_state *, enum ac_bank_id);
7429949e86Sstevel static void ac_eval_memory_status(struct ac_soft_state *, enum ac_bank_id);
7529949e86Sstevel static void ac_ecache_flush(uint64_t, uint64_t);
7629949e86Sstevel static int ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
7729949e86Sstevel static int ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
7829949e86Sstevel static int ac_reset_timeout(int rw);
7929949e86Sstevel static void ac_timeout(void *);
8029949e86Sstevel static int ac_enter_transition(void);
8129949e86Sstevel static void ac_exit_transition(void);
8229949e86Sstevel 
8329949e86Sstevel 
8429949e86Sstevel int ac_add_memory(ac_cfga_pkt_t *);
8529949e86Sstevel int ac_del_memory(ac_cfga_pkt_t *);
8629949e86Sstevel int ac_mem_stat(ac_cfga_pkt_t *, int);
8729949e86Sstevel int ac_mem_test_start(ac_cfga_pkt_t *, int);
8829949e86Sstevel int ac_mem_test_stop(ac_cfga_pkt_t *, int);
8929949e86Sstevel int ac_mem_test_read(ac_cfga_pkt_t *, int);
9029949e86Sstevel int ac_mem_test_write(ac_cfga_pkt_t *, int);
9129949e86Sstevel void ac_mem_test_stop_on_close(uint_t, uint_t);
9229949e86Sstevel /*
9329949e86Sstevel  * ac audit message events
9429949e86Sstevel  */
9529949e86Sstevel typedef enum {
9629949e86Sstevel 	AC_AUDIT_OSTATE_CONFIGURE,
9729949e86Sstevel 	AC_AUDIT_OSTATE_UNCONFIGURE,
9829949e86Sstevel 	AC_AUDIT_OSTATE_SUCCEEDED,
9929949e86Sstevel 	AC_AUDIT_OSTATE_CONFIGURE_FAILED,
10029949e86Sstevel 	AC_AUDIT_OSTATE_UNCONFIGURE_FAILED
10129949e86Sstevel } ac_audit_evt_t;
10229949e86Sstevel static void ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt);
10329949e86Sstevel static char *ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event);
10429949e86Sstevel 
10529949e86Sstevel /* The memory ioctl interface version of this driver. */
10629949e86Sstevel static ac_mem_version_t ac_mem_version = AC_MEM_ADMIN_VERSION;
10729949e86Sstevel 
10829949e86Sstevel static int ac_mem_exercise(ac_cfga_pkt_t *, int);
10929949e86Sstevel 
11029949e86Sstevel /*
11129949e86Sstevel  * Configuration data structures
11229949e86Sstevel  */
11329949e86Sstevel static struct cb_ops ac_cb_ops = {
11429949e86Sstevel 	ac_open,			/* open */
11529949e86Sstevel 	ac_close,			/* close */
11629949e86Sstevel 	nulldev,			/* strategy */
11729949e86Sstevel 	nulldev,			/* print */
11829949e86Sstevel 	nodev,				/* dump */
11929949e86Sstevel 	nulldev,			/* read */
12029949e86Sstevel 	nulldev,			/* write */
12129949e86Sstevel 	ac_ioctl,			/* ioctl */
12229949e86Sstevel 	nodev,				/* devmap */
12329949e86Sstevel 	nodev,				/* mmap */
12429949e86Sstevel 	nodev,				/* segmap */
12529949e86Sstevel 	nochpoll,			/* poll */
12629949e86Sstevel 	ddi_prop_op,			/* cb_prop_op */
12729949e86Sstevel 	0,				/* streamtab */
12829949e86Sstevel 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
12929949e86Sstevel 	CB_REV,				/* rev */
13029949e86Sstevel 	nodev,				/* cb_aread */
13129949e86Sstevel 	nodev				/* cb_awrite */
13229949e86Sstevel };
13329949e86Sstevel 
13429949e86Sstevel static struct dev_ops ac_ops = {
13529949e86Sstevel 	DEVO_REV,			/* devo_rev, */
13629949e86Sstevel 	0,				/* refcnt */
13729949e86Sstevel 	ac_info,			/* getinfo */
13829949e86Sstevel 	nulldev,			/* identify */
13929949e86Sstevel 	nulldev,			/* probe */
14029949e86Sstevel 	ac_attach,			/* attach */
14129949e86Sstevel 	ac_detach,			/* detach */
14229949e86Sstevel 	nulldev,			/* reset */
14329949e86Sstevel 	&ac_cb_ops,			/* cb_ops */
14429949e86Sstevel 	(struct bus_ops *)0,		/* bus_ops */
14519397407SSherry Moore 	nulldev,			/* power */
14619397407SSherry Moore 	ddi_quiesce_not_needed,			/* quiesce */
14729949e86Sstevel };
14829949e86Sstevel 
14929949e86Sstevel /*
15029949e86Sstevel  * Driver globals
15129949e86Sstevel  */
15229949e86Sstevel void *acp;				/* ac soft state hook */
15329949e86Sstevel static kstat_t	*ac_picN_ksp[AC_NUM_PICS];	/* performance picN kstats */
15429949e86Sstevel static int	ac_attachcnt = 0;	/* number of instances attached */
15529949e86Sstevel static kmutex_t ac_attachcnt_mutex;	/* ac_attachcnt lock - attach/detach */
15629949e86Sstevel static kmutex_t ac_hot_plug_mode_mutex;
15729949e86Sstevel static timeout_id_t	ac_hot_plug_timeout;
15829949e86Sstevel static int		ac_hot_plug_timeout_interval = 10;
15929949e86Sstevel 
16029949e86Sstevel #define	AC_GETSOFTC(I) \
16129949e86Sstevel 	((struct ac_soft_state *)ddi_get_soft_state(acp, (I)))
16229949e86Sstevel 
16329949e86Sstevel extern struct mod_ops mod_driverops;
16429949e86Sstevel 
16529949e86Sstevel static struct modldrv modldrv = {
16629949e86Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
16719397407SSherry Moore 	"AC Leaf",		/* name of module */
16829949e86Sstevel 	&ac_ops,		/* driver ops */
16929949e86Sstevel };
17029949e86Sstevel 
17129949e86Sstevel static struct modlinkage modlinkage = {
17229949e86Sstevel 	MODREV_1,
17329949e86Sstevel 	(void *)&modldrv,
17429949e86Sstevel 	NULL
17529949e86Sstevel };
17629949e86Sstevel 
17729949e86Sstevel /*
17829949e86Sstevel  * These are the module initialization routines.
17929949e86Sstevel  */
18029949e86Sstevel 
18129949e86Sstevel int
18229949e86Sstevel _init(void)
18329949e86Sstevel {
18429949e86Sstevel 	int error;
18529949e86Sstevel 
18629949e86Sstevel 	if ((error = ddi_soft_state_init(&acp, sizeof (struct ac_soft_state),
18729949e86Sstevel 	    1)) != 0)
18829949e86Sstevel 		return (error);
18929949e86Sstevel 
19029949e86Sstevel 	if ((error = mod_install(&modlinkage)) != 0) {
19129949e86Sstevel 		ddi_soft_state_fini(&acp);
19229949e86Sstevel 		return (error);
19329949e86Sstevel 	}
19429949e86Sstevel 	/* Initialize global mutex */
19529949e86Sstevel 	mutex_init(&ac_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
19629949e86Sstevel 	mutex_init(&ac_hot_plug_mode_mutex, NULL, MUTEX_DRIVER, NULL);
19729949e86Sstevel 	return (0);
19829949e86Sstevel }
19929949e86Sstevel 
20029949e86Sstevel int
20129949e86Sstevel _fini(void)
20229949e86Sstevel {
20329949e86Sstevel 	int error;
20429949e86Sstevel 
20529949e86Sstevel 	if ((error = mod_remove(&modlinkage)) == 0) {
20629949e86Sstevel 		ddi_soft_state_fini(&acp);
20729949e86Sstevel 		mutex_destroy(&ac_attachcnt_mutex);
20829949e86Sstevel 		mutex_destroy(&ac_hot_plug_mode_mutex);
20929949e86Sstevel 	}
21029949e86Sstevel 	return (error);
21129949e86Sstevel }
21229949e86Sstevel 
21329949e86Sstevel int
21429949e86Sstevel _info(struct modinfo *modinfop)
21529949e86Sstevel {
21629949e86Sstevel 	return (mod_info(&modlinkage, modinfop));
21729949e86Sstevel }
21829949e86Sstevel 
21929949e86Sstevel /* ARGSUSED */
22029949e86Sstevel static int
22129949e86Sstevel ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
22229949e86Sstevel {
22329949e86Sstevel 	dev_t	dev;
22429949e86Sstevel 	int	instance;
22529949e86Sstevel 
22629949e86Sstevel 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
22729949e86Sstevel 		dev = (dev_t)arg;
22829949e86Sstevel 		instance = AC_GETINSTANCE(getminor(dev));
22929949e86Sstevel 		*result = (void *)(uintptr_t)instance;
23029949e86Sstevel 		return (DDI_SUCCESS);
23129949e86Sstevel 	}
23229949e86Sstevel 	return (DDI_FAILURE);
23329949e86Sstevel }
23429949e86Sstevel 
23529949e86Sstevel static int
23629949e86Sstevel ac_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
23729949e86Sstevel {
23829949e86Sstevel 	int instance;
23929949e86Sstevel 	struct ac_soft_state *softsp;
24029949e86Sstevel 	struct bd_list *list = NULL;
24129949e86Sstevel 
24229949e86Sstevel 	switch (cmd) {
24329949e86Sstevel 	case DDI_ATTACH:
24429949e86Sstevel 		break;
24529949e86Sstevel 
24629949e86Sstevel 	case DDI_RESUME:
24729949e86Sstevel 		return (DDI_SUCCESS);
24829949e86Sstevel 
24929949e86Sstevel 	default:
25029949e86Sstevel 		return (DDI_FAILURE);
25129949e86Sstevel 	}
25229949e86Sstevel 
25329949e86Sstevel 	instance = ddi_get_instance(devi);
25429949e86Sstevel 
25529949e86Sstevel 	if (ddi_soft_state_zalloc(acp, instance) != DDI_SUCCESS) {
25629949e86Sstevel 		cmn_err(CE_WARN, "ddi_soft_state_zalloc failed for ac%d",
25729949e86Sstevel 		    instance);
25829949e86Sstevel 		return (DDI_FAILURE);
25929949e86Sstevel 	}
26029949e86Sstevel 
26129949e86Sstevel 	softsp = ddi_get_soft_state(acp, instance);
26229949e86Sstevel 
26329949e86Sstevel 	/* Set the dip in the soft state */
26429949e86Sstevel 	softsp->dip = devi;
26529949e86Sstevel 
26629949e86Sstevel 	/* Get the board number from this nodes parent */
26729949e86Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
26829949e86Sstevel 	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
26929949e86Sstevel 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
27029949e86Sstevel 		cmn_err(CE_WARN, "ac%d: unable to retrieve %s property",
27129949e86Sstevel 		    instance, OBP_BOARDNUM);
27229949e86Sstevel 		goto bad;
27329949e86Sstevel 	}
27429949e86Sstevel 
27529949e86Sstevel 	DPRINTF(AC_ATTACH_DEBUG, ("ac%d: devi= 0x%p\n,"
27607d06da5SSurya Prakki 	    " softsp=0x%p\n", instance, (void *)devi, (void *)softsp));
27729949e86Sstevel 
27829949e86Sstevel 	/* map in the registers for this device. */
27929949e86Sstevel 	if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0)) {
28029949e86Sstevel 		cmn_err(CE_WARN, "ac%d: unable to map registers", instance);
28129949e86Sstevel 		goto bad;
28229949e86Sstevel 	}
28329949e86Sstevel 
28429949e86Sstevel 	/* Setup the pointers to the hardware registers */
28529949e86Sstevel 	softsp->ac_id = (uint32_t *)softsp->ac_base;
28629949e86Sstevel 	softsp->ac_memctl = (uint64_t *)((char *)softsp->ac_base +
28729949e86Sstevel 	    AC_OFF_MEMCTL);
28829949e86Sstevel 	softsp->ac_memdecode0 = (uint64_t *)((char *)softsp->ac_base +
28929949e86Sstevel 	    AC_OFF_MEMDEC0);
29029949e86Sstevel 	softsp->ac_memdecode1 = (uint64_t *)((char *)softsp->ac_base +
29129949e86Sstevel 	    AC_OFF_MEMDEC1);
29229949e86Sstevel 	softsp->ac_counter = (uint64_t *)((char *)softsp->ac_base +
29329949e86Sstevel 	    AC_OFF_CNTR);
29429949e86Sstevel 	softsp->ac_mccr = (uint32_t *)((char *)softsp->ac_base +
29529949e86Sstevel 	    AC_OFF_MCCR);
29629949e86Sstevel 
29729949e86Sstevel 	/* nothing to suspend/resume here */
29829949e86Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
29929949e86Sstevel 	    "pm-hardware-state", "no-suspend-resume");
30029949e86Sstevel 
30129949e86Sstevel 	/* setup the the AC counter registers to allow for hotplug. */
30229949e86Sstevel 	list = fhc_bdlist_lock(softsp->board);
30329949e86Sstevel 
30429949e86Sstevel 	if (list == NULL) {
30529949e86Sstevel 		cmn_err(CE_PANIC, "ac%d: Board %d not found in database",
30629949e86Sstevel 		    instance, softsp->board);
30729949e86Sstevel 	}
30829949e86Sstevel 
30929949e86Sstevel 	/* set the AC rev into the bd list structure */
31029949e86Sstevel 	list->sc.ac_compid = *softsp->ac_id;
31129949e86Sstevel 
31229949e86Sstevel 	list->ac_softsp = softsp;
31329949e86Sstevel 
31429949e86Sstevel 	if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
31529949e86Sstevel 		/* Create the minor nodes */
31629949e86Sstevel 		if (ddi_create_minor_node(devi, NAME_BANK0, S_IFCHR,
31729949e86Sstevel 		    (AC_PUTINSTANCE(instance) | 0),
31829949e86Sstevel 		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
31929949e86Sstevel 			cmn_err(CE_WARN, "ac%d: \"%s\" "
32029949e86Sstevel 			    "ddi_create_minor_node failed", instance,
32129949e86Sstevel 			    NAME_BANK0);
32229949e86Sstevel 		}
32329949e86Sstevel 		if (ddi_create_minor_node(devi, NAME_BANK1, S_IFCHR,
32429949e86Sstevel 		    (AC_PUTINSTANCE(instance) | 1),
32529949e86Sstevel 		    DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
32629949e86Sstevel 			cmn_err(CE_WARN, "ac%d: \"%s\" "
32729949e86Sstevel 			    "ddi_create_minor_node failed", instance,
32829949e86Sstevel 			    NAME_BANK0);
32929949e86Sstevel 		}
33029949e86Sstevel 
33129949e86Sstevel 		/* purge previous fhc pa database entries */
33229949e86Sstevel 		fhc_del_memloc(softsp->board);
33329949e86Sstevel 
33429949e86Sstevel 		/* Inherit Memory Bank Status */
33529949e86Sstevel 		ac_get_memory_status(softsp, Bank0);
33629949e86Sstevel 		ac_get_memory_status(softsp, Bank1);
33729949e86Sstevel 		/* Final Memory Bank Status evaluation and messaging */
33829949e86Sstevel 		ac_eval_memory_status(softsp, Bank0);
33929949e86Sstevel 		ac_eval_memory_status(softsp, Bank1);
34029949e86Sstevel 	}
34129949e86Sstevel 
34229949e86Sstevel 	fhc_bdlist_unlock();
34329949e86Sstevel 
34429949e86Sstevel 	/* create the kstats for this device. */
34529949e86Sstevel 	ac_add_kstats(softsp);
34629949e86Sstevel 
34729949e86Sstevel 	ddi_report_dev(devi);
34829949e86Sstevel 
34929949e86Sstevel 	return (DDI_SUCCESS);
35029949e86Sstevel 
35129949e86Sstevel bad:
35229949e86Sstevel 	ddi_soft_state_free(acp, instance);
35329949e86Sstevel 	return (DDI_FAILURE);
35429949e86Sstevel }
35529949e86Sstevel 
35629949e86Sstevel /* ARGSUSED */
35729949e86Sstevel static int
35829949e86Sstevel ac_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
35929949e86Sstevel {
36029949e86Sstevel 	int instance;
36129949e86Sstevel 	struct ac_soft_state *softsp;
36229949e86Sstevel 	struct bd_list *list;
36329949e86Sstevel 
36429949e86Sstevel 	/* get the instance of this devi */
36529949e86Sstevel 	instance = ddi_get_instance(devi);
36629949e86Sstevel 
36729949e86Sstevel 	/* get the soft state pointer for this device node */
36829949e86Sstevel 	softsp = ddi_get_soft_state(acp, instance);
36929949e86Sstevel 
37029949e86Sstevel 	switch (cmd) {
37129949e86Sstevel 	case DDI_SUSPEND:
37229949e86Sstevel 		return (DDI_SUCCESS);
37329949e86Sstevel 
37429949e86Sstevel 	case DDI_DETACH:
37529949e86Sstevel 		list = fhc_bdlist_lock(softsp->board);
37629949e86Sstevel 
37729949e86Sstevel 		if (fhc_bd_detachable(softsp->board))
37829949e86Sstevel 			break;
37929949e86Sstevel 		else
38029949e86Sstevel 			fhc_bdlist_unlock();
38129949e86Sstevel 		/* FALLTHROUGH */
38229949e86Sstevel 
38329949e86Sstevel 	default:
38429949e86Sstevel 		return (DDI_FAILURE);
38529949e86Sstevel 	}
38629949e86Sstevel 
38729949e86Sstevel 	ASSERT(list->ac_softsp == softsp);
38829949e86Sstevel 
38929949e86Sstevel 	if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
39029949e86Sstevel 		int cpui;
39129949e86Sstevel 
39229949e86Sstevel 		/*
39329949e86Sstevel 		 * Test to see if memory is in use on a CPU/MEM board.
39429949e86Sstevel 		 * In the case of a DR operation this condition
39529949e86Sstevel 		 * will have been assured when the board was unconfigured.
39629949e86Sstevel 		 */
39729949e86Sstevel 		if (softsp->bank[Bank0].busy != 0 ||
39829949e86Sstevel 		    softsp->bank[Bank0].ostate == SYSC_CFGA_OSTATE_CONFIGURED ||
39929949e86Sstevel 		    softsp->bank[Bank1].busy != 0 ||
40029949e86Sstevel 		    softsp->bank[Bank1].ostate == SYSC_CFGA_OSTATE_CONFIGURED) {
40129949e86Sstevel 			fhc_bdlist_unlock();
40229949e86Sstevel 			return (DDI_FAILURE);
40329949e86Sstevel 		}
40429949e86Sstevel 		/*
40529949e86Sstevel 		 * CPU busy test is done by the DR sequencer before
40629949e86Sstevel 		 * device detach called.
40729949e86Sstevel 		 */
40829949e86Sstevel 
40929949e86Sstevel 		/*
41029949e86Sstevel 		 * Flush all E-caches to remove references to this
41129949e86Sstevel 		 * board's memory.
41229949e86Sstevel 		 *
41329949e86Sstevel 		 * Do this one CPU at a time to avoid stalls and timeouts
41429949e86Sstevel 		 * due to all CPUs flushing concurrently.
41529949e86Sstevel 		 * xc_one returns silently for non-existant CPUs.
41629949e86Sstevel 		 */
41729949e86Sstevel 		for (cpui = 0; cpui < NCPU; cpui++)
41829949e86Sstevel 			xc_one(cpui, ac_ecache_flush, 0, 0);
41929949e86Sstevel 	}
42029949e86Sstevel 
42129949e86Sstevel 	list->ac_softsp = NULL;
42229949e86Sstevel 
42329949e86Sstevel 	/* delete the kstat for this driver. */
42429949e86Sstevel 	ac_del_kstats(softsp);
42529949e86Sstevel 
42629949e86Sstevel 	/* unmap the registers */
42729949e86Sstevel 	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0);
42829949e86Sstevel 
42929949e86Sstevel 	fhc_bdlist_unlock();
43029949e86Sstevel 
43129949e86Sstevel 	/* Remove the minor nodes. */
43229949e86Sstevel 	ddi_remove_minor_node(devi, NULL);
43329949e86Sstevel 
43429949e86Sstevel 	/* free the soft state structure */
43529949e86Sstevel 	ddi_soft_state_free(acp, instance);
43629949e86Sstevel 	ddi_prop_remove_all(devi);
43729949e86Sstevel 
43829949e86Sstevel 	return (DDI_SUCCESS);
43929949e86Sstevel }
44029949e86Sstevel 
44129949e86Sstevel /* ARGSUSED */
44229949e86Sstevel static int
44329949e86Sstevel ac_open(dev_t *devp, int flag, int otyp, cred_t *credp)
44429949e86Sstevel {
44529949e86Sstevel 	int instance;
44629949e86Sstevel 	dev_t dev;
44729949e86Sstevel 	struct ac_soft_state *softsp;
44829949e86Sstevel 	struct bd_list *board;
44929949e86Sstevel 	int vis;
45029949e86Sstevel 
45129949e86Sstevel 	dev = *devp;
45229949e86Sstevel 	instance = AC_GETINSTANCE(getminor(dev));
45329949e86Sstevel 	softsp = AC_GETSOFTC(instance);
45429949e86Sstevel 
45529949e86Sstevel 	/* Is the instance attached? */
45629949e86Sstevel 	if (softsp == NULL) {
45729949e86Sstevel #ifdef DEBUG
45829949e86Sstevel 		cmn_err(CE_WARN, "ac%d device not attached", instance);
45929949e86Sstevel #endif /* DEBUG */
46029949e86Sstevel 		return (ENXIO);
46129949e86Sstevel 	}
46229949e86Sstevel 
46329949e86Sstevel 	/*
46429949e86Sstevel 	 * If the board is not configured, hide the memory APs
46529949e86Sstevel 	 */
46629949e86Sstevel 	board = fhc_bdlist_lock(softsp->board);
46729949e86Sstevel 	vis = (board != NULL) && MEM_BOARD_VISIBLE(board);
46829949e86Sstevel 	fhc_bdlist_unlock();
46929949e86Sstevel 
47029949e86Sstevel 	if (!vis)
47129949e86Sstevel 		return (ENXIO);
47229949e86Sstevel 
47329949e86Sstevel 	/* verify that otyp is appropriate */
47429949e86Sstevel 	if (otyp != OTYP_CHR) {
47529949e86Sstevel 		return (EINVAL);
47629949e86Sstevel 	}
47729949e86Sstevel 
47829949e86Sstevel 	return (DDI_SUCCESS);
47929949e86Sstevel }
48029949e86Sstevel 
48129949e86Sstevel /* ARGSUSED */
48229949e86Sstevel static int
48329949e86Sstevel ac_close(dev_t devt, int flag, int otyp, cred_t *credp)
48429949e86Sstevel {
48529949e86Sstevel 	struct ac_soft_state *softsp;
48629949e86Sstevel 	int instance;
48729949e86Sstevel 
48829949e86Sstevel 	instance = AC_GETINSTANCE(getminor(devt));
48929949e86Sstevel 	softsp = AC_GETSOFTC(instance);
49029949e86Sstevel 	ASSERT(softsp != NULL);
49129949e86Sstevel 	ac_mem_test_stop_on_close(softsp->board, AC_GETBANK(getminor(devt)));
49229949e86Sstevel 	return (DDI_SUCCESS);
49329949e86Sstevel }
49429949e86Sstevel 
49529949e86Sstevel static int
49629949e86Sstevel ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
49729949e86Sstevel {
49829949e86Sstevel #ifdef _MULTI_DATAMODEL
49929949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
50029949e86Sstevel 		ac_cfga_cmd32_t ac_cmd32;
50129949e86Sstevel 
50229949e86Sstevel 		if (ddi_copyin((void *)arg, &ac_cmd32,
50329949e86Sstevel 		    sizeof (ac_cfga_cmd32_t), flag) != 0) {
50429949e86Sstevel 			return (EFAULT);
50529949e86Sstevel 		}
50629949e86Sstevel 		pkt->cmd_cfga.force = ac_cmd32.force;
50729949e86Sstevel 		pkt->cmd_cfga.test = ac_cmd32.test;
50829949e86Sstevel 		pkt->cmd_cfga.arg = ac_cmd32.arg;
50929949e86Sstevel 		pkt->cmd_cfga.errtype = ac_cmd32.errtype;
51029949e86Sstevel 		pkt->cmd_cfga.outputstr =
51129949e86Sstevel 		    (char *)(uintptr_t)ac_cmd32.outputstr;
51229949e86Sstevel 		pkt->cmd_cfga.private =
51329949e86Sstevel 		    (void *)(uintptr_t)ac_cmd32.private;
51429949e86Sstevel 	} else
51529949e86Sstevel #endif /* _MULTI_DATAMODEL */
51629949e86Sstevel 	if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
51729949e86Sstevel 	    sizeof (ac_cfga_cmd_t), flag) != 0) {
51829949e86Sstevel 		return (EFAULT);
51929949e86Sstevel 	}
52029949e86Sstevel 	pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
52129949e86Sstevel 	return (0);
52229949e86Sstevel }
52329949e86Sstevel 
52429949e86Sstevel static int
52529949e86Sstevel ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
52629949e86Sstevel {
52729949e86Sstevel 	int ret = TRUE;
52829949e86Sstevel 
52929949e86Sstevel #ifdef _MULTI_DATAMODEL
53029949e86Sstevel 	if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
53129949e86Sstevel 
53229949e86Sstevel 		if (ddi_copyout(&(pkt->cmd_cfga.errtype),
53329949e86Sstevel 		    (void *)&(((ac_cfga_cmd32_t *)arg)->errtype),
53429949e86Sstevel 		    sizeof (ac_err_t), flag) != 0) {
53529949e86Sstevel 			ret = FALSE;
53629949e86Sstevel 		}
53729949e86Sstevel 	} else
53829949e86Sstevel #endif
53929949e86Sstevel 	if (ddi_copyout(&(pkt->cmd_cfga.errtype),
54029949e86Sstevel 	    (void *)&(((ac_cfga_cmd_t *)arg)->errtype),
54129949e86Sstevel 	    sizeof (ac_err_t), flag) != 0) {
54229949e86Sstevel 		ret = FALSE;
54329949e86Sstevel 	}
54429949e86Sstevel 
54529949e86Sstevel 	if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
54629949e86Sstevel 	    (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
54729949e86Sstevel 	    SYSC_OUTPUT_LEN, flag) != 0))) {
54829949e86Sstevel 			ret = FALSE;
54929949e86Sstevel 	}
55029949e86Sstevel 
55129949e86Sstevel 	kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
55229949e86Sstevel 	return (ret);
55329949e86Sstevel }
55429949e86Sstevel 
55529949e86Sstevel /* ARGSUSED */
55629949e86Sstevel static int
55729949e86Sstevel ac_ioctl(
55829949e86Sstevel 	dev_t devt,
55929949e86Sstevel 	int cmd,
56029949e86Sstevel 	intptr_t arg,
56129949e86Sstevel 	int flag,
56229949e86Sstevel 	cred_t *cred_p,
56329949e86Sstevel 	int *rval_p)
56429949e86Sstevel {
56529949e86Sstevel 	struct ac_soft_state *softsp;
56629949e86Sstevel 	ac_cfga_pkt_t cfga_pkt, *pkt;
56729949e86Sstevel 	int instance;
56829949e86Sstevel 	int retval;
56929949e86Sstevel 
57029949e86Sstevel 	instance = AC_GETINSTANCE(getminor(devt));
57129949e86Sstevel 	softsp = AC_GETSOFTC(instance);
57229949e86Sstevel 	if (softsp == NULL) {
57329949e86Sstevel #ifdef DEBUG
57429949e86Sstevel 		cmn_err(CE_NOTE, "ac%d device not attached", instance);
57529949e86Sstevel #endif /* DEBUG */
57629949e86Sstevel 		return (ENXIO);
57729949e86Sstevel 	}
57829949e86Sstevel 
57929949e86Sstevel 	/*
58029949e86Sstevel 	 * Dispose of the easy ones first.
58129949e86Sstevel 	 */
58229949e86Sstevel 	switch (cmd) {
58329949e86Sstevel 	case AC_MEM_ADMIN_VER:
58429949e86Sstevel 		/*
58529949e86Sstevel 		 * Specify the revision of this ioctl interface driver.
58629949e86Sstevel 		 */
58729949e86Sstevel 		if (ddi_copyout(&ac_mem_version, (void *)arg,
58829949e86Sstevel 		    sizeof (ac_mem_version_t), flag) != 0)
58929949e86Sstevel 			return (EFAULT);
59029949e86Sstevel 		return (DDI_SUCCESS);
59129949e86Sstevel 
59229949e86Sstevel 	case AC_MEM_CONFIGURE:
59329949e86Sstevel 	case AC_MEM_UNCONFIGURE:
59429949e86Sstevel 	case AC_MEM_STAT:
59529949e86Sstevel 	case AC_MEM_TEST_START:
59629949e86Sstevel 	case AC_MEM_TEST_STOP:
59729949e86Sstevel 	case AC_MEM_TEST_READ:
59829949e86Sstevel 	case AC_MEM_TEST_WRITE:
59929949e86Sstevel 	case AC_MEM_EXERCISE:
60029949e86Sstevel 		break;
60129949e86Sstevel 
60229949e86Sstevel 	default:
60329949e86Sstevel 		return (ENOTTY);
60429949e86Sstevel 	}
60529949e86Sstevel 	if (cmd != AC_MEM_STAT && !fpu_exists) {
60629949e86Sstevel 		return (ENOTSUP);
60729949e86Sstevel 	}
60829949e86Sstevel 
60929949e86Sstevel 	pkt = &cfga_pkt;
61029949e86Sstevel 	if ((retval = ac_pkt_init(pkt, arg, flag)) != 0)
61129949e86Sstevel 		return (retval);
61229949e86Sstevel 	pkt->softsp = softsp;
61329949e86Sstevel 	pkt->bank = AC_GETBANK(getminor(devt));
61429949e86Sstevel 
61529949e86Sstevel 	switch (cmd) {
61629949e86Sstevel 	case AC_MEM_CONFIGURE:
61729949e86Sstevel 		if ((flag & FWRITE) == 0) {
61829949e86Sstevel 			retval = EBADF;
61929949e86Sstevel 			break;
62029949e86Sstevel 		}
62129949e86Sstevel 
62229949e86Sstevel 		if (pkt->cmd_cfga.private != NULL) {
62329949e86Sstevel 			retval = EINVAL;
62429949e86Sstevel 			break;
62529949e86Sstevel 		}
62629949e86Sstevel 		ac_policy_audit_messages(AC_AUDIT_OSTATE_CONFIGURE, pkt);
62729949e86Sstevel 		retval = ac_add_memory(pkt);
62829949e86Sstevel 		if (!retval)
62929949e86Sstevel 			ac_policy_audit_messages(
63029949e86Sstevel 			    AC_AUDIT_OSTATE_SUCCEEDED, pkt);
63129949e86Sstevel 		else
63229949e86Sstevel 			ac_policy_audit_messages(
63329949e86Sstevel 			    AC_AUDIT_OSTATE_CONFIGURE_FAILED, pkt);
63429949e86Sstevel 		break;
63529949e86Sstevel 
63629949e86Sstevel 	case AC_MEM_UNCONFIGURE:
63729949e86Sstevel 		if ((flag & FWRITE) == 0) {
63829949e86Sstevel 			retval = EBADF;
63929949e86Sstevel 			break;
64029949e86Sstevel 		}
64129949e86Sstevel 
64229949e86Sstevel 		if (pkt->cmd_cfga.private != NULL) {
64329949e86Sstevel 			retval = EINVAL;
64429949e86Sstevel 			break;
64529949e86Sstevel 		}
64629949e86Sstevel 		ac_policy_audit_messages(AC_AUDIT_OSTATE_UNCONFIGURE, pkt);
64729949e86Sstevel 		retval = ac_del_memory(pkt);
64829949e86Sstevel 		if (!retval) {
64929949e86Sstevel 			ac_policy_audit_messages(
65029949e86Sstevel 			    AC_AUDIT_OSTATE_SUCCEEDED, pkt);
65129949e86Sstevel 		} else
65229949e86Sstevel 			ac_policy_audit_messages(
65329949e86Sstevel 			    AC_AUDIT_OSTATE_UNCONFIGURE_FAILED, pkt);
65429949e86Sstevel 		break;
65529949e86Sstevel 
65629949e86Sstevel 	case AC_MEM_STAT:
65729949e86Sstevel 		/*
65829949e86Sstevel 		 * Query usage of a bank of memory.
65929949e86Sstevel 		 */
66029949e86Sstevel 		retval = ac_mem_stat(pkt, flag);
66129949e86Sstevel 		break;
66229949e86Sstevel 
66329949e86Sstevel 	case AC_MEM_TEST_START:
66429949e86Sstevel 		if ((flag & FWRITE) == 0) {
66529949e86Sstevel 			retval = EBADF;
66629949e86Sstevel 			break;
66729949e86Sstevel 		}
66829949e86Sstevel 
66929949e86Sstevel 		retval = ac_mem_test_start(pkt, flag);
67029949e86Sstevel 		break;
67129949e86Sstevel 
67229949e86Sstevel 	case AC_MEM_TEST_STOP:
67329949e86Sstevel 		if ((flag & FWRITE) == 0) {
67429949e86Sstevel 			retval = EBADF;
67529949e86Sstevel 			break;
67629949e86Sstevel 		}
67729949e86Sstevel 
67829949e86Sstevel 		retval =  ac_mem_test_stop(pkt, flag);
67929949e86Sstevel 		break;
68029949e86Sstevel 
68129949e86Sstevel 	case AC_MEM_TEST_READ:
68229949e86Sstevel 		/*
68329949e86Sstevel 		 * read a 'page' (or less) of memory safely.
68429949e86Sstevel 		 */
68529949e86Sstevel 		if ((flag & FWRITE) == 0) {
68629949e86Sstevel 			retval = EBADF;
68729949e86Sstevel 			break;
68829949e86Sstevel 		}
68929949e86Sstevel 
69029949e86Sstevel 		retval = ac_mem_test_read(pkt, flag);
69129949e86Sstevel 		break;
69229949e86Sstevel 
69329949e86Sstevel 	case AC_MEM_TEST_WRITE:
69429949e86Sstevel 		/*
69529949e86Sstevel 		 * write a 'page' (or less) of memory safely.
69629949e86Sstevel 		 */
69729949e86Sstevel 		if ((flag & FWRITE) == 0) {
69829949e86Sstevel 			retval = EBADF;
69929949e86Sstevel 			break;
70029949e86Sstevel 		}
70129949e86Sstevel 
70229949e86Sstevel 		retval = ac_mem_test_write(pkt, flag);
70329949e86Sstevel 		break;
70429949e86Sstevel 
70529949e86Sstevel 	case AC_MEM_EXERCISE:
70629949e86Sstevel 		retval = ac_mem_exercise(pkt, flag);
70729949e86Sstevel 		break;
70829949e86Sstevel 
70929949e86Sstevel 	default:
71029949e86Sstevel 		ASSERT(0);
71129949e86Sstevel 		retval = ENOTTY;
71229949e86Sstevel 		break;
71329949e86Sstevel 	}
71429949e86Sstevel 
71529949e86Sstevel 	if (ac_pkt_fini(pkt, arg, flag) != TRUE)
71629949e86Sstevel 		retval = EFAULT;
71729949e86Sstevel 
71829949e86Sstevel 	return (retval);
71929949e86Sstevel }
72029949e86Sstevel 
72129949e86Sstevel static void
72229949e86Sstevel ac_add_kstats(struct ac_soft_state *softsp)
72329949e86Sstevel {
72429949e86Sstevel 	struct kstat *ac_ksp, *ac_counters_ksp;
72529949e86Sstevel 	struct ac_kstat *ac_named_ksp;
72629949e86Sstevel 	struct kstat_named *ac_counters_named_data;
72729949e86Sstevel 
72829949e86Sstevel 	/*
72929949e86Sstevel 	 * create the unix-misc kstat for address controller
73029949e86Sstevel 	 * using the board number as the instance.
73129949e86Sstevel 	 */
73229949e86Sstevel 	if ((ac_ksp = kstat_create("unix", softsp->board,
73329949e86Sstevel 	    AC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
73429949e86Sstevel 	    sizeof (struct ac_kstat) / sizeof (kstat_named_t),
73529949e86Sstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
73629949e86Sstevel 		cmn_err(CE_WARN, "ac%d: kstat_create failed",
73729949e86Sstevel 		    ddi_get_instance(softsp->dip));
73829949e86Sstevel 		return;
73929949e86Sstevel 	}
74029949e86Sstevel 
74129949e86Sstevel 	ac_named_ksp = (struct ac_kstat *)(ac_ksp->ks_data);
74229949e86Sstevel 
74329949e86Sstevel 	/* initialize the named kstats */
74429949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_memctl,
74529949e86Sstevel 	    MEMCTL_KSTAT_NAMED,
74629949e86Sstevel 	    KSTAT_DATA_UINT64);
74729949e86Sstevel 
74829949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_memdecode0,
74929949e86Sstevel 	    MEMDECODE0_KSTAT_NAMED,
75029949e86Sstevel 	    KSTAT_DATA_UINT64);
75129949e86Sstevel 
75229949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_memdecode1,
75329949e86Sstevel 	    MEMDECODE1_KSTAT_NAMED,
75429949e86Sstevel 	    KSTAT_DATA_UINT64);
75529949e86Sstevel 
75629949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_mccr,
75729949e86Sstevel 	    MCCR_KSTAT_NAMED,
75829949e86Sstevel 	    KSTAT_DATA_UINT32);
75929949e86Sstevel 
76029949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_counter,
76129949e86Sstevel 	    CNTR_KSTAT_NAMED,
76229949e86Sstevel 	    KSTAT_DATA_UINT64);
76329949e86Sstevel 
76429949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_bank0_status,
76529949e86Sstevel 	    BANK_0_KSTAT_NAMED,
76629949e86Sstevel 	    KSTAT_DATA_CHAR);
76729949e86Sstevel 
76829949e86Sstevel 	kstat_named_init(&ac_named_ksp->ac_bank1_status,
76929949e86Sstevel 	    BANK_1_KSTAT_NAMED,
77029949e86Sstevel 	    KSTAT_DATA_CHAR);
77129949e86Sstevel 
77229949e86Sstevel 	ac_ksp->ks_update = ac_misc_kstat_update;
77329949e86Sstevel 	ac_ksp->ks_private = (void *)softsp;
77429949e86Sstevel 	softsp->ac_ksp = ac_ksp;
77529949e86Sstevel 	kstat_install(ac_ksp);
77629949e86Sstevel 
77729949e86Sstevel 	/*
77829949e86Sstevel 	 * Create the picN kstats if we are the first instance
77929949e86Sstevel 	 * to attach. We use ac_attachcnt as a count of how
78029949e86Sstevel 	 * many instances have attached. This is protected by
78129949e86Sstevel 	 * a mutex.
78229949e86Sstevel 	 */
78329949e86Sstevel 	mutex_enter(&ac_attachcnt_mutex);
78429949e86Sstevel 	if (ac_attachcnt == 0)
78529949e86Sstevel 		ac_add_picN_kstats(softsp->dip);
78629949e86Sstevel 
78729949e86Sstevel 	ac_attachcnt ++;
78829949e86Sstevel 	mutex_exit(&ac_attachcnt_mutex);
78929949e86Sstevel 
79029949e86Sstevel 	/*
79129949e86Sstevel 	 * Create the "counter" kstat for each AC instance.
79229949e86Sstevel 	 * This provides access to the %pcr and %pic
79329949e86Sstevel 	 * registers for that instance.
79429949e86Sstevel 	 *
79529949e86Sstevel 	 * The size of this kstat is AC_NUM_PICS + 1 for %pcr
79629949e86Sstevel 	 */
79729949e86Sstevel 	if ((ac_counters_ksp = kstat_create("ac",
79829949e86Sstevel 	    ddi_get_instance(softsp->dip), "counters",
79929949e86Sstevel 	    "bus", KSTAT_TYPE_NAMED, AC_NUM_PICS + 1,
80029949e86Sstevel 	    KSTAT_FLAG_WRITABLE)) == NULL) {
80129949e86Sstevel 
80229949e86Sstevel 		cmn_err(CE_WARN, "ac%d counters: kstat_create failed",
80329949e86Sstevel 		    ddi_get_instance(softsp->dip));
80429949e86Sstevel 		return;
80529949e86Sstevel 	}
80629949e86Sstevel 	ac_counters_named_data =
80729949e86Sstevel 	    (struct kstat_named *)(ac_counters_ksp->ks_data);
80829949e86Sstevel 
80929949e86Sstevel 	/* initialize the named kstats */
81029949e86Sstevel 	kstat_named_init(&ac_counters_named_data[0],
81129949e86Sstevel 	    "pcr", KSTAT_DATA_UINT64);
81229949e86Sstevel 
81329949e86Sstevel 	kstat_named_init(&ac_counters_named_data[1],
81429949e86Sstevel 	    "pic0", KSTAT_DATA_UINT64);
81529949e86Sstevel 
81629949e86Sstevel 	kstat_named_init(&ac_counters_named_data[2],
81729949e86Sstevel 	    "pic1", KSTAT_DATA_UINT64);
81829949e86Sstevel 
81929949e86Sstevel 	ac_counters_ksp->ks_update = ac_counters_kstat_update;
82029949e86Sstevel 	ac_counters_ksp->ks_private = (void *)softsp;
82129949e86Sstevel 	kstat_install(ac_counters_ksp);
82229949e86Sstevel 
82329949e86Sstevel 	/* update the sofstate */
82429949e86Sstevel 	softsp->ac_counters_ksp = ac_counters_ksp;
82529949e86Sstevel }
82629949e86Sstevel 
82729949e86Sstevel /*
82829949e86Sstevel  * called from ac_add_kstats() to create a kstat for each %pic
82929949e86Sstevel  * that the AC supports. These (read-only) kstats export the
83029949e86Sstevel  * event names and %pcr masks that each %pic supports.
83129949e86Sstevel  *
83229949e86Sstevel  * if we fail to create any of these kstats we must remove any
83329949e86Sstevel  * that we have already created and return;
83429949e86Sstevel  *
83529949e86Sstevel  * NOTE: because all AC's use the same events we only need to
83629949e86Sstevel  *       create the picN kstats once. All instances can use
83729949e86Sstevel  *       the same picN kstats.
83829949e86Sstevel  *
83929949e86Sstevel  *       The flexibility exists to allow each device specify it's
84029949e86Sstevel  *       own events by creating picN kstats with the instance number
84129949e86Sstevel  *       set to ddi_get_instance(softsp->dip).
84229949e86Sstevel  *
84329949e86Sstevel  *       When searching for a picN kstat for a device you should
84429949e86Sstevel  *       first search for a picN kstat using the instance number
84529949e86Sstevel  *       of the device you are interested in. If that fails you
84629949e86Sstevel  *       should use the first picN kstat found for that device.
84729949e86Sstevel  */
84829949e86Sstevel static void
84929949e86Sstevel ac_add_picN_kstats(dev_info_t *dip)
85029949e86Sstevel {
85129949e86Sstevel 	typedef struct ac_event_mask {
85229949e86Sstevel 		char *event_name;
85329949e86Sstevel 		uint64_t pcr_mask;
85429949e86Sstevel 	} ac_event_mask_t;
85529949e86Sstevel 
85629949e86Sstevel 	/*
85729949e86Sstevel 	 * AC Performance Events.
85829949e86Sstevel 	 *
85929949e86Sstevel 	 * We declare an array of event-names and event-masks.
86029949e86Sstevel 	 */
86129949e86Sstevel 	ac_event_mask_t ac_events_arr[] = {
86229949e86Sstevel 		{"mem_bank0_rds", 0x1}, {"mem_bank0_wrs", 0x2},
86329949e86Sstevel 		{"mem_bank0_stall", 0x3}, {"mem_bank1_rds", 0x4},
86429949e86Sstevel 		{"mem_bank1_wrs", 0x5}, {"mem_bank1_stall", 0x6},
86529949e86Sstevel 		{"clock_cycles", 0x7}, {"addr_pkts", 0x8},
86629949e86Sstevel 		{"data_pkts", 0x9}, {"flow_ctl_cyc", 0xa},
86729949e86Sstevel 		{"fast_arb_pkts", 0xb}, {"bus_cont_cyc", 0xc},
86829949e86Sstevel 		{"data_bus_can", 0xd}, {"ac_addr_pkts", 0xe},
86929949e86Sstevel 		{"ac_data_pkts", 0xf}, {"rts_pkts", 0x10},
87029949e86Sstevel 		{"rtsa_pkts", 0x11}, {"rto_pkts", 0x12},
87129949e86Sstevel 		{"rs_pkts", 0x13}, {"wb_pkts", 0x14},
87229949e86Sstevel 		{"ws_pkts", 0x15}, {"rio_pkts", 0x16},
87329949e86Sstevel 		{"rbio_pkts", 0x17}, {"wio_pkts", 0x18},
87429949e86Sstevel 		{"wbio_pkts", 0x19}, {"upa_a_rds_m", 0x1a},
87529949e86Sstevel 		{"upa_a_rdo_v", 0x1b}, {"upa_b_rds_m", 0x1c},
87629949e86Sstevel 		{"upa_b_rdo_v", 0x1d}, {"upa_a_preqs_fr", 0x20},
87729949e86Sstevel 		{"upa_a_sreqs_to", 0x21}, {"upa_a_preqs_to", 0x22},
87829949e86Sstevel 		{"upa_a_rds_fr", 0x23}, {"upa_a_rdsa_fr", 0x24},
87929949e86Sstevel 		{"upa_a_rdo_fr", 0x25}, {"upa_a_rdd_fr", 0x26},
88029949e86Sstevel 		{"upa_a_rio_rbio", 0x27}, {"upa_a_wio_wbio", 0x28},
88129949e86Sstevel 		{"upa_a_cpb_to", 0x29}, {"upa_a_inv_to", 0x2a},
88229949e86Sstevel 		{"upa_a_hits_buff", 0x2b}, {"upa_a_wb", 0x2c},
88329949e86Sstevel 		{"upa_a_wi", 0x2d}, {"upa_b_preqs_fr", 0x30},
88429949e86Sstevel 		{"upa_b_sreqs_to", 0x31}, {"upa_b_preqs_to", 0x32},
88529949e86Sstevel 		{"upa_b_rds_fr", 0x33}, {"upa_b_rdsa_fr", 0x34},
88629949e86Sstevel 		{"upa_b_rdo_fr", 0x35}, {"upa_b_rdd_fr", 0x36},
88729949e86Sstevel 		{"upa_b_rio_rbio", 0x37}, {"upa_b_wio_wbio", 0x38},
88829949e86Sstevel 		{"upa_b_cpb_to", 0x39}, {"upa_b_inv_to", 0x3a},
88929949e86Sstevel 		{"upa_b_hits_buff", 0x3b}, {"upa_b_wb", 0x3c},
89029949e86Sstevel 		{"upa_b_wi", 0x3d}
89129949e86Sstevel 	};
89229949e86Sstevel 
89329949e86Sstevel #define	AC_NUM_EVENTS sizeof (ac_events_arr) / sizeof (ac_events_arr[0])
89429949e86Sstevel 
89529949e86Sstevel 	/*
89629949e86Sstevel 	 * array of clear masks for each pic.
89729949e86Sstevel 	 * These masks are used to clear the %pcr bits for
89829949e86Sstevel 	 * each pic.
89929949e86Sstevel 	 */
90029949e86Sstevel 	ac_event_mask_t ac_clear_pic[AC_NUM_PICS] = {
90129949e86Sstevel 		/* pic0 */
90229949e86Sstevel 		{"clear_pic", (uint64_t)~(0x3f)},
90329949e86Sstevel 		/* pic1 */
90429949e86Sstevel 		{"clear_pic", (uint64_t)~(0x3f << 8)}
90529949e86Sstevel 	};
90629949e86Sstevel 
90729949e86Sstevel 	struct kstat_named *ac_pic_named_data;
90829949e86Sstevel 	int  		event, pic;
90929949e86Sstevel 	char 		pic_name[30];
91029949e86Sstevel 	int		instance = ddi_get_instance(dip);
91129949e86Sstevel 	int		pic_shift = 0;
91229949e86Sstevel 
91329949e86Sstevel 	for (pic = 0; pic < AC_NUM_PICS; pic++) {
91429949e86Sstevel 		/*
91529949e86Sstevel 		 * create the picN kstat. The size of this kstat is
91629949e86Sstevel 		 * AC_NUM_EVENTS + 1 for the clear_event_mask
91729949e86Sstevel 		 */
91829949e86Sstevel 		(void) sprintf(pic_name, "pic%d", pic);	/* pic0, pic1 ... */
91929949e86Sstevel 		if ((ac_picN_ksp[pic] = kstat_create("ac",
92029949e86Sstevel 		    instance, pic_name, "bus", KSTAT_TYPE_NAMED,
92129949e86Sstevel 		    AC_NUM_EVENTS + 1, NULL)) == NULL) {
92229949e86Sstevel 
92329949e86Sstevel 				cmn_err(CE_WARN, "ac %s: kstat_create failed",
92429949e86Sstevel 				    pic_name);
92529949e86Sstevel 
92629949e86Sstevel 				/* remove pic0 kstat if pic1 create fails */
92729949e86Sstevel 				if (pic == 1) {
92829949e86Sstevel 					kstat_delete(ac_picN_ksp[0]);
92929949e86Sstevel 					ac_picN_ksp[0] = NULL;
93029949e86Sstevel 				}
93129949e86Sstevel 				return;
93229949e86Sstevel 		}
93329949e86Sstevel 		ac_pic_named_data =
93429949e86Sstevel 		    (struct kstat_named *)(ac_picN_ksp[pic]->ks_data);
93529949e86Sstevel 
93629949e86Sstevel 		/*
93729949e86Sstevel 		 * when we are storing pcr_masks we need to shift bits
93829949e86Sstevel 		 * left by 8 for pic1 events.
93929949e86Sstevel 		 */
94029949e86Sstevel 		if (pic == 1)
94129949e86Sstevel 			pic_shift = 8;
94229949e86Sstevel 
94329949e86Sstevel 		/*
94429949e86Sstevel 		 * for each picN event we need to write a kstat record
94529949e86Sstevel 		 * (name = EVENT, value.ui64 = PCR_MASK)
94629949e86Sstevel 		 */
94729949e86Sstevel 		for (event = 0; event < AC_NUM_EVENTS; event ++) {
94829949e86Sstevel 
94929949e86Sstevel 			/* pcr_mask */
95029949e86Sstevel 			ac_pic_named_data[event].value.ui64 =
95129949e86Sstevel 			    ac_events_arr[event].pcr_mask << pic_shift;
95229949e86Sstevel 
95329949e86Sstevel 			/* event-name */
95429949e86Sstevel 			kstat_named_init(&ac_pic_named_data[event],
95529949e86Sstevel 			    ac_events_arr[event].event_name,
95629949e86Sstevel 			    KSTAT_DATA_UINT64);
95729949e86Sstevel 		}
95829949e86Sstevel 
95929949e86Sstevel 		/*
96029949e86Sstevel 		 * we add the clear_pic event and mask as the last
96129949e86Sstevel 		 * record in the kstat
96229949e86Sstevel 		 */
96329949e86Sstevel 		/* pcr mask */
96429949e86Sstevel 		ac_pic_named_data[AC_NUM_EVENTS].value.ui64 =
96529949e86Sstevel 		    ac_clear_pic[pic].pcr_mask;
96629949e86Sstevel 
96729949e86Sstevel 		/* event-name */
96829949e86Sstevel 		kstat_named_init(&ac_pic_named_data[AC_NUM_EVENTS],
96929949e86Sstevel 		    ac_clear_pic[pic].event_name,
97029949e86Sstevel 		    KSTAT_DATA_UINT64);
97129949e86Sstevel 
97229949e86Sstevel 		kstat_install(ac_picN_ksp[pic]);
97329949e86Sstevel 	}
97429949e86Sstevel }
97529949e86Sstevel 
97629949e86Sstevel 
97729949e86Sstevel static void
97829949e86Sstevel ac_del_kstats(struct ac_soft_state *softsp)
97929949e86Sstevel {
98029949e86Sstevel 	struct kstat *ac_ksp;
98129949e86Sstevel 	int pic;
98229949e86Sstevel 
98329949e86Sstevel 	/* remove "misc" kstat */
98429949e86Sstevel 	ac_ksp = softsp->ac_ksp;
98529949e86Sstevel 	softsp->ac_ksp = NULL;
98629949e86Sstevel 	if (ac_ksp != NULL) {
98729949e86Sstevel 		ASSERT(ac_ksp->ks_private == (void *)softsp);
98829949e86Sstevel 		kstat_delete(ac_ksp);
98929949e86Sstevel 	}
99029949e86Sstevel 
99129949e86Sstevel 	/* remove "bus" kstat */
99229949e86Sstevel 	ac_ksp = softsp->ac_counters_ksp;
99329949e86Sstevel 	softsp->ac_counters_ksp = NULL;
99429949e86Sstevel 	if (ac_ksp != NULL) {
99529949e86Sstevel 		ASSERT(ac_ksp->ks_private == (void *)softsp);
99629949e86Sstevel 		kstat_delete(ac_ksp);
99729949e86Sstevel 	}
99829949e86Sstevel 
99929949e86Sstevel 	/*
100029949e86Sstevel 	 * if we are the last instance to detach we need to
100129949e86Sstevel 	 * remove the picN kstats. We use ac_attachcnt as a
100229949e86Sstevel 	 * count of how many instances are still attached. This
100329949e86Sstevel 	 * is protected by a mutex.
100429949e86Sstevel 	 */
100529949e86Sstevel 	mutex_enter(&ac_attachcnt_mutex);
100629949e86Sstevel 	ac_attachcnt --;
100729949e86Sstevel 	if (ac_attachcnt == 0) {
100829949e86Sstevel 		for (pic = 0; pic < AC_NUM_PICS; pic++) {
100929949e86Sstevel 			if (ac_picN_ksp[pic] != (kstat_t *)NULL) {
101029949e86Sstevel 				kstat_delete(ac_picN_ksp[pic]);
101129949e86Sstevel 				ac_picN_ksp[pic] = NULL;
101229949e86Sstevel 			}
101329949e86Sstevel 		}
101429949e86Sstevel 	}
101529949e86Sstevel 	mutex_exit(&ac_attachcnt_mutex);
101629949e86Sstevel }
101729949e86Sstevel 
101829949e86Sstevel static enum ac_bank_status
101929949e86Sstevel ac_kstat_stat(sysc_cfga_rstate_t rst, sysc_cfga_ostate_t ost)
102029949e86Sstevel {
102129949e86Sstevel 	switch (rst) {
102229949e86Sstevel 	case SYSC_CFGA_RSTATE_EMPTY:
102329949e86Sstevel 		return (StNoMem);
102429949e86Sstevel 	case SYSC_CFGA_RSTATE_DISCONNECTED:
102529949e86Sstevel 		return (StBad);
102629949e86Sstevel 	case SYSC_CFGA_RSTATE_CONNECTED:
102729949e86Sstevel 		switch (ost) {
102829949e86Sstevel 		case SYSC_CFGA_OSTATE_UNCONFIGURED:
102929949e86Sstevel 			return (StSpare);
103029949e86Sstevel 		case SYSC_CFGA_OSTATE_CONFIGURED:
103129949e86Sstevel 			return (StActive);
103229949e86Sstevel 		default:
103329949e86Sstevel 			return (StUnknown);
103429949e86Sstevel 		}
103529949e86Sstevel 	default:
103629949e86Sstevel 		return (StUnknown);
103729949e86Sstevel 	}
103829949e86Sstevel }
103929949e86Sstevel 
104029949e86Sstevel static enum ac_bank_condition
104129949e86Sstevel ac_kstat_cond(sysc_cfga_cond_t cond)
104229949e86Sstevel {
104329949e86Sstevel 	switch (cond) {
104429949e86Sstevel 	case SYSC_CFGA_COND_UNKNOWN:
104529949e86Sstevel 		return (ConUnknown);
104629949e86Sstevel 	case SYSC_CFGA_COND_OK:
104729949e86Sstevel 		return (ConOK);
104829949e86Sstevel 	case SYSC_CFGA_COND_FAILING:
104929949e86Sstevel 		return (ConFailing);
105029949e86Sstevel 	case SYSC_CFGA_COND_FAILED:
105129949e86Sstevel 		return (ConFailed);
105229949e86Sstevel 	case SYSC_CFGA_COND_UNUSABLE:
105329949e86Sstevel 		return (ConBad);
105429949e86Sstevel 	default:
105529949e86Sstevel 		return (ConUnknown);
105629949e86Sstevel 	}
105729949e86Sstevel }
105829949e86Sstevel 
105929949e86Sstevel static int
106029949e86Sstevel ac_misc_kstat_update(kstat_t *ksp, int rw)
106129949e86Sstevel {
106229949e86Sstevel 	struct ac_kstat *acksp;
106329949e86Sstevel 	struct ac_soft_state *softsp;
106429949e86Sstevel 
106529949e86Sstevel 	acksp = (struct ac_kstat *)ksp->ks_data;
106629949e86Sstevel 	softsp = (struct ac_soft_state *)ksp->ks_private;
106729949e86Sstevel 	/* Need the NULL check in case kstat is about to be deleted. */
106829949e86Sstevel 	ASSERT(softsp->ac_ksp == NULL || ksp == softsp->ac_ksp);
106929949e86Sstevel 
107029949e86Sstevel 	/* this is a read-only kstat. Bail out on a write */
107129949e86Sstevel 	if (rw == KSTAT_WRITE) {
107229949e86Sstevel 		return (EACCES);
107329949e86Sstevel 	} else {
107429949e86Sstevel 		/*
107529949e86Sstevel 		 * copy the current state of the hardware into the
107629949e86Sstevel 		 * kstat structure.
107729949e86Sstevel 		 */
107829949e86Sstevel 		acksp->ac_memctl.value.ui64 = *softsp->ac_memctl;
107929949e86Sstevel 		acksp->ac_memdecode0.value.ui64 = *softsp->ac_memdecode0;
108029949e86Sstevel 		acksp->ac_memdecode1.value.ui64 = *softsp->ac_memdecode1;
108129949e86Sstevel 		acksp->ac_mccr.value.ui32 = *softsp->ac_mccr;
108229949e86Sstevel 		acksp->ac_counter.value.ui64 = *softsp->ac_counter;
108329949e86Sstevel 		acksp->ac_bank0_status.value.c[0] =
108429949e86Sstevel 		    ac_kstat_stat(softsp->bank[0].rstate,
108529949e86Sstevel 		    softsp->bank[0].ostate);
108629949e86Sstevel 		acksp->ac_bank0_status.value.c[1] =
108729949e86Sstevel 		    ac_kstat_cond(softsp->bank[0].condition);
108829949e86Sstevel 		acksp->ac_bank1_status.value.c[0] =
108929949e86Sstevel 		    ac_kstat_stat(softsp->bank[1].rstate,
109029949e86Sstevel 		    softsp->bank[1].ostate);
109129949e86Sstevel 		acksp->ac_bank1_status.value.c[1] =
109229949e86Sstevel 		    ac_kstat_cond(softsp->bank[1].condition);
109329949e86Sstevel 	}
109429949e86Sstevel 	return (0);
109529949e86Sstevel }
109629949e86Sstevel 
109729949e86Sstevel static int
109829949e86Sstevel ac_counters_kstat_update(kstat_t *ksp, int rw)
109929949e86Sstevel {
110029949e86Sstevel 	struct kstat_named *ac_counters_data;
110129949e86Sstevel 	struct ac_soft_state *softsp;
110229949e86Sstevel 	uint64_t pic_register;
110329949e86Sstevel 
110429949e86Sstevel 	ac_counters_data = (struct kstat_named *)ksp->ks_data;
110529949e86Sstevel 	softsp = (struct ac_soft_state *)ksp->ks_private;
110629949e86Sstevel 
110729949e86Sstevel 	/*
110829949e86Sstevel 	 * We need to start/restart the ac_timeout that will
110929949e86Sstevel 	 * return the AC counters to hot-plug mode after the
111029949e86Sstevel 	 * ac_hot_plug_timeout_interval has expired. We tell
111129949e86Sstevel 	 * ac_reset_timeout() whether this is a kstat_read or a
111229949e86Sstevel 	 * kstat_write call. If this fails we reject the kstat
111329949e86Sstevel 	 * operation.
111429949e86Sstevel 	 */
111529949e86Sstevel 	if (ac_reset_timeout(rw) != 0)
111629949e86Sstevel 		return (-1);
111729949e86Sstevel 
111829949e86Sstevel 
111929949e86Sstevel 	if (rw == KSTAT_WRITE) {
112029949e86Sstevel 		/*
112129949e86Sstevel 		 * Write the %pcr value to the softsp->ac_mccr.
112229949e86Sstevel 		 * This interface does not support writing to the
112329949e86Sstevel 		 * %pic.
112429949e86Sstevel 		 */
112529949e86Sstevel 		*softsp->ac_mccr =
112629949e86Sstevel 		    (uint32_t)ac_counters_data[0].value.ui64;
112729949e86Sstevel 	} else {
112829949e86Sstevel 		/*
112929949e86Sstevel 		 * Read %pcr and %pic register values and write them
113029949e86Sstevel 		 * into counters kstat.
113129949e86Sstevel 		 */
113229949e86Sstevel 
113329949e86Sstevel 		/* pcr */
113429949e86Sstevel 		ac_counters_data[0].value.ui64 = *softsp->ac_mccr;
113529949e86Sstevel 
113629949e86Sstevel 		pic_register = *softsp->ac_counter;
113729949e86Sstevel 		/*
113829949e86Sstevel 		 * ac pic register:
113929949e86Sstevel 		 *  (63:32) = pic1
114029949e86Sstevel 		 *  (31:00) = pic0
114129949e86Sstevel 		 */
114229949e86Sstevel 
114329949e86Sstevel 		/* pic0 */
114429949e86Sstevel 		ac_counters_data[1].value.ui64 =
114529949e86Sstevel 		    AC_COUNTER_TO_PIC0(pic_register);
114629949e86Sstevel 		/* pic1 */
114729949e86Sstevel 		ac_counters_data[2].value.ui64 =
114829949e86Sstevel 		    AC_COUNTER_TO_PIC1(pic_register);
114929949e86Sstevel 	}
115029949e86Sstevel 	return (0);
115129949e86Sstevel }
115229949e86Sstevel 
115329949e86Sstevel /*
115429949e86Sstevel  * Decode the memory state given to us and plug it into the soft state
115529949e86Sstevel  */
115629949e86Sstevel static void
115729949e86Sstevel ac_get_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
115829949e86Sstevel {
115929949e86Sstevel 	char	*property = (id == Bank0) ? AC_BANK0_STATUS : AC_BANK1_STATUS;
116029949e86Sstevel 	char	*propval;
116129949e86Sstevel 	int	proplen;
116229949e86Sstevel 	uint64_t memdec = (id == Bank0) ?
116329949e86Sstevel 	    *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
116429949e86Sstevel 	uint_t		grp_size;
116529949e86Sstevel 
116629949e86Sstevel 	softsp->bank[id].busy = 0;
116729949e86Sstevel 	softsp->bank[id].status_change = ddi_get_time();
116829949e86Sstevel 
116929949e86Sstevel 	if (GRP_SIZE_IS_SET(memdec)) {
117029949e86Sstevel 		grp_size = GRP_SPANMB(memdec);
117129949e86Sstevel 
117229949e86Sstevel 		/* determine the memory bank size (in MB) */
117329949e86Sstevel 		softsp->bank[id].real_size = softsp->bank[id].use_size =
117429949e86Sstevel 		    (id == Bank0) ? (grp_size / INTLV0(*softsp->ac_memctl)) :
117529949e86Sstevel 		    (grp_size / INTLV1(*softsp->ac_memctl));
117629949e86Sstevel 	} else {
117729949e86Sstevel 		softsp->bank[id].real_size = softsp->bank[id].use_size = 0;
117829949e86Sstevel 	}
117929949e86Sstevel 
118029949e86Sstevel 	/*
118129949e86Sstevel 	 * decode the memory bank property.  set condition based
118229949e86Sstevel 	 * on the values.
118329949e86Sstevel 	 */
118429949e86Sstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
118529949e86Sstevel 	    DDI_PROP_DONTPASS, property, (caddr_t)&propval, &proplen) ==
118629949e86Sstevel 	    DDI_PROP_SUCCESS) {
118729949e86Sstevel 		if (strcmp(propval, AC_BANK_NOMEM) == 0) {
118829949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
118929949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
119029949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
119129949e86Sstevel 		} else if (strcmp(propval, AC_BANK_OK) == 0) {
119229949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
119329949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
119429949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_OK;
119529949e86Sstevel 		} else if (strcmp(propval, AC_BANK_SPARE) == 0) {
119629949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
119729949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
119829949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
119929949e86Sstevel 		} else if (strcmp(propval, AC_BANK_FAILED) == 0) {
120029949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
120129949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
120229949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
120329949e86Sstevel 		} else {
120429949e86Sstevel 			cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
120529949e86Sstevel 			    "unknown %smemory state [%s]",
120629949e86Sstevel 			    ddi_get_instance(softsp->dip), softsp->board, id,
120729949e86Sstevel 			    (memdec & AC_MEM_VALID) ? "connected " : "",
120829949e86Sstevel 			    propval);
120929949e86Sstevel 			if (memdec & AC_MEM_VALID) {
121029949e86Sstevel 				softsp->bank[id].rstate =
121129949e86Sstevel 				    SYSC_CFGA_RSTATE_CONNECTED;
121229949e86Sstevel 				softsp->bank[id].ostate =
121329949e86Sstevel 				    SYSC_CFGA_OSTATE_CONFIGURED;
121429949e86Sstevel 				softsp->bank[id].condition =
121529949e86Sstevel 				    SYSC_CFGA_COND_OK;
121629949e86Sstevel 			} else {
121729949e86Sstevel 				softsp->bank[id].rstate =
121829949e86Sstevel 				    SYSC_CFGA_RSTATE_DISCONNECTED;
121929949e86Sstevel 				softsp->bank[id].ostate =
122029949e86Sstevel 				    SYSC_CFGA_OSTATE_UNCONFIGURED;
122129949e86Sstevel 				softsp->bank[id].condition =
122229949e86Sstevel 				    SYSC_CFGA_COND_UNUSABLE;
122329949e86Sstevel 			}
122429949e86Sstevel 		}
122529949e86Sstevel 
122629949e86Sstevel 		kmem_free(propval, proplen);
122729949e86Sstevel 	} else {
122829949e86Sstevel 		/* we don't have the property, deduce the state of memory */
122929949e86Sstevel 		if (memdec & AC_MEM_VALID) {
123029949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
123129949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
123229949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_OK;
123329949e86Sstevel 		} else {
123429949e86Sstevel 			/* could be an i/o board... */
123529949e86Sstevel 			softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
123629949e86Sstevel 			softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
123729949e86Sstevel 			softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
123829949e86Sstevel 		}
123929949e86Sstevel 	}
124029949e86Sstevel 
124129949e86Sstevel 	/* we assume that all other bank statuses are NOT valid */
124229949e86Sstevel 	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
124329949e86Sstevel 		if ((memdec & AC_MEM_VALID) != 0) {
124429949e86Sstevel 			uint64_t	base_pa;
124529949e86Sstevel 
124629949e86Sstevel 			ASSERT((*softsp->ac_memctl & AC_CSR_REFEN) != 0);
124729949e86Sstevel 			/* register existence in the memloc database */
124829949e86Sstevel 			base_pa = GRP_REALBASE(memdec);
124929949e86Sstevel 			fhc_add_memloc(softsp->board, base_pa, grp_size);
125029949e86Sstevel 		}
125129949e86Sstevel 	}
125229949e86Sstevel }
125329949e86Sstevel 
125429949e86Sstevel static void
125529949e86Sstevel ac_eval_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
125629949e86Sstevel {
125729949e86Sstevel 	uint64_t memdec = (id == Bank0) ?
125829949e86Sstevel 	    *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
125929949e86Sstevel 	uint64_t	base_pa;
126029949e86Sstevel 
126129949e86Sstevel 	/*
126229949e86Sstevel 	 * Downgrade the status of any bank that did not get
126329949e86Sstevel 	 * programmed.
126429949e86Sstevel 	 */
126529949e86Sstevel 	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED &&
126629949e86Sstevel 	    softsp->bank[id].ostate == SYSC_CFGA_OSTATE_UNCONFIGURED &&
126729949e86Sstevel 	    (memdec & AC_MEM_VALID) == 0) {
126829949e86Sstevel 		cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
126929949e86Sstevel 		    "spare memory bank not valid - it was ",
127029949e86Sstevel 		    ddi_get_instance(softsp->dip), softsp->board, id);
127129949e86Sstevel 		cmn_err(CE_WARN, "misconfigured by the system "
127229949e86Sstevel 		    "firmware.  Disabling...");
127329949e86Sstevel 		softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
127429949e86Sstevel 		softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
127529949e86Sstevel 		softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
127629949e86Sstevel 	}
127729949e86Sstevel 	/*
127829949e86Sstevel 	 * Log a message about good banks.
127929949e86Sstevel 	 */
128029949e86Sstevel 	if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
128129949e86Sstevel 		ASSERT((memdec & AC_MEM_VALID) != 0);
128229949e86Sstevel 		base_pa = GRP_REALBASE(memdec);
128329949e86Sstevel 
128429949e86Sstevel 		cmn_err(CE_CONT, "?ac%d board %d bank %d: "
128529949e86Sstevel 		    "base 0x%" PRIx64 " size %dmb rstate %d "
128629949e86Sstevel 		    "ostate %d condition %d\n",
128729949e86Sstevel 		    ddi_get_instance(softsp->dip),
128829949e86Sstevel 		    softsp->board, id, base_pa, softsp->bank[id].real_size,
128929949e86Sstevel 		    softsp->bank[id].rstate, softsp->bank[id].ostate,
129029949e86Sstevel 		    softsp->bank[id].condition);
129129949e86Sstevel 	}
129229949e86Sstevel }
129329949e86Sstevel 
129429949e86Sstevel /*ARGSUSED*/
129529949e86Sstevel static void
129629949e86Sstevel ac_ecache_flush(uint64_t a, uint64_t b)
129729949e86Sstevel {
129829949e86Sstevel 	cpu_flush_ecache();
129929949e86Sstevel }
130029949e86Sstevel 
130129949e86Sstevel static char *
130229949e86Sstevel ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event)
130329949e86Sstevel {
130429949e86Sstevel 	char *type_str;
130529949e86Sstevel 
130629949e86Sstevel 	switch (ostate) {
130729949e86Sstevel 	case SYSC_CFGA_OSTATE_UNCONFIGURED:
130829949e86Sstevel 		switch (event) {
130929949e86Sstevel 		case AC_AUDIT_OSTATE_UNCONFIGURE:
131029949e86Sstevel 			type_str = "unconfiguring";
131129949e86Sstevel 			break;
131229949e86Sstevel 		case AC_AUDIT_OSTATE_SUCCEEDED:
131329949e86Sstevel 		case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
131429949e86Sstevel 			type_str = "unconfigured";
131529949e86Sstevel 			break;
131629949e86Sstevel 		default:
131729949e86Sstevel 			type_str = "unconfigure?";
131829949e86Sstevel 			break;
131929949e86Sstevel 		}
132029949e86Sstevel 		break;
132129949e86Sstevel 	case SYSC_CFGA_OSTATE_CONFIGURED:
132229949e86Sstevel 		switch (event) {
132329949e86Sstevel 		case AC_AUDIT_OSTATE_CONFIGURE:
132429949e86Sstevel 			type_str = "configuring";
132529949e86Sstevel 			break;
132629949e86Sstevel 		case AC_AUDIT_OSTATE_SUCCEEDED:
132729949e86Sstevel 		case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
132829949e86Sstevel 			type_str = "configured";
132929949e86Sstevel 			break;
133029949e86Sstevel 		default:
133129949e86Sstevel 			type_str = "configure?";
133229949e86Sstevel 			break;
133329949e86Sstevel 		}
133429949e86Sstevel 		break;
133529949e86Sstevel 
133629949e86Sstevel 	default:
133729949e86Sstevel 		type_str = "undefined occupant state";
133829949e86Sstevel 		break;
133929949e86Sstevel 	}
134029949e86Sstevel 	return (type_str);
134129949e86Sstevel }
134229949e86Sstevel 
134329949e86Sstevel static void
134429949e86Sstevel ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt)
134529949e86Sstevel {
134629949e86Sstevel 	struct ac_soft_state *softsp = pkt->softsp;
134729949e86Sstevel 
134829949e86Sstevel 	switch (event) {
134929949e86Sstevel 		case AC_AUDIT_OSTATE_CONFIGURE:
135029949e86Sstevel 			cmn_err(CE_NOTE,
135129949e86Sstevel 			    "%s memory bank %d in slot %d",
135229949e86Sstevel 			    ac_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
135329949e86Sstevel 			    event), pkt->bank,
135429949e86Sstevel 			    softsp->board);
135529949e86Sstevel 			break;
135629949e86Sstevel 		case AC_AUDIT_OSTATE_UNCONFIGURE:
135729949e86Sstevel 			cmn_err(CE_NOTE,
135829949e86Sstevel 			    "%s memory bank %d in slot %d",
135929949e86Sstevel 			    ac_ostate_typestr(
136029949e86Sstevel 			    SYSC_CFGA_OSTATE_UNCONFIGURED,
136129949e86Sstevel 			    event), pkt->bank,
136229949e86Sstevel 			    softsp->board);
136329949e86Sstevel 			break;
136429949e86Sstevel 		case AC_AUDIT_OSTATE_SUCCEEDED:
136529949e86Sstevel 			cmn_err(CE_NOTE,
136629949e86Sstevel 			    "memory bank %d in slot %d is %s",
136729949e86Sstevel 			    pkt->bank, softsp->board,
136829949e86Sstevel 			    ac_ostate_typestr(
136929949e86Sstevel 			    softsp->bank[pkt->bank].ostate,
137029949e86Sstevel 			    event));
137129949e86Sstevel 			break;
137229949e86Sstevel 		case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
137329949e86Sstevel 			cmn_err(CE_NOTE,
137429949e86Sstevel 			"memory bank %d in slot %d not %s",
137529949e86Sstevel 			    pkt->bank,
137629949e86Sstevel 			    softsp->board,
137729949e86Sstevel 			    ac_ostate_typestr(
137829949e86Sstevel 			    SYSC_CFGA_OSTATE_CONFIGURED,
137929949e86Sstevel 			    event));
138029949e86Sstevel 			break;
138129949e86Sstevel 		case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
138229949e86Sstevel 			cmn_err(CE_NOTE,
138329949e86Sstevel 			    "memory bank %d in slot %d not %s",
138429949e86Sstevel 			    pkt->bank,
138529949e86Sstevel 			    softsp->board,
138629949e86Sstevel 			    ac_ostate_typestr(
138729949e86Sstevel 			    SYSC_CFGA_OSTATE_UNCONFIGURED,
138829949e86Sstevel 			    event));
138929949e86Sstevel 			break;
139029949e86Sstevel 		default:
139129949e86Sstevel 			cmn_err(CE_NOTE,
139229949e86Sstevel 			    "unknown audit of memory bank %d in slot %d",
139329949e86Sstevel 			    pkt->bank, softsp->board);
139429949e86Sstevel 			break;
139529949e86Sstevel 	}
139629949e86Sstevel }
139729949e86Sstevel 
139829949e86Sstevel #include <vm/page.h>
139929949e86Sstevel #include <vm/hat.h>
140029949e86Sstevel 
140129949e86Sstevel static int
140229949e86Sstevel ac_mem_exercise(ac_cfga_pkt_t *pkt, int flag)
140329949e86Sstevel {
140429949e86Sstevel 	struct ac_mem_info *mem_info;
140529949e86Sstevel 	pfn_t base;
140629949e86Sstevel 	pgcnt_t npgs;
140729949e86Sstevel 
140829949e86Sstevel 	mem_info = &pkt->softsp->bank[pkt->bank];
140929949e86Sstevel 	if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) {
141029949e86Sstevel 		uint64_t base_pa, bank_size;
141129949e86Sstevel 		uint64_t decode;
141229949e86Sstevel 
141329949e86Sstevel 		decode = (pkt->bank == Bank0) ?
141429949e86Sstevel 		    *pkt->softsp->ac_memdecode0 : *pkt->softsp->ac_memdecode1;
141529949e86Sstevel 		base_pa = GRP_REALBASE(decode);
141629949e86Sstevel 		bank_size = GRP_UK2SPAN(decode);
141729949e86Sstevel 
141829949e86Sstevel 		base = base_pa >> PAGESHIFT;
141929949e86Sstevel 		npgs = bank_size >> PAGESHIFT;
142029949e86Sstevel 	} else {
142129949e86Sstevel 		base = 0;
142229949e86Sstevel 		npgs = 0;
142329949e86Sstevel 	}
142429949e86Sstevel 	switch (pkt->cmd_cfga.arg) {
142529949e86Sstevel 	case AC_MEMX_RELOCATE_ALL: {
142629949e86Sstevel 		pfn_t pfn, pglim;
142729949e86Sstevel 		struct ac_memx_relocate_stats rstat;
142829949e86Sstevel 
142929949e86Sstevel 		if (npgs == 0 ||
143029949e86Sstevel 		    mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
143129949e86Sstevel 			return (EINVAL);
143229949e86Sstevel 		}
143329949e86Sstevel 		if (mem_info->busy != FALSE) {
143429949e86Sstevel 			return (EBUSY);
143529949e86Sstevel 		}
143629949e86Sstevel 		bzero(&rstat, sizeof (rstat));
143729949e86Sstevel 		rstat.base = (uint_t)base;
143829949e86Sstevel 		rstat.npgs = (uint_t)npgs;
143929949e86Sstevel 		pglim = base + npgs;
144029949e86Sstevel 		for (pfn = base; pfn < pglim; pfn++) {
144129949e86Sstevel 			page_t *pp, *pp_repl;
144229949e86Sstevel 
144329949e86Sstevel 		retry:
144429949e86Sstevel 			pp = page_numtopp_nolock(pfn);
144529949e86Sstevel 			if (pp != NULL) {
144629949e86Sstevel 				if (!page_trylock(pp, SE_EXCL)) {
144729949e86Sstevel 					pp = NULL;
144829949e86Sstevel 					rstat.nolock++;
144929949e86Sstevel 				}
145029949e86Sstevel 				if (pp != NULL && page_pptonum(pp) != pfn) {
145129949e86Sstevel 					page_unlock(pp);
145229949e86Sstevel 					goto retry;
145329949e86Sstevel 				}
145429949e86Sstevel 			} else {
145529949e86Sstevel 				rstat.nopaget++;
145629949e86Sstevel 			}
145729949e86Sstevel 			if (pp != NULL && PP_ISFREE(pp)) {
145829949e86Sstevel 				page_unlock(pp);
145929949e86Sstevel 				rstat.isfree++;
146029949e86Sstevel 				pp = NULL;
146129949e86Sstevel 			}
146229949e86Sstevel 			if (pp != NULL) {
146329949e86Sstevel 				spgcnt_t npgs;
146429949e86Sstevel 				int result;
146529949e86Sstevel 
146629949e86Sstevel 				pp_repl = NULL;
146729949e86Sstevel 				result = page_relocate(&pp, &pp_repl, 1, 1,
146829949e86Sstevel 				    &npgs, NULL);
146929949e86Sstevel 				if (result == 0) {
147029949e86Sstevel 					while (npgs-- > 0) {
147129949e86Sstevel 						page_t *tpp;
147229949e86Sstevel 
147329949e86Sstevel 						ASSERT(pp_repl != NULL);
147429949e86Sstevel 						tpp = pp_repl;
147529949e86Sstevel 						page_sub(&pp_repl, tpp);
147629949e86Sstevel 						page_unlock(tpp);
147729949e86Sstevel 					}
147829949e86Sstevel 
147929949e86Sstevel 					rstat.reloc++;
148029949e86Sstevel 				} else {
148129949e86Sstevel 					page_unlock(pp);
148229949e86Sstevel 					rstat.noreloc++;
148329949e86Sstevel 				}
148429949e86Sstevel 			}
148529949e86Sstevel 		}
148629949e86Sstevel 		if (pkt->cmd_cfga.private != NULL && ddi_copyout(&rstat,
148729949e86Sstevel 		    pkt->cmd_cfga.private, sizeof (rstat), flag) != 0)
148829949e86Sstevel 			return (EFAULT);
148929949e86Sstevel 		return (DDI_SUCCESS);
149029949e86Sstevel 	}
149129949e86Sstevel 
149229949e86Sstevel 	default:
149329949e86Sstevel 		return (EINVAL);
149429949e86Sstevel 	}
149529949e86Sstevel }
149629949e86Sstevel 
149729949e86Sstevel static int
149829949e86Sstevel ac_reset_timeout(int rw)
149929949e86Sstevel {
150029949e86Sstevel 	mutex_enter(&ac_hot_plug_mode_mutex);
150129949e86Sstevel 
150229949e86Sstevel 	if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
150329949e86Sstevel 	    (rw == KSTAT_READ)) {
150429949e86Sstevel 		/*
150529949e86Sstevel 		 * We are in hot-plug mode. A kstat_read is not
150629949e86Sstevel 		 * going to affect this. return 0 to allow the
150729949e86Sstevel 		 * kstat_read to continue.
150829949e86Sstevel 		 */
150929949e86Sstevel 		mutex_exit(&ac_hot_plug_mode_mutex);
151029949e86Sstevel 		return (0);
151129949e86Sstevel 
151229949e86Sstevel 	} else if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
151329949e86Sstevel 	    (rw == KSTAT_WRITE)) {
151429949e86Sstevel 		/*
151529949e86Sstevel 		 * There are no pending timeouts and we have received a
151629949e86Sstevel 		 * kstat_write request so we must be transitioning
151729949e86Sstevel 		 * from "hot-plug" mode to non "hot-plug" mode.
151829949e86Sstevel 		 * Try to lock all boards before allowing the kstat_write.
151929949e86Sstevel 		 */
152029949e86Sstevel 		if (ac_enter_transition() == TRUE)
152129949e86Sstevel 			fhc_bdlist_unlock();
152229949e86Sstevel 		else {
152329949e86Sstevel 			/* cannot lock boards so fail */
152429949e86Sstevel 			mutex_exit(&ac_hot_plug_mode_mutex);
152529949e86Sstevel 			return (-1);
152629949e86Sstevel 		}
152729949e86Sstevel 
152829949e86Sstevel 		/*
152929949e86Sstevel 		 * We need to display a Warning about hot-plugging any
153029949e86Sstevel 		 * boards. This message is only needed when we are
153129949e86Sstevel 		 * transitioning out of "hot-plug" mode.
153229949e86Sstevel 		 */
153329949e86Sstevel 		cmn_err(CE_WARN, "This machine is being taken out of "
153429949e86Sstevel 		    "hot-plug mode.");
153529949e86Sstevel 		cmn_err(CE_CONT, "Do not attempt to hot-plug boards "
153629949e86Sstevel 		    "or power supplies in this system until further notice.");
153729949e86Sstevel 
153829949e86Sstevel 	} else if (ac_hot_plug_timeout != (timeout_id_t)NULL) {
153929949e86Sstevel 		/*
154029949e86Sstevel 		 * There is a pending timeout so we must already be
154129949e86Sstevel 		 * in non "hot-plug" mode. It doesn't matter if the
154229949e86Sstevel 		 * kstat request is a read or a write.
154329949e86Sstevel 		 *
154429949e86Sstevel 		 * We need to cancel the existing timeout.
154529949e86Sstevel 		 */
154629949e86Sstevel 		(void) untimeout(ac_hot_plug_timeout);
154729949e86Sstevel 		ac_hot_plug_timeout = NULL;
154829949e86Sstevel 	}
154929949e86Sstevel 
155029949e86Sstevel 	/*
155129949e86Sstevel 	 * create a new timeout.
155229949e86Sstevel 	 */
155329949e86Sstevel 	ac_hot_plug_timeout = timeout(ac_timeout, NULL,
155429949e86Sstevel 	    drv_usectohz(ac_hot_plug_timeout_interval * 1000000));
155529949e86Sstevel 
155629949e86Sstevel 	mutex_exit(&ac_hot_plug_mode_mutex);
155729949e86Sstevel 	return (0);
155829949e86Sstevel }
155929949e86Sstevel 
156029949e86Sstevel static void
156129949e86Sstevel ac_timeout(void *arg)
156229949e86Sstevel {
156329949e86Sstevel 	struct ac_soft_state *softsp;
156429949e86Sstevel 	fhc_bd_t	*board;
156529949e86Sstevel 
156629949e86Sstevel #ifdef lint
156729949e86Sstevel 	arg = arg;
156829949e86Sstevel #endif /* lint */
156929949e86Sstevel 
157029949e86Sstevel 	ac_hot_plug_timeout = (timeout_id_t)NULL;
157129949e86Sstevel 
157229949e86Sstevel 	(void) fhc_bdlist_lock(-1);
157329949e86Sstevel 
157429949e86Sstevel 	/*
157529949e86Sstevel 	 * Foreach ac in the board list we need to
157629949e86Sstevel 	 * re-program the pcr into "hot-plug" mode.
157729949e86Sstevel 	 * We also program the pic register with the
157829949e86Sstevel 	 * bus pause timing
157929949e86Sstevel 	 */
158029949e86Sstevel 	board = fhc_bd_first();
158129949e86Sstevel 	while (board != NULL) {
158229949e86Sstevel 		softsp = board->ac_softsp;
158329949e86Sstevel 		if (softsp == NULL) {
158429949e86Sstevel 			/*
158529949e86Sstevel 			 * This board must not have an AC.
158629949e86Sstevel 			 * Skip it and move on.
158729949e86Sstevel 			 */
158829949e86Sstevel 			board = fhc_bd_next(board);
158929949e86Sstevel 			continue;
159029949e86Sstevel 		}
159129949e86Sstevel 		/* program the pcr into hot-plug mode */
159229949e86Sstevel 		*softsp->ac_mccr = AC_CLEAR_PCR(*softsp->ac_mccr);
159329949e86Sstevel 		*softsp->ac_mccr = AC_SET_HOT_PLUG(*softsp->ac_mccr);
159429949e86Sstevel 
159529949e86Sstevel 		/* program the pic with the bus pause time value */
159629949e86Sstevel 		*softsp->ac_counter = AC_SET_PIC_BUS_PAUSE(softsp->board);
159729949e86Sstevel 
159829949e86Sstevel 		/* get the next board */
159929949e86Sstevel 		board = fhc_bd_next(board);
160029949e86Sstevel 	}
160129949e86Sstevel 
160229949e86Sstevel 	ac_exit_transition();
160329949e86Sstevel 
160429949e86Sstevel 	fhc_bdlist_unlock();
160529949e86Sstevel 
160629949e86Sstevel 	/*
160729949e86Sstevel 	 * It is now safe to start hot-plugging again. We need
160829949e86Sstevel 	 * to display a message.
160929949e86Sstevel 	 */
161029949e86Sstevel 	cmn_err(CE_NOTE, "This machine is now in hot-plug mode.");
161129949e86Sstevel 	cmn_err(CE_CONT, "Board and power supply hot-plug operations "
161229949e86Sstevel 	    "can be resumed.");
161329949e86Sstevel }
161429949e86Sstevel 
161529949e86Sstevel /*
161629949e86Sstevel  * This function will acquire the lock and set the in_transition
161729949e86Sstevel  * bit for all the slots.  If the slots are being used,
161829949e86Sstevel  * we return FALSE; else set in_transition and return TRUE.
161929949e86Sstevel  */
162029949e86Sstevel static int
162129949e86Sstevel ac_enter_transition(void)
162229949e86Sstevel {
162329949e86Sstevel 	fhc_bd_t	*list;
162429949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
162529949e86Sstevel 
162629949e86Sstevel 	/* mutex lock the structure */
162729949e86Sstevel 	(void) fhc_bdlist_lock(-1);
162829949e86Sstevel 
162929949e86Sstevel 	list = fhc_bd_clock();
163029949e86Sstevel 
163129949e86Sstevel 	/* change the in_transition bit */
163229949e86Sstevel 	sysc_stat_lk = &list->sc;
163329949e86Sstevel 	if (sysc_stat_lk->in_transition == TRUE) {
163429949e86Sstevel 		fhc_bdlist_unlock();
163529949e86Sstevel 		return (FALSE);
163629949e86Sstevel 	} else {
163729949e86Sstevel 		sysc_stat_lk->in_transition = TRUE;
163829949e86Sstevel 		return (TRUE);
163929949e86Sstevel 	}
164029949e86Sstevel }
164129949e86Sstevel 
164229949e86Sstevel /*
164329949e86Sstevel  * clear the in_transition bit for all the slots.
164429949e86Sstevel  */
164529949e86Sstevel static void
164629949e86Sstevel ac_exit_transition(void)
164729949e86Sstevel {
164829949e86Sstevel 	fhc_bd_t	*list;
164929949e86Sstevel 	sysc_cfga_stat_t *sysc_stat_lk;
165029949e86Sstevel 
165129949e86Sstevel 	ASSERT(fhc_bdlist_locked());
165229949e86Sstevel 
165329949e86Sstevel 	list = fhc_bd_clock();
165429949e86Sstevel 
165529949e86Sstevel 	sysc_stat_lk = &list->sc;
165629949e86Sstevel 	ASSERT(sysc_stat_lk->in_transition == TRUE);
165729949e86Sstevel 	sysc_stat_lk->in_transition = FALSE;
165829949e86Sstevel }
1659