/* * Get current temperature * Returns -1 on error, 0 if successful */ int get_temperature(env_sensor_t *sensorp, tempr_t *temp) { int fd = sensorp->fd; int retval = 0; if (fd == -1) retval = -1; else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { retval = -1; if (sensorp->error == 0) { sensorp->error = 1; envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, sensorp->name, errno, strerror(errno)); } } else if (sensorp->error != 0) { sensorp->error = 0; envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name); } if (sensorp->crtbl != NULL) { *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp); } return (retval); }
void env_picl_setup(void) { int err; sensor_node_t *snodep; fan_node_t *fnodep; picl_nodehdl_t plath; char fullfilename[PATH_MAX]; picl_nodehdl_t rooth; /* * Initialize sensorp and other fields in the sensor_nodes[] array */ for (snodep = sensor_nodes; snodep->sensor_name != NULL; snodep++) { snodep->sensorp = sensor_lookup(snodep->sensor_name); snodep->nodeh = NULL; snodep->proph = NULL; snodep->sdev_proph = NULL; } /* * Initialize fanp and other fields in the fan_nodes[] array */ for (fnodep = fan_nodes; fnodep->fan_name != NULL; fnodep++) { fnodep->fanp = fan_lookup(fnodep->fan_name); fnodep->nodeh = NULL; fnodep->proph = NULL; } /* * Get platform handle and populate PICL tree with environmental * nodes and properties */ err = ptree_get_node_by_path("/platform", &plath); if (err == PICL_SUCCESS) { err = add_sensor_nodes_and_props(plath); if (err == PICL_SUCCESS) err = add_fan_nodes_and_props(plath); } if (err != PICL_SUCCESS) { envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED); return; } /* * Parse the envmodel.conf file and populate the PICL tree */ if (get_envmodel_conf_file(fullfilename) < 0) envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED); if (ptree_get_root(&rooth) != PICL_SUCCESS) envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED); err = picld_pluginutil_parse_config_file(rooth, fullfilename); if (err != PICL_SUCCESS) envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED); }
/* * Open fan devices and initialize per fan data structure. * Returns #fans found. */ static int envd_setup_fans(void) { int i, fd; env_fan_t *fanp; char path[PATH_MAX]; int fancnt = 0; uint8_t n = 0; for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { (void) strcpy(path, "/devices"); (void) strlcat(path, fanp->devfs_path, sizeof (path)); fd = open(path, O_RDWR); if (fd == -1) { envd_log(LOG_CRIT, ENV_FAN_OPEN_FAIL, fanp->name, fanp->devfs_path, errno, strerror(errno)); fanp->present = B_FALSE; continue; } fanp->fd = fd; if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) { fanp->speedrange = adm_speedrange_map[(n >> 6) & 0x03]; } else {
static int envd_es_setup() { envfru = get_fru_envsegs(); if (envfru == NULL) { envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); return (-1); } return (process_fru_seeprom((uchar_t *)envfru->envsegbufp)); }
/* * Open temperature sensor devices and initialize per sensor data structure. * Returns #sensors found. */ static int envd_setup_sensors(void) { int i; tempr_t temp; env_sensor_t *sensorp; char path[FILENAME_MAX]; int sensorcnt = 0; sensor_thresh_t *threshp; for (i = 0; (sensorp = envd_sensors[i]) != NULL; i++) { sensorp->fd = -1; sensorp->shutdown_initiated = B_FALSE; sensorp->warning_tstamp = 0; sensorp->shutdown_tstamp = 0; threshp = sensorp->temp_thresh; sensorp->cur_temp = threshp->target_temp; sensorp->error = 0; (void) strcpy(path, "/devices"); (void) strlcat(path, sensorp->devfs_path, sizeof (path)); sensorp->fd = open(path, O_RDWR); if (sensorp->fd == -1) { envd_log(LOG_WARNING, ENV_SENSOR_OPEN_FAIL, sensorp->name, sensorp->devfs_path, errno, strerror(errno)); sensorp->present = B_FALSE; continue; } sensorp->present = B_TRUE; sensorcnt++; if (monitor_temperature) { /* * Set low_power_off and high_power_off limits */ (void) ioctl(sensorp->fd, MAX1617_SET_LOW_LIMIT, &threshp->low_power_off); (void) ioctl(sensorp->fd, MAX1617_SET_HIGH_LIMIT, &threshp->high_power_off); } /* * Set cur_temp field to the current temperature value */ if (get_temperature(sensorp, &temp) == 0) { sensorp->cur_temp = temp; } } return (sensorcnt); }
static void piclenvd_init(void) { /* * Start environmental daemon/threads */ if (envd_setup() != 0) { envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); return; } /* * Now setup/populate PICL tree */ env_picl_setup(); }
/* * Open fan devices and initialize per fan data structure. * Returns #fans found. */ static int envd_setup_fans(void) { int i, fd; fanspeed_t speed; env_fan_t *fanp; char path[FILENAME_MAX]; int fancnt = 0; for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { fanp->fd = -1; fanp->cur_speed = 0; fanp->prev_speed = 0; (void) strcpy(path, "/devices"); (void) strlcat(path, fanp->devfs_path, sizeof (path)); fd = open(path, O_RDWR); if (fd == -1) { envd_log(LOG_WARNING, ENV_FAN_OPEN_FAIL, fanp->name, fanp->devfs_path, errno, strerror(errno)); fanp->present = B_FALSE; continue; } fanp->fd = fd; fanp->present = B_TRUE; fancnt++; /* * Set cur_speed/prev_speed to current fan speed */ if (get_fan_speed(fanp, &speed) == -1) { /* * The Fan driver does not know the current fan speed. * Initialize it to 50% of the max speed and reread * to get the current speed. */ speed = fanp->speed_max/2; (void) set_fan_speed(fanp, speed); if (get_fan_speed(fanp, &speed) == -1) continue; } fanp->cur_speed = speed; fanp->prev_speed = speed; } return (fancnt); }
static int process_fru_seeprom(unsigned char *buff) { id_off_t id; int i; int id_offset = 0; int nsensors; int nfans; env_fan_t *fnodep; env_sensor_t *snodep; #define NSENSOR_OFFSET 1 #define ID_OFF_SIZE 6 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2) nsensors = (int)buff[NSENSOR_OFFSET]; if (nsensors != MAX_SENSORS) { envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); return (-1); } nfans = (int)buff[NFANS_OFFSET(nsensors)]; if (nfans != MAX_FANS) { envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); return (-1); } while (nsensors > 0) { (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], ID_OFF_SIZE); if (env_debug) envd_log(LOG_ERR, "\n Sensor Id %x offset %x", id.id, id.offset); if (id.id > MAX_SENSOR_ID) { envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); return (-1); } /* * Copy into the sensor control block array according to the * sensor ID */ (void) memcpy((char *)&sensor_ctrl[id.id], (char *)&buff[id.offset], sizeof (sensor_ctrl_blk_t)); nsensors--; id_offset += ID_OFF_SIZE; } /* * Skip past no of Fan entry(single byte) */ id_offset++; while (nfans > 0) { (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], ID_OFF_SIZE); if (env_debug) envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id, id.offset); (void) memcpy((char *)&fan_ctrl[id.id], (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t)); nfans--; id_offset += ID_OFF_SIZE; } /* * Match Sensor/ES ID and point correct data * based on IDs */ for (snodep = envd_sensors; snodep->name != NULL; snodep++) snodep->es_ptr = &sensor_ctrl[snodep->id]; /* * Match Fan/ES ID and point to correct ES Data * based on IDs */ for (i = 0; (fnodep = envd_fans[i]) != NULL; i++) fnodep->es_ptr = &fan_ctrl[fnodep->id]; return (0); }
/* * Get all environmental segments */ static fruenvseg_t * get_fru_envsegs(void) { fruenvseg_t *fruenvsegs; envseg_layout_t *envsegp; void *envsegbufp; int fd, envseglen, hdrlen; char path[PATH_MAX]; fruenvsegs = NULL; fruenvsegs = malloc(sizeof (*fruenvsegs)); if (fruenvsegs == NULL) { return (NULL); } /* * Now get the environmental segment from this FRU */ (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV); fd = open(path, O_RDONLY); if (fd == -1) { envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path); free(fruenvsegs); return (NULL); } /* * Read environmental segment from this FRU SEEPROM */ if (get_envseg(fd, &envsegbufp, &envseglen) != 0) { envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path); free(fruenvsegs); (void) close(fd); return (NULL); } /* * Validate envseg version number and header length */ envsegp = (envseg_layout_t *)envsegbufp; hdrlen = sizeof (envseg_layout_t) - sizeof (envseg_sensor_t) + (envsegp->sensor_count) * sizeof (envseg_sensor_t); if (envsegp->version != ENVSEG_VERSION || envseglen < hdrlen) { /* * version mismatch or header not big enough */ envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, path); if (envsegbufp != NULL) (void) free(envsegbufp); free(fruenvsegs); (void) close(fd); return (NULL); } fruenvsegs->envseglen = envseglen; fruenvsegs->envsegbufp = envsegbufp; (void) close(fd); return (fruenvsegs); }
/* * Get environmental segment from the specified FRU SEEPROM */ static int get_envseg(int fd, void **envsegp, int *envseglenp) { int i, segcnt, envseglen; section_layout_t section; segment_layout_t segment; uint8_t *envseg; if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L || read(fd, §ion, sizeof (section)) != sizeof (section)) { return (EINVAL); } /* * Verify we have the correct section and contents are valid * For now, we don't verify the CRC. */ if (section.header_tag != SECTION_HDR_TAG || GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) { if (env_debug) envd_log(LOG_INFO, "Invalid section header tag:%x version:%x\n", section.header_tag, GET_UNALIGN16(§ion.header_version)); return (EINVAL); } /* * Locate our environmental segment */ segcnt = section.segment_count; for (i = 0; i < segcnt; i++) { if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) { return (EINVAL); } if (env_debug) envd_log(LOG_INFO, "Seg name: %x desc:%x off:%x len:%x\n", GET_UNALIGN16(&segment.name), GET_UNALIGN32(&segment.descriptor[0]), GET_UNALIGN16(&segment.offset), GET_UNALIGN16(&segment.length)); if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME) break; } if (i >= segcnt) { return (ENOENT); } /* * Allocate memory to hold the environmental segment data. */ envseglen = GET_UNALIGN16(&segment.length); if ((envseg = malloc(envseglen)) == NULL) { return (ENOMEM); } if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L || read(fd, envseg, envseglen) != envseglen) { (void) free(envseg); return (EIO); } *envsegp = envseg; *envseglenp = envseglen; return (0); }
static int envd_setup(void) { if (envd_inited == B_FALSE) { /* * Initialize global state */ system_shutdown_started = B_FALSE; envthr_created = B_FALSE; pmthr_created = B_FALSE; if (pthread_attr_init(&thr_attr) != 0 || pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) return (-1); if (pthread_mutex_init(&lpstate_lock, NULL) != 0 || pthread_cond_init(&lpstate_cond, NULL) != 0) return (-1); /* * Process tuneable parameters */ process_env_conf_file(); /* * Setup temperature sensors and fail if we can't open * at least one sensor. */ if (envd_setup_sensors() <= 0) return (-1); /* * Setup fan device (don't fail even if we can't access * the fan as we can still monitor temeperature. */ (void) envd_setup_fans(); /* * Create a thread to monitor temperature and control fan * speed. */ if (envthr_created == B_FALSE && pthread_create(&envthr_tid, &thr_attr, envthr, (void *)NULL) != 0) { envd_close_fans(); envd_close_sensors(); envd_log(LOG_CRIT, ENV_THREAD_CREATE_FAILED); return (-1); } envthr_created = B_TRUE; } envd_inited = B_TRUE; /* * Create a thread to monitor PM state */ if (pmthr_created == B_FALSE) { pm_fd = open(PM_DEVICE, O_RDONLY); if (pm_fd == -1 || pthread_create(&pmthr_tid, &thr_attr, pmthr, (void *)NULL) != 0) { envd_close_pm(); envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); } else pmthr_created = B_TRUE; } return (0); }
/* * Process configuration file */ static void process_env_conf_file(void) { int line, len, val, toklen; char buf[BUFSIZ]; FILE *fp; env_tuneable_t *tunep; char nmbuf[SYS_NMLN]; char fname[PATH_MAX]; char *tok, *valuep, *strend; char tokdel[] = " \t\n\r"; int skip_line = 0; if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) == -1) return; (void) snprintf(fname, sizeof (fname), PICLD_PLAT_PLUGIN_DIRF, nmbuf); (void) strlcat(fname, ENV_CONF_FILE, sizeof (fname)); fp = fopen(fname, "r"); if (fp == NULL) return; /* * Blank lines or lines starting with "#" or "*" in the first * column are ignored. All other lines are assumed to contain * input in the following format: * * keyword value * * where the "value" can be a signed integer or string (in * double quotes) depending upon the keyword. */ for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) { len = strlen(buf); if (len <= 0) continue; /* skip long lines */ if (buf[len-1] != '\n') { skip_line = 1; continue; } else if (skip_line) { skip_line = 0; continue; } else buf[len-1] = '\0'; /* skip comments */ if (buf[0] == '*' || buf[0] == '#') continue; /* * Skip over white space to get the keyword */ tok = buf + strspn(buf, tokdel); if (*tok == '\0') continue; /* blank line */ toklen = strcspn(tok, tokdel); tok[toklen] = '\0'; /* Get possible location for value (within current line) */ valuep = tok + toklen + 1; if (valuep > buf+len) valuep = buf + len; /* * Lookup the keyword and process value accordingly */ for (tunep = &env_tuneables[0]; tunep->name != NULL; tunep++) { if (strcmp(tunep->name, tok) != 0) continue; switch (tunep->type) { case KTYPE_INT: errno = 0; val = strtol(valuep, &valuep, 0); /* Check for invalid value or extra tokens */ if (errno != 0 || strtok(valuep, tokdel)) { envd_log(LOG_INFO, ENV_CONF_INT_EXPECTED, fname, line, tok); break; } /* Update only if value within range */ if (tunep->size == sizeof (int8_t) && val == (int8_t)val) *(int8_t *)tunep->addr = (int8_t)val; else if (tunep->size == sizeof (short) && val == (short)val) *(short *)tunep->addr = (short)val; else if (tunep->size == sizeof (int)) *(int *)tunep->addr = (int)val; else { envd_log(LOG_INFO, ENV_CONF_INT_EXPECTED, fname, line, tok); break; } if (env_debug) envd_log(LOG_INFO, "SUNW_piclenvd: " "file:%s line:%d %s = %d\n", fname, line, tok, val); break; case KTYPE_STRING: /* * String value must be within double quotes. * Skip over initial white spaces before * looking for value. */ valuep += strspn(valuep, tokdel); strend = parse_string_val(valuep); if (strend == NULL || *valuep != '"' || strtok(strend+1, tokdel) != NULL || (strend-valuep) > tunep->size) { envd_log(LOG_INFO, ENV_CONF_STRING_EXPECTED, fname, line, tok, tunep->size); break; } *strend = '\0'; if (env_debug) envd_log(LOG_INFO, "piclenvd: file:%s" " line:%d %s = \"%s\"\n", fname, line, tok, valuep+1); (void) strcpy(tunep->addr, (caddr_t)valuep+1); break; default: envd_log(LOG_INFO, ENV_CONF_UNSUPPORTED_TYPE, fname, line, tunep->type, tunep->name); } break; } if (tunep->name == NULL) envd_log(LOG_INFO, ENV_CONF_UNSUPPORTED_KEYWORD, fname, line, tok); } (void) fclose(fp); }
static int add_fan_nodes_and_props(picl_nodehdl_t plath) { int err; char *pname, *nodename, *devfs_path; env_fan_t *fanp; fan_node_t *fnodep; picl_nodehdl_t nodeh, cnodeh; picl_prophdl_t proph; node_list_t *node_list, *listp; node_list = get_node_list_by_class(plath, PICL_CLASS_FAN_CONTROL, NULL); if (node_list == NULL) return (PICL_FAILURE); for (listp = node_list; listp != NULL; listp = listp->next) { /* * Add various fan nodes and properties */ nodeh = listp->nodeh; err = PICL_SUCCESS; for (fnodep = fan_nodes; fnodep->fan_name != NULL; fnodep++) { /* Skip if already initialized or no fan info */ if (fnodep->nodeh != NULL || fnodep->fanp == NULL) continue; /* * Create "fan" class node and save node handle */ nodename = fnodep->fan_name; err = ptree_create_and_add_node(nodeh, nodename, PICL_CLASS_FAN, &cnodeh); if (env_debug) envd_log(LOG_INFO, "Creating PICL fan node '%s' err:%d\n", nodename, err); if (err != PICL_SUCCESS) break; fnodep->nodeh = cnodeh; /* * Add "devfs_path" property in child node */ fanp = fnodep->fanp; devfs_path = fanp->devfs_path; pname = PICL_PROP_DEVFS_PATH; err = add_regular_prop(cnodeh, pname, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(devfs_path)+1, (void *)devfs_path, &proph); if (err != PICL_SUCCESS) break; /* * Add "Speed" volatile property in this "fan" * class node and save prop handle. */ pname = PROP_FAN_SPEED; err = add_volatile_prop(cnodeh, pname, PICL_PTYPE_INT, PICL_READ, sizeof (fanspeed_t), get_current_speed, NULL, &proph); if (err != PICL_SUCCESS) break; fnodep->proph = proph; /* * Add other "fan" class properties */ pname = PROP_FAN_SPEED_UNIT, err = add_regular_prop(cnodeh, pname, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(fnodep->speed_unit)+1, (void *)fnodep->speed_unit, &proph); if (err != PICL_SUCCESS) break; } if (err != PICL_SUCCESS) { delete_fan_nodes_and_props(); free_node_list(node_list); if (env_debug) envd_log(LOG_WARNING, "Can't create prop/node for fan '%s'\n", nodename); return (err); } } free_node_list(node_list); return (PICL_SUCCESS); }
/* * This is the environment thread, which monitors the current temperature * and power managed state and controls system fan speed. Temperature is * polled every sensor-poll_interval seconds duration. */ static void * envthr(void *args) { int err; fanspeed_t fan_speed; struct timeval ct; struct timespec to; env_fan_t *pmfanp = &envd_system_fan; tempr_t cpu_amb_temp, cpu_die_temp; tempr_t cpu_amb_warning, cpu_die_warning; (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); cpu_amb_warning = cpu_amb_sensor.temp_thresh->high_warning; cpu_die_warning = cpu_die_sensor.temp_thresh->high_warning; for (;;) { (void) gettimeofday(&ct, NULL); /* * Monitor current temperature for all sensors * (current temperature is recorded in the "cur_temp" * field within each sensor data structure) */ monitor_sensors(); cpu_amb_temp = cpu_amb_sensor.cur_temp; cpu_die_temp = cpu_die_sensor.cur_temp; /* * Process any PM state change events while waiting until * time to poll sensors again (i.e. sensor_poll_interval * seconds from the last time). */ to.tv_sec = ct.tv_sec + sensor_poll_interval; to.tv_nsec = 0; for (;;) { /* * Turn off system fan if in lowest power state * and both CPU die and ambient temperatures are * below corresponding high warning temperatures. */ fan_speed = pmfanp->speed_max; if (cur_lpstate && cpu_amb_temp < cpu_amb_warning && cpu_die_temp < cpu_die_warning) fan_speed = pmfanp->speed_min; if (env_debug) envd_log(LOG_INFO, "fan: %-16s speed cur:%3d new:%3d " "low-power:%d\n", pmfanp->name, (uint_t)pmfanp->cur_speed, (uint_t)fan_speed, cur_lpstate); if (fan_speed != pmfanp->cur_speed && set_fan_speed(pmfanp, fan_speed) == 0) pmfanp->cur_speed = fan_speed; /* wait for power state change or time to poll */ pthread_mutex_lock(&lpstate_lock); err = pthread_cond_timedwait(&lpstate_cond, &lpstate_lock, &to); pthread_mutex_unlock(&lpstate_lock); if (err == ETIMEDOUT) break; } } /*NOTREACHED*/ return (NULL); }
/* * Read all temperature sensors and take appropriate action based * upon temperature threshols associated with each sensor. Possible * actions are: * * temperature > high_shutdown * temperature < low_shutdown * Gracefully shutdown the system and log/print a message * on the system console provided the temperature has been * in shutdown range for "shutdown_interval" seconds. * * high_warning < temperature <= high_shutdown * low_warning > temperature >= low_shutdown * Log/print a warning message on the system console at most * once every "warning_interval" seconds. * * Note that the current temperature is recorded in the "cur_temp" field * within each env_sensor_t structure. */ static void monitor_sensors(void) { tempr_t temp; int i; env_sensor_t *sensorp; sensor_thresh_t *threshp; struct timeval ct; char msgbuf[BUFSIZ]; char syscmd[BUFSIZ]; for (i = 0; (sensorp = envd_sensors[i]) != NULL; i++) { if (get_temperature(sensorp, &temp) < 0) continue; sensorp->cur_temp = temp; if (env_debug) envd_log(LOG_INFO, "sensor: %-13s temp cur:%3d target:%3d\n", sensorp->name, temp, sensorp->temp_thresh->target_temp); if (!monitor_temperature) continue; /* * If this sensor already triggered system shutdown, don't * log any more shutdown/warning messages for it. */ if (sensorp->shutdown_initiated) continue; /* * Check for the temperature in warning and shutdown range * and take appropriate action. */ threshp = sensorp->temp_thresh; if (TEMP_IN_WARNING_RANGE(temp, threshp)) { /* * Log warning message at most once every * warning_interval seconds. */ (void) gettimeofday(&ct, NULL); if ((ct.tv_sec - sensorp->warning_tstamp) >= warning_interval) { envd_log(LOG_WARNING, ENV_WARNING_MSG, sensorp->name, temp, threshp->low_warning, threshp->high_warning); sensorp->warning_tstamp = ct.tv_sec; } } if (TEMP_IN_SHUTDOWN_RANGE(temp, threshp)) { (void) gettimeofday(&ct, NULL); if (sensorp->shutdown_tstamp == 0) sensorp->shutdown_tstamp = ct.tv_sec; /* * Shutdown the system if the temperature remains * in the shutdown range for over shutdown_interval * seconds. */ if ((ct.tv_sec - sensorp->shutdown_tstamp) >= shutdown_interval) { /* log error */ sensorp->shutdown_initiated = B_TRUE; (void) snprintf(msgbuf, sizeof (msgbuf), ENV_SHUTDOWN_MSG, sensorp->name, temp, threshp->low_shutdown, threshp->high_shutdown); envd_log(LOG_CRIT, msgbuf); /* shutdown the system (only once) */ if (system_shutdown_started == B_FALSE) { (void) snprintf(syscmd, sizeof (syscmd), "%s \"%s\"", shutdown_cmd, msgbuf); envd_log(LOG_CRIT, syscmd); system_shutdown_started = B_TRUE; (void) system(syscmd); } } } else if (sensorp->shutdown_tstamp != 0) sensorp->shutdown_tstamp = 0; } }
/* * This is the power management thread, which monitors all power state * change events and wakes up the "envthr" thread when the system enters * or exits the lowest power state. */ static void * pmthr(void *args) { pm_state_change_t pmstate; char physpath[PATH_MAX]; int prev_lpstate; (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pmstate.physpath = physpath; pmstate.size = sizeof (physpath); cur_lpstate = 0; prev_lpstate = 0; for (;;) { /* * Get PM state change events to check if the system * is in lowest power state and wake up the "envthr" * thread when the power state changes. * * To minimize polling, we use the blocking interface * to get the power state change event here. */ if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) { if (errno != EINTR) break; continue; } /* * Extract the lowest power state from the last queued * state change events. We pick up queued state change * events using the non-blocking interface and wake up * the "envthr" thread only after consuming all the * state change events queued at that time. */ do { if (env_debug > 1) { envd_log(LOG_INFO, "pmstate event:0x%x flags:%x comp:%d " "oldval:%d newval:%d path:%s\n", pmstate.event, pmstate.flags, pmstate.component, pmstate.old_level, pmstate.new_level, pmstate.physpath); } cur_lpstate = (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0; } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0); if (cur_lpstate != prev_lpstate) { prev_lpstate = cur_lpstate; pthread_mutex_lock(&lpstate_lock); pthread_cond_signal(&lpstate_cond); pthread_mutex_unlock(&lpstate_lock); } } /* * We won't be able to monitor lowest power state any longer, * hence reset it and wakeup the "envthr". */ if (cur_lpstate != 0) { prev_lpstate = cur_lpstate; cur_lpstate = 0; pthread_mutex_lock(&lpstate_lock); pthread_cond_signal(&lpstate_cond); pthread_mutex_unlock(&lpstate_lock); } envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno)); return (NULL); }
static int add_sensor_nodes_and_props(picl_nodehdl_t plath) { int err; char *pname, *nodename, *refnode, *devfs_path; node_list_t *node_list, *listp; sensor_node_t *snodep; sensor_thresh_t *threshp; picl_nodehdl_t nodeh, refnodeh, cnodeh; picl_prophdl_t proph; char unitaddr[UNITADDR_LEN_MAX]; env_sensor_t *sensorp; node_list = get_node_list_by_class(plath, PICL_CLASS_TEMP_DEVICE, NULL); if (node_list == NULL) return (PICL_FAILURE); for (listp = node_list; listp != NULL; listp = listp->next) { /* * Get "reg" property. Skip if no "reg" property found. */ nodeh = listp->nodeh; err = get_unit_address_prop(nodeh, (void *)unitaddr, sizeof (unitaddr)); if (err != PICL_SUCCESS) continue; for (snodep = sensor_nodes; snodep->sensor_name != NULL; snodep++) { /* Match "UnitAddress" property */ if (strcasecmp(unitaddr, snodep->unitaddr) != 0) continue; /* * Skip if already initialized or no sensor info */ sensorp = snodep->sensorp; if (snodep->nodeh != NULL || sensorp == NULL) continue; /* * Create temperature-sensor node */ nodename = snodep->sensor_name; err = ptree_create_and_add_node(nodeh, nodename, PICL_CLASS_TEMP_SENSOR, &cnodeh); if (env_debug) envd_log(LOG_INFO, "Creating PICL sensor node '%s' err:%d\n", nodename, err); if (err != PICL_SUCCESS) break; /* save node handle */ snodep->nodeh = cnodeh; /* * Add "devfs_path" property in child node */ devfs_path = sensorp->devfs_path; pname = PICL_PROP_DEVFS_PATH; err = add_regular_prop(cnodeh, pname, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(devfs_path)+1, (void *)devfs_path, &proph); if (err != PICL_SUCCESS) break; /* * Now add volatile "temperature" volatile property * in this "temperature-sensor" class node. */ pname = PROP_TEMPERATURE; err = add_volatile_prop(cnodeh, pname, PICL_PTYPE_INT, PICL_READ, sizeof (tempr_t), get_current_temp, NULL, &proph); if (err != PICL_SUCCESS) break; /* Save prop handle */ snodep->proph = proph; /* * Add threshold related properties */ threshp = sensorp->temp_thresh; if (threshp != NULL) add_sensor_thresh_props(cnodeh, threshp); /* * Finally create property in the sensed device * (if one specified) */ refnode = snodep->sdev_node; pname = snodep->sdev_pname; if (refnode == NULL || pname == NULL) continue; err = ptree_get_node_by_path(refnode, &refnodeh); if (err == PICL_SUCCESS) { err = add_volatile_prop(refnodeh, pname, PICL_PTYPE_INT, PICL_READ, sizeof (tempr_t), get_current_temp, NULL, &proph); } if (err != PICL_SUCCESS) break; /* Save prop handle */ snodep->sdev_proph = proph; } if (err != PICL_SUCCESS) { delete_sensor_nodes_and_props(); free_node_list(node_list); if (env_debug) envd_log(LOG_INFO, "Can't create prop/node for sensor '%s'\n", nodename); return (err); } } free_node_list(node_list); return (PICL_SUCCESS); }