Example #1
0
/*
 * 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);
}
Example #2
0
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);
}
Example #3
0
/*
 * 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 {
Example #4
0
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));
}
Example #5
0
/*
 * 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);
}
Example #6
0
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();
}
Example #7
0
/*
 * 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);
}
Example #8
0
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);
}
Example #9
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);
}
Example #10
0
/*
 * 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, &section, 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(&section.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(&section.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);
}
Example #11
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);
}
Example #12
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);
}
Example #13
0
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);
}
Example #14
0
/*
 * 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);
}
Example #15
0
/*
 * 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;
	}
}
Example #16
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);
}
Example #17
0
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);
}