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 = {
13229949e86Sstevel &mod_driverops, /* module type, this one is a driver */
13319397407SSherry Moore "Environment Leaf", /* name of module */
13429949e86Sstevel &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",
21629949e86Sstevel 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,
23229949e86Sstevel "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 "
36129949e86Sstevel "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,
44129949e86Sstevel *(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),
48829949e86Sstevel KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
48929949e86Sstevel cmn_err(CE_WARN, "environ%d: temp override kstat_create failed",
49029949e86Sstevel 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