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 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 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 17229949e86Sstevel _info(struct modinfo *modinfop) 17329949e86Sstevel { 17429949e86Sstevel return (mod_info(&modlinkage, modinfop)); 17529949e86Sstevel } 17629949e86Sstevel 17729949e86Sstevel static int 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 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 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 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 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 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