xref: /illumos-gate/usr/src/uts/sun4u/sunfire/io/environ.c (revision 89b43686)
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/ivintr.h>
4129949e86Sstevel #include <sys/callb.h>
4229949e86Sstevel #include <sys/autoconf.h>
4329949e86Sstevel #include <sys/intreg.h>
4429949e86Sstevel #include <sys/modctl.h>
4529949e86Sstevel #include <sys/proc.h>
4629949e86Sstevel #include <sys/disp.h>
4729949e86Sstevel #include <sys/fhc.h>
4829949e86Sstevel #include <sys/environ.h>
4929949e86Sstevel 
5029949e86Sstevel /* Useful debugging Stuff */
5129949e86Sstevel #include <sys/nexusdebug.h>
5229949e86Sstevel 
5329949e86Sstevel /*
5429949e86Sstevel  * Function prototypes
5529949e86Sstevel  */
5629949e86Sstevel static int environ_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
5729949e86Sstevel 
5829949e86Sstevel static int environ_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
5929949e86Sstevel 
6029949e86Sstevel static int environ_init(struct environ_soft_state *softsp);
6129949e86Sstevel 
6229949e86Sstevel void environ_add_temp_kstats(struct environ_soft_state *softsp);
6329949e86Sstevel 
6429949e86Sstevel static void overtemp_wakeup(void *);
6529949e86Sstevel 
6629949e86Sstevel static void environ_overtemp_poll(void);
6729949e86Sstevel 
6829949e86Sstevel /*
6929949e86Sstevel  * Configuration data structures
7029949e86Sstevel  */
7129949e86Sstevel static struct cb_ops environ_cb_ops = {
7229949e86Sstevel 	nulldev,			/* open */
7329949e86Sstevel 	nulldev,			/* close */
7429949e86Sstevel 	nulldev,			/* strategy */
7529949e86Sstevel 	nulldev,			/* print */
7629949e86Sstevel 	nodev,				/* dump */
7729949e86Sstevel 	nulldev,			/* read */
7829949e86Sstevel 	nulldev,			/* write */
7929949e86Sstevel 	nulldev,			/* ioctl */
8029949e86Sstevel 	nodev,				/* devmap */
8129949e86Sstevel 	nodev,				/* mmap */
8229949e86Sstevel 	nodev,				/* segmap */
8329949e86Sstevel 	nochpoll,			/* poll */
8429949e86Sstevel 	ddi_prop_op,			/* cb_prop_op */
8529949e86Sstevel 	0,				/* streamtab */
8629949e86Sstevel 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
8729949e86Sstevel 	CB_REV,				/* rev */
8829949e86Sstevel 	nodev,				/* cb_aread */
8929949e86Sstevel 	nodev				/* cb_awrite */
9029949e86Sstevel };
9129949e86Sstevel 
9229949e86Sstevel static struct dev_ops environ_ops = {
9329949e86Sstevel 	DEVO_REV,			/* devo_rev, */
9429949e86Sstevel 	0,				/* refcnt */
9529949e86Sstevel 	ddi_no_info,			/* getinfo */
9629949e86Sstevel 	nulldev,			/* identify */
9729949e86Sstevel 	nulldev,			/* probe */
9829949e86Sstevel 	environ_attach,			/* attach */
9929949e86Sstevel 	environ_detach,			/* detach */
10029949e86Sstevel 	nulldev,			/* reset */
10129949e86Sstevel 	&environ_cb_ops,		/* cb_ops */
10229949e86Sstevel 	(struct bus_ops *)0,		/* bus_ops */
10319397407SSherry Moore 	nulldev,			/* power */
10419397407SSherry Moore 	ddi_quiesce_not_needed,			/* quiesce */
10529949e86Sstevel };
10629949e86Sstevel 
10729949e86Sstevel void *environp;			/* environ soft state hook */
10829949e86Sstevel 
10929949e86Sstevel /*
11029949e86Sstevel  * Mutex used to protect the soft state list and their data.
11129949e86Sstevel  */
11229949e86Sstevel static kmutex_t overtemp_mutex;
11329949e86Sstevel 
11429949e86Sstevel /* The CV is used to wakeup the thread when needed. */
11529949e86Sstevel static kcondvar_t overtemp_cv;
11629949e86Sstevel 
11729949e86Sstevel /* linked list of all environ soft states */
11829949e86Sstevel struct environ_soft_state *tempsp_list = NULL;
11929949e86Sstevel 
12029949e86Sstevel /* overtemp polling routine timeout delay */
12129949e86Sstevel static int overtemp_timeout_sec = OVERTEMP_TIMEOUT_SEC;
12229949e86Sstevel 
12329949e86Sstevel /* Should the environ_overtemp_poll thread be running? */
12429949e86Sstevel static int environ_do_overtemp_thread = 1;
12529949e86Sstevel 
12629949e86Sstevel /* Indicates whether or not the overtemp thread has been started */
12729949e86Sstevel static int environ_overtemp_thread_started = 0;
12829949e86Sstevel 
12929949e86Sstevel extern struct mod_ops mod_driverops;
13029949e86Sstevel 
13129949e86Sstevel static struct modldrv modldrv = {
13219397407SSherry Moore 	&mod_driverops,		/* module type, this one is a driver */
13319397407SSherry Moore 	"Environment Leaf",	/* name of module */
13419397407SSherry Moore 	&environ_ops,		/* driver ops */
13529949e86Sstevel };
13629949e86Sstevel 
13729949e86Sstevel static struct modlinkage modlinkage = {
13829949e86Sstevel 	MODREV_1,
13929949e86Sstevel 	(void *)&modldrv,
14029949e86Sstevel 	NULL
14129949e86Sstevel };
14229949e86Sstevel 
14329949e86Sstevel /*
14429949e86Sstevel  * These are the module initialization routines.
14529949e86Sstevel  */
14629949e86Sstevel 
14729949e86Sstevel int
_init(void)14829949e86Sstevel _init(void)
14929949e86Sstevel {
15029949e86Sstevel 	int error;
15129949e86Sstevel 
15229949e86Sstevel 	if ((error = ddi_soft_state_init(&environp,
15329949e86Sstevel 	    sizeof (struct environ_soft_state), 1)) != 0)
15429949e86Sstevel 		return (error);
15529949e86Sstevel 
15629949e86Sstevel 	return (mod_install(&modlinkage));
15729949e86Sstevel }
15829949e86Sstevel 
15929949e86Sstevel int
_fini(void)16029949e86Sstevel _fini(void)
16129949e86Sstevel {
16229949e86Sstevel 	int error;
16329949e86Sstevel 
16429949e86Sstevel 	if ((error = mod_remove(&modlinkage)) != 0)
16529949e86Sstevel 		return (error);
16629949e86Sstevel 
16729949e86Sstevel 	ddi_soft_state_fini(&environp);
16829949e86Sstevel 	return (0);
16929949e86Sstevel }
17029949e86Sstevel 
17129949e86Sstevel int
_info(struct modinfo * modinfop)17229949e86Sstevel _info(struct modinfo *modinfop)
17329949e86Sstevel {
17429949e86Sstevel 	return (mod_info(&modlinkage, modinfop));
17529949e86Sstevel }
17629949e86Sstevel 
17729949e86Sstevel static int
environ_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)17829949e86Sstevel environ_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
17929949e86Sstevel {
18029949e86Sstevel 	struct environ_soft_state *softsp;
18129949e86Sstevel 	int instance;
18229949e86Sstevel 
18329949e86Sstevel 	switch (cmd) {
18429949e86Sstevel 	case DDI_ATTACH:
18529949e86Sstevel 		break;
18629949e86Sstevel 
18729949e86Sstevel 	case DDI_RESUME:
18829949e86Sstevel 		return (DDI_SUCCESS);
18929949e86Sstevel 
19029949e86Sstevel 	default:
19129949e86Sstevel 		return (DDI_FAILURE);
19229949e86Sstevel 	}
19329949e86Sstevel 
19429949e86Sstevel 	instance = ddi_get_instance(devi);
19529949e86Sstevel 
19629949e86Sstevel 	if (ddi_soft_state_zalloc(environp, instance) != DDI_SUCCESS)
19729949e86Sstevel 		return (DDI_FAILURE);
19829949e86Sstevel 
19929949e86Sstevel 	softsp = ddi_get_soft_state(environp, instance);
20029949e86Sstevel 
20129949e86Sstevel 	/* Set the dip in the soft state */
20229949e86Sstevel 	softsp->dip = devi;
20329949e86Sstevel 
20429949e86Sstevel 	/*
20529949e86Sstevel 	 * The DDI documentation on ddi_getprop() routine says that
20629949e86Sstevel 	 * you should always use the real dev_t when calling it,
20729949e86Sstevel 	 * but all calls found in uts use either DDI_DEV_T_ANY
20829949e86Sstevel 	 * or DDI_DEV_T_NONE. No notes either on how to find the real
20929949e86Sstevel 	 * dev_t. So we are doing it in two steps.
21029949e86Sstevel 	 */
21129949e86Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
21229949e86Sstevel 
21329949e86Sstevel 	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
21429949e86Sstevel 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
21529949e86Sstevel 		cmn_err(CE_WARN, "environ%d: unable to retrieve %s property",
21619397407SSherry Moore 		    instance, OBP_BOARDNUM);
21729949e86Sstevel 		goto bad;
21829949e86Sstevel 	}
21929949e86Sstevel 
22029949e86Sstevel 	DPRINTF(ENVIRON_ATTACH_DEBUG, ("environ: devi= 0x%p\n, softsp=0x%p,",
22107d06da5SSurya Prakki 	    (void *)devi, (void *)softsp));
22229949e86Sstevel 
22329949e86Sstevel 	/*
22429949e86Sstevel 	 * Init the temperature device here. We start the overtemp
22529949e86Sstevel 	 * polling thread here.
22629949e86Sstevel 	 */
22729949e86Sstevel 	if (environ_init(softsp) != DDI_SUCCESS)
22829949e86Sstevel 		goto bad;
22929949e86Sstevel 
23029949e86Sstevel 	/* nothing to suspend/resume here */
23129949e86Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
23219397407SSherry Moore 	    "pm-hardware-state", "no-suspend-resume");
23329949e86Sstevel 
23429949e86Sstevel 	ddi_report_dev(devi);
23529949e86Sstevel 
23629949e86Sstevel 	if (environ_overtemp_thread_started == 0) {
23729949e86Sstevel 		/*
23829949e86Sstevel 		 * set up the overtemp mutex and condition variable before
23929949e86Sstevel 		 * starting the thread.
24029949e86Sstevel 		 */
24129949e86Sstevel 		mutex_init(&overtemp_mutex, NULL, MUTEX_DEFAULT, NULL);
24229949e86Sstevel 		cv_init(&overtemp_cv, NULL, CV_DRIVER, NULL);
24329949e86Sstevel 
24429949e86Sstevel 		/* Start the overtemp polling thread now. */
24529949e86Sstevel 		(void) thread_create(NULL, 0, (void (*)())environ_overtemp_poll,
24629949e86Sstevel 		    NULL, 0, &p0, TS_RUN, minclsyspri);
24729949e86Sstevel 		environ_overtemp_thread_started++;
24829949e86Sstevel 	}
24929949e86Sstevel 
25029949e86Sstevel 	(void) fhc_bdlist_lock(softsp->board);
25129949e86Sstevel 	fhc_bd_env_set(softsp->board, (void *)softsp);
25229949e86Sstevel 	fhc_bdlist_unlock();
25329949e86Sstevel 
25429949e86Sstevel 	return (DDI_SUCCESS);
25529949e86Sstevel 
25629949e86Sstevel bad:
25729949e86Sstevel 	ddi_soft_state_free(environp, instance);
25829949e86Sstevel 	return (DDI_FAILURE);
25929949e86Sstevel }
26029949e86Sstevel 
26129949e86Sstevel /* ARGSUSED */
26229949e86Sstevel static int
environ_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)26329949e86Sstevel environ_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
26429949e86Sstevel {
26529949e86Sstevel 	int instance;
26629949e86Sstevel 	struct environ_soft_state *softsp;
26729949e86Sstevel 	struct environ_soft_state **vect;	/* used in list deletion */
26829949e86Sstevel 	struct environ_soft_state *temp;	/* used in list deletion */
26929949e86Sstevel 
27029949e86Sstevel 	/* get the instance of this devi */
27129949e86Sstevel 	instance = ddi_get_instance(devi);
27229949e86Sstevel 
27329949e86Sstevel 	/* get the soft state pointer for this device node */
27429949e86Sstevel 	softsp = ddi_get_soft_state(environp, instance);
27529949e86Sstevel 
27629949e86Sstevel 	switch (cmd) {
27729949e86Sstevel 	case DDI_SUSPEND:
27829949e86Sstevel 		return (DDI_SUCCESS);
27929949e86Sstevel 
28029949e86Sstevel 	case DDI_DETACH:
28129949e86Sstevel 		(void) fhc_bdlist_lock(softsp->board);
28229949e86Sstevel 		if (fhc_bd_detachable(softsp->board))
28329949e86Sstevel 			break;
28429949e86Sstevel 		else
28529949e86Sstevel 			fhc_bdlist_unlock();
28629949e86Sstevel 		/* FALLTHROUGH */
28729949e86Sstevel 
28829949e86Sstevel 	default:
28929949e86Sstevel 		return (DDI_FAILURE);
29029949e86Sstevel 	}
29129949e86Sstevel 
29229949e86Sstevel 	fhc_bd_env_set(softsp->board, NULL);
29329949e86Sstevel 
29429949e86Sstevel 	fhc_bdlist_unlock();
29529949e86Sstevel 
29629949e86Sstevel 	/* remove the environmental kstats if they were allocated */
29729949e86Sstevel 	if (softsp->environ_ksp)
29829949e86Sstevel 		kstat_delete(softsp->environ_ksp);
29929949e86Sstevel 	if (softsp->environ_oksp)
30029949e86Sstevel 		kstat_delete(softsp->environ_oksp);
30129949e86Sstevel 
30229949e86Sstevel 	/*
30329949e86Sstevel 	 * remove from soft state pointer from the singly linked list of
30429949e86Sstevel 	 * soft state pointers for temperature monitoring.
30529949e86Sstevel 	 */
30629949e86Sstevel 	mutex_enter(&overtemp_mutex);
30729949e86Sstevel 
30829949e86Sstevel 	/*
30929949e86Sstevel 	 * find the soft state for this instance in the soft state list
31029949e86Sstevel 	 * and remove it from the list
31129949e86Sstevel 	 */
31229949e86Sstevel 	for (temp = tempsp_list, vect = &tempsp_list; temp != NULL;
31329949e86Sstevel 	    vect = &temp->next, temp = temp->next) {
31429949e86Sstevel 		if (temp == softsp) {
31529949e86Sstevel 			*vect = temp->next;
31629949e86Sstevel 			break;
31729949e86Sstevel 		}
31829949e86Sstevel 	}
31929949e86Sstevel 
32029949e86Sstevel 	mutex_exit(&overtemp_mutex);
32129949e86Sstevel 
32229949e86Sstevel 	/* unmap the registers (if they have been mapped) */
32329949e86Sstevel 	if (softsp->temp_reg)
32429949e86Sstevel 		ddi_unmap_regs(devi, 0, (caddr_t *)&softsp->temp_reg, 0, 0);
32529949e86Sstevel 
32629949e86Sstevel 	/* deallocate the soft state instance */
32729949e86Sstevel 	ddi_soft_state_free(environp, instance);
32829949e86Sstevel 
32929949e86Sstevel 	ddi_prop_remove_all(devi);
33029949e86Sstevel 
33129949e86Sstevel 	return (DDI_SUCCESS);
33229949e86Sstevel }
33329949e86Sstevel 
33429949e86Sstevel static int
environ_init(struct environ_soft_state * softsp)33529949e86Sstevel environ_init(struct environ_soft_state *softsp)
33629949e86Sstevel {
33729949e86Sstevel 	uchar_t tmp;
33829949e86Sstevel 
33929949e86Sstevel 	/*
34029949e86Sstevel 	 * If this environment node is on a CPU-less system board, i.e.,
34129949e86Sstevel 	 * board type MEM_TYPE, then we do not want to map in, read
34229949e86Sstevel 	 * the temperature register, create the polling entry for
34329949e86Sstevel 	 * the overtemp polling thread, or create a kstat entry.
34429949e86Sstevel 	 *
34529949e86Sstevel 	 * The reason for this is that when no CPU modules are present
34629949e86Sstevel 	 * on a CPU/Memory board, then the thermistors are not present,
34729949e86Sstevel 	 * and the output of the A/D convertor is the max 8 bit value (0xFF)
34829949e86Sstevel 	 */
34929949e86Sstevel 	if (fhc_bd_type(softsp->board) == MEM_BOARD) {
35029949e86Sstevel 		return (DDI_SUCCESS);
35129949e86Sstevel 	}
35229949e86Sstevel 
35329949e86Sstevel 	/*
35429949e86Sstevel 	 * Map in the temperature register. Once the temperature register
35529949e86Sstevel 	 * is mapped, the timeout thread can read the temperature and
35629949e86Sstevel 	 * update the temperature in the softsp.
35729949e86Sstevel 	 */
35829949e86Sstevel 	if (ddi_map_regs(softsp->dip, 0,
35929949e86Sstevel 	    (caddr_t *)&softsp->temp_reg, 0, 0)) {
36029949e86Sstevel 		cmn_err(CE_WARN, "environ%d: unable to map temperature "
36119397407SSherry Moore 		    "register", ddi_get_instance(softsp->dip));
36229949e86Sstevel 		return (DDI_FAILURE);
36329949e86Sstevel 	}
36429949e86Sstevel 
36529949e86Sstevel 	/* Initialize the temperature */
36629949e86Sstevel 	init_temp_arrays(&softsp->tempstat);
36729949e86Sstevel 
36829949e86Sstevel 	/*
36929949e86Sstevel 	 * Do a priming read on the ADC, and throw away the first value
37029949e86Sstevel 	 * read. This is a feature of the ADC hardware. After a power cycle
37129949e86Sstevel 	 * it does not contains valid data until a read occurs.
37229949e86Sstevel 	 */
37329949e86Sstevel 	tmp = *(softsp->temp_reg);
37429949e86Sstevel 
37529949e86Sstevel 	/* Wait 30 usec for ADC hardware to stabilize. */
37629949e86Sstevel 	DELAY(30);
37729949e86Sstevel 
37829949e86Sstevel #ifdef lint
37929949e86Sstevel 	tmp = tmp;
38029949e86Sstevel #endif
38129949e86Sstevel 
38229949e86Sstevel 	/*
38329949e86Sstevel 	 * Now add this soft state structure to the front of the linked list
38429949e86Sstevel 	 * of soft state structures.
38529949e86Sstevel 	 */
38629949e86Sstevel 	mutex_enter(&overtemp_mutex);
38729949e86Sstevel 	softsp->next = tempsp_list;
38829949e86Sstevel 	tempsp_list = softsp;
38929949e86Sstevel 	mutex_exit(&overtemp_mutex);
39029949e86Sstevel 
39129949e86Sstevel 	/* Create kstats for this instance of the environ driver */
39229949e86Sstevel 	environ_add_temp_kstats(softsp);
39329949e86Sstevel 
39429949e86Sstevel 	return (DDI_SUCCESS);
39529949e86Sstevel }
39629949e86Sstevel 
39729949e86Sstevel /* ARGSUSED */
39829949e86Sstevel static void
overtemp_wakeup(void * arg)39929949e86Sstevel overtemp_wakeup(void *arg)
40029949e86Sstevel {
40129949e86Sstevel 	/*
40229949e86Sstevel 	 * grab mutex to guarantee that our wakeup call
40329949e86Sstevel 	 * arrives after we go to sleep -- so we can't sleep forever.
40429949e86Sstevel 	 */
40529949e86Sstevel 	mutex_enter(&overtemp_mutex);
40629949e86Sstevel 	cv_signal(&overtemp_cv);
40729949e86Sstevel 	mutex_exit(&overtemp_mutex);
40829949e86Sstevel }
40929949e86Sstevel 
41029949e86Sstevel /*
41129949e86Sstevel  * This function polls all the system board digital temperature registers
41229949e86Sstevel  * and stores them in the history buffers using the fhc driver support
41329949e86Sstevel  * routines.
41429949e86Sstevel  * The temperature detected must then be checked against our current
41529949e86Sstevel  * policy for what to do in the case of overtemperature situations. We
41629949e86Sstevel  * must also allow for manufacturing's use of a heat chamber.
41729949e86Sstevel  */
41829949e86Sstevel static void
environ_overtemp_poll(void)41929949e86Sstevel environ_overtemp_poll(void)
42029949e86Sstevel {
42129949e86Sstevel 	struct environ_soft_state *list;
42229949e86Sstevel 	callb_cpr_t cprinfo;
42329949e86Sstevel 
42429949e86Sstevel 	CALLB_CPR_INIT(&cprinfo, &overtemp_mutex, callb_generic_cpr, "environ");
42529949e86Sstevel 
42629949e86Sstevel 	/* The overtemp data strcutures are protected by a mutex. */
42729949e86Sstevel 	mutex_enter(&overtemp_mutex);
42829949e86Sstevel 
42929949e86Sstevel 	while (environ_do_overtemp_thread) {
43029949e86Sstevel 
43129949e86Sstevel 		/*
43229949e86Sstevel 		 * for each environment node that has been attached,
43329949e86Sstevel 		 * read it and check for overtemp.
43429949e86Sstevel 		 */
43529949e86Sstevel 		for (list = tempsp_list; list != NULL; list = list->next) {
43629949e86Sstevel 			if (list->temp_reg == NULL) {
43729949e86Sstevel 				continue;
43829949e86Sstevel 			}
43929949e86Sstevel 
44029949e86Sstevel 			update_temp(list->pdip, &list->tempstat,
44119397407SSherry Moore 			    *(list->temp_reg));
44229949e86Sstevel 		}
44329949e86Sstevel 
44429949e86Sstevel 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
44529949e86Sstevel 
44629949e86Sstevel 		/* now have this thread sleep for a while */
44729949e86Sstevel 		(void) timeout(overtemp_wakeup, NULL, overtemp_timeout_sec*hz);
44829949e86Sstevel 
44929949e86Sstevel 		cv_wait(&overtemp_cv, &overtemp_mutex);
45029949e86Sstevel 
45129949e86Sstevel 		CALLB_CPR_SAFE_END(&cprinfo, &overtemp_mutex);
45229949e86Sstevel 	}
45329949e86Sstevel 	CALLB_CPR_EXIT(&cprinfo);
45429949e86Sstevel 	thread_exit();
45529949e86Sstevel 	/* NOTREACHED */
45629949e86Sstevel }
45729949e86Sstevel 
45829949e86Sstevel void
environ_add_temp_kstats(struct environ_soft_state * softsp)45929949e86Sstevel environ_add_temp_kstats(struct environ_soft_state *softsp)
46029949e86Sstevel {
46129949e86Sstevel 	struct  kstat   *tksp;
46229949e86Sstevel 	struct  kstat   *ttsp;	/* environ temperature test kstat */
46329949e86Sstevel 
46429949e86Sstevel 	/*
46529949e86Sstevel 	 * Create the overtemp kstat required for the environment driver.
46629949e86Sstevel 	 * The kstat instances are tagged with the physical board number
46729949e86Sstevel 	 * instead of ddi instance number.
46829949e86Sstevel 	 */
46929949e86Sstevel 	if ((tksp = kstat_create("unix", softsp->board,
47029949e86Sstevel 	    OVERTEMP_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
47129949e86Sstevel 	    sizeof (struct temp_stats), KSTAT_FLAG_PERSISTENT)) == NULL) {
47229949e86Sstevel 		cmn_err(CE_WARN, "environ%d: temp kstat_create failed",
47329949e86Sstevel 			ddi_get_instance(softsp->dip));
47429949e86Sstevel 	} else {
47529949e86Sstevel 		tksp->ks_update = overtemp_kstat_update;
47629949e86Sstevel 		tksp->ks_private = (void *) &softsp->tempstat;
47729949e86Sstevel 		softsp->environ_ksp = tksp;
47829949e86Sstevel 		kstat_install(tksp);
47929949e86Sstevel 	}
48029949e86Sstevel 
48129949e86Sstevel 	/*
48229949e86Sstevel 	 * Create the temperature override kstat, for testability.
48329949e86Sstevel 	 * The kstat instances are tagged with the physical board number
48429949e86Sstevel 	 * instead of ddi instance number.
48529949e86Sstevel 	 */
48629949e86Sstevel 	if ((ttsp = kstat_create("unix", softsp->board,
48729949e86Sstevel 	    TEMP_OVERRIDE_KSTAT_NAME, "misc", KSTAT_TYPE_RAW, sizeof (short),
48819397407SSherry Moore 	    KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
48929949e86Sstevel 		cmn_err(CE_WARN, "environ%d: temp override kstat_create failed",
49019397407SSherry Moore 		    ddi_get_instance(softsp->dip));
49129949e86Sstevel 	} else {
49229949e86Sstevel 		ttsp->ks_update = temp_override_kstat_update;
49329949e86Sstevel 		ttsp->ks_private = (void *) &softsp->tempstat.override;
49429949e86Sstevel 		softsp->environ_oksp = ttsp;
49529949e86Sstevel 		kstat_install(ttsp);
49629949e86Sstevel 	}
49729949e86Sstevel }
498