Example #1
0
scfga_ret_t
make_dyncomp(
	di_node_t node,
	const char *physpath,
	char **dyncompp,
	int *l_errnop)
{
	char *devlink = NULL;
	scfga_ret_t ret;
	di_minor_t minor;
	char *path;
	char pathbuf[MAXPATHLEN];
	int match_minor;

	if (*dyncompp != NULL) {
		return (SCFGA_LIB_ERR);
	}

	/* tag on minor name */
	minor = di_minor_next(node, DI_MINOR_NIL);
	if (minor == DI_MINOR_NIL) {
		match_minor = 0;
		path = (char *)physpath;
	} else {
		match_minor = 1;
		(void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
		    di_minor_name(minor));
		path = pathbuf;
	}

	/* Get the corresponding devlink from the physical path */
	ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor);
	if (ret == SCFGA_OK) {
		assert(devlink != NULL);

		/* Create dynamic component. */
		ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop);
		S_FREE(devlink);
		if (ret == SCFGA_OK) {
			assert(*dyncompp != NULL);
			return (SCFGA_OK);
		}

		/*
		 * Failed to get devlink based dynamic component.
		 * Try driver and instance
		 */
	}

	ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop);
	assert(ret != SCFGA_OK || *dyncompp != NULL);

	return (ret);
}
Example #2
0
static scfga_ret_t
get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop)
{
	size_t len;
	scfga_ret_t ret;
	int match_minor = 1;

	ret = physpath_to_devlink((char *)hba_phys, hba_logpp,
	    l_errnop, match_minor);
	if (ret != SCFGA_OK) {
		return (ret);
	}

	assert(*hba_logpp != NULL);

	/* Remove the "/dev/cfg/"  prefix */
	len = strlen(CFGA_DEV_DIR SLASH);

	(void) memmove(*hba_logpp, *hba_logpp + len,
	    strlen(*hba_logpp + len) + 1);

	return (SCFGA_OK);
}
Example #3
0
/*ARGSUSED*/
cfga_err_t
cfga_list_ext(
	const char *ap_id,
	cfga_list_data_t **ap_id_list,
	int *nlistp,
	const char *options,
	const char *listopts,
	char **errstring,
	cfga_flags_t flags)
{
	int			l_errno;
	char			*ap_id_log = NULL;
	size_t			size;
	nvlist_t		*user_nvlist = NULL;
	devctl_hdl_t		devctl_hdl = NULL;
	cfga_sata_ret_t		rv = CFGA_SATA_OK;
	devctl_ap_state_t	devctl_ap_state;
	char			*pdyn;


	if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
		(void) cfga_help(NULL, options, flags);
		goto bailout;
	}
	/* We do not care here about dynamic AP name component */
	if ((pdyn = GET_DYN(ap_id)) != NULL) {
		*pdyn = '\0';
	}

	if (ap_id_list == NULL || nlistp == NULL) {
		rv = CFGA_SATA_DATA_ERROR;
		(void) cfga_help(NULL, options, flags);
		goto bailout;
	}

	/* Get ap status */
	if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
	    DC_RDONLY)) != CFGA_SATA_OK) {
		goto bailout;
	}

	/* will call dc_cmd to send IOCTL to kernel */
	if (devctl_ap_getstate(devctl_hdl, user_nvlist,
	    &devctl_ap_state) == -1) {
		cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
		rv = CFGA_SATA_IOCTL;
		goto bailout;
	}

	cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);

	/*
	 * Create cfga_list_data_t struct.
	 */
	if ((*ap_id_list =
	    (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
		rv = CFGA_SATA_ALLOC_FAIL;
		goto bailout;
	}
	*nlistp = 1;

	/*
	 * Rest of the code fills in the cfga_list_data_t struct.
	 */

	/* Get /dev/cfg path to corresponding to the physical ap_id */
	/* Remember ap_id_log must be freed */
	rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
	    &ap_id_log, &l_errno);

	if (rv != 0) {
		rv = CFGA_SATA_DEVLINK;
		goto bailout;
	}

	/* Get logical ap_id corresponding to the physical */
	if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
		rv = CFGA_SATA_DEVLINK;
		goto bailout;
	}

	(void) strlcpy((*ap_id_list)->ap_log_id,
	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
	    sizeof ((*ap_id_list)->ap_log_id));

	free(ap_id_log);
	ap_id_log = NULL;

	(void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
	    sizeof ((*ap_id_list)->ap_phys_id));

	switch (devctl_ap_state.ap_rstate) {
		case AP_RSTATE_EMPTY:
			(*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
			break;

		case AP_RSTATE_DISCONNECTED:
			(*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
			break;

		case AP_RSTATE_CONNECTED:
			(*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
			break;

		default:
			rv = CFGA_SATA_STATE;
			goto bailout;
	}

	switch (devctl_ap_state.ap_ostate) {
		case AP_OSTATE_CONFIGURED:
			(*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
			break;

		case AP_OSTATE_UNCONFIGURED:
			(*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
			break;

		default:
			rv = CFGA_SATA_STATE;
			goto bailout;
	}

	switch (devctl_ap_state.ap_condition) {
		case AP_COND_OK:
			(*ap_id_list)->ap_cond = CFGA_COND_OK;
			break;

		case AP_COND_FAILING:
			(*ap_id_list)->ap_cond = CFGA_COND_FAILING;
			break;

		case AP_COND_FAILED:
			(*ap_id_list)->ap_cond = CFGA_COND_FAILED;
			break;

		case AP_COND_UNUSABLE:
			(*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
			break;

		case AP_COND_UNKNOWN:
			(*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
			break;

		default:
			rv = CFGA_SATA_STATE;
			goto bailout;
	}

	(*ap_id_list)->ap_class[0] = '\0';	/* Filled by libcfgadm */
	(*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
	(*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
	(*ap_id_list)->ap_info[0] = NULL;

	if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
		char *str_p;
		int skip, i;

		/*
		 * Fill in the 'Information' field for the -v option
		 * Model (MOD:)
		 */
		if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
		    NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
			(void) printf(
				"SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
			goto bailout;
		}
		/* drop leading and trailing spaces */
		skip = strspn(str_p, " ");
		for (i = size - 1; i >= 0; i--) {
			if (str_p[i] == '\040')
				str_p[i] = '\0';
			else if (str_p[i] != '\0')
				break;
		}

		(void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
			sizeof ((*ap_id_list)->ap_info));
		(void) strlcat((*ap_id_list)->ap_info, str_p + skip,
			sizeof ((*ap_id_list)->ap_info));

		free(str_p);

		/*
		 * Fill in the 'Information' field for the -v option
		 * Firmware revision (FREV:)
		 */
		if ((rv = do_control_ioctl(ap_id,
		    SATA_CFGA_GET_REVFIRMWARE_INFO,
		    NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
			(void) printf(
			    "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
			goto bailout;
		}
		/* drop leading and trailing spaces */
		skip = strspn(str_p, " ");
		for (i = size - 1; i >= 0; i--) {
			if (str_p[i] == '\040')
				str_p[i] = '\0';
			else if (str_p[i] != '\0')
				break;
		}
		(void) strlcat((*ap_id_list)->ap_info, " FRev: ",
			sizeof ((*ap_id_list)->ap_info));
		(void) strlcat((*ap_id_list)->ap_info, str_p + skip,
			sizeof ((*ap_id_list)->ap_info));

		free(str_p);


		/*
		 * Fill in the 'Information' field for the -v option
		 * Serial Number (SN:)
		 */
		if ((rv = do_control_ioctl(ap_id,
		    SATA_CFGA_GET_SERIALNUMBER_INFO,
		    NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
			(void) printf(
			    "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
			goto bailout;
		}
		/* drop leading and trailing spaces */
		skip = strspn(str_p, " ");
		for (i = size - 1; i >= 0; i--) {
			if (str_p[i] == '\040')
				str_p[i] = '\0';
			else if (str_p[i] != '\0')
				break;
		}
		(void) strlcat((*ap_id_list)->ap_info, " SN: ",
				sizeof ((*ap_id_list)->ap_info));
		(void) strlcat((*ap_id_list)->ap_info, str_p + skip,
				sizeof ((*ap_id_list)->ap_info));

		free(str_p);



		/* Fill in ap_type which is collected from HBA driver */
		/* call do_control_ioctl TBD */
		if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
		    (void **)&str_p, &size)) != CFGA_SATA_OK) {
			(void) printf(
				"SATA_CFGA_GET_AP_TYPE ioctl failed\n");
			goto bailout;
		}

		(void) strlcpy((*ap_id_list)->ap_type, str_p,
			sizeof ((*ap_id_list)->ap_type));

		free(str_p);

		if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED) {

			char *dyncomp = NULL;

			/*
			 * This is the case where we need to generate
			 * a dynamic component of the ap_id, i.e. device.
			 */
			rv = sata_make_dyncomp(ap_id, &dyncomp);
			if (rv != CFGA_SATA_OK)
				goto bailout;
			if (dyncomp != NULL) {
				(void) strcat((*ap_id_list)->ap_log_id,
					DYN_SEP);
				(void) strlcat((*ap_id_list)->ap_log_id,
					dyncomp,
					sizeof ((*ap_id_list)->ap_log_id));
				free(dyncomp);
			}
		}

	} else {
		/* Change it when port multiplier is supported */
		(void) strlcpy((*ap_id_list)->ap_type, "sata-port",
			sizeof ((*ap_id_list)->ap_type));
	}

	return (sata_err_msg(errstring, rv, ap_id, errno));

bailout:
	if (*ap_id_list != NULL) {
		free(*ap_id_list);
	}
	if (ap_id_log != NULL) {
		free(ap_id_log);
	}

	return (sata_err_msg(errstring, rv, ap_id, errno));
}
Example #4
0
static cfga_sata_ret_t
physpath_to_devlink(const char *basedir, const char *node_path,
    char **logpp, int *l_errnop)
{
	char *linkpath;
	char *buf;
	char *real_path;
	DIR *dp;
	struct dirent *dep, *newdep;
	int deplen;
	boolean_t found = B_FALSE;
	int err = 0;
	struct stat sb;
	char *p;
	cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR;

	/*
	 * Using libdevinfo for this is overkill and kills performance
	 * when multiple consumers of libcfgadm are executing
	 * concurrently.
	 */
	if ((dp = opendir(basedir)) == NULL) {
		*l_errnop = errno;
		return (CFGA_SATA_INTERNAL_ERROR);
	}

	linkpath = malloc(PATH_MAX);
	buf = malloc(PATH_MAX);
	real_path = malloc(PATH_MAX);

	deplen = pathconf(basedir, _PC_NAME_MAX) +
	    sizeof (struct dirent);
	dep = (struct dirent *)malloc(deplen);

	if (dep == NULL || linkpath == NULL || buf == NULL ||
	    real_path == NULL) {
		*l_errnop = ENOMEM;
		rv = CFGA_SATA_ALLOC_FAIL;
		goto pp_cleanup;
	}

	*logpp = NULL;

	while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
	    newdep != NULL) {

		assert(newdep == dep);

		if (strcmp(dep->d_name, ".") == 0 ||
		    strcmp(dep->d_name, "..") == 0)
			continue;

		(void) snprintf(linkpath, MAXPATHLEN,
		    "%s/%s", basedir, dep->d_name);

		if (lstat(linkpath, &sb) < 0)
			continue;

		if (S_ISDIR(sb.st_mode)) {

			if ((rv = physpath_to_devlink(linkpath, node_path,
			    logpp, l_errnop)) != CFGA_SATA_OK) {

				goto pp_cleanup;
			}

			if (*logpp != NULL)
				found = B_TRUE;

		} else if (S_ISLNK(sb.st_mode)) {

			bzero(buf, PATH_MAX);
			if (readlink(linkpath, buf, PATH_MAX) < 0)
				continue;


			/*
			 * realpath() is too darn slow, so fake
			 * it, by using what we know about /dev
			 * links: they are always of the form:
			 * <"../">+/devices/<path>
			 */
			p = buf;
			while (strncmp(p, "../", 3) == 0)
				p += 3;

			if (p != buf)
				p--;	/* back up to get a slash */

			assert (*p == '/');

			if (strcmp(p, node_path) == 0) {
				*logpp = strdup(linkpath);
				if (*logpp == NULL) {

					rv = CFGA_SATA_ALLOC_FAIL;
					goto pp_cleanup;
				}

				found = B_TRUE;
			}
		}
	}

	free(linkpath);
	free(buf);
	free(real_path);
	free(dep);
	(void) closedir(dp);

	if (err != 0) {
		*l_errnop = err;
		return (CFGA_SATA_INTERNAL_ERROR);
	}

	return (CFGA_SATA_OK);

pp_cleanup:

	if (dp)
		(void) closedir(dp);
	if (dep)
		free(dep);
	if (linkpath)
		free(linkpath);
	if (buf)
		free(buf);
	if (real_path)
		free(real_path);
	if (*logpp) {
		free(*logpp);
		*logpp = NULL;
	}
	return (rv);
}
Example #5
0
/*
 * The dynamic component buffer returned by this function has to be freed!
 */
int
sata_make_dyncomp(const char *ap_id, char **dyncomp)
{
	char	*devpath = NULL;
	char	*cp = NULL;
	int	l_errno;
	char	minor_path[MAXPATHLEN];
	char	name_part[MAXNAMELEN];
	char	*devlink = NULL;
	char	*minor_portion = NULL;
	int	deplen;
	int	err;
	DIR	*dp = NULL;
	struct stat sb;
	struct dirent *dep = NULL;
	struct dirent *newdep = NULL;
	char	*p;

	assert(dyncomp != NULL);

	/*
	 * Get target node path
	 */
	devpath = sata_get_devicepath(ap_id);
	if (devpath == NULL) {

		(void) printf("cfga_list_ext: cannot locate target device\n");
		return (CFGA_SATA_DYNAMIC_AP);

	} else {

		cp = strrchr(devpath, *PATH_SEP);
		assert(cp != NULL);
		*cp = 0;	/* terminate path for opendir() */

		(void) strncpy(name_part, cp + 1, MAXNAMELEN);

		/*
		 * Using libdevinfo for this is overkill and kills
		 * performance when many consumers are using libcfgadm
		 * concurrently.
		 */
		if ((dp = opendir(devpath)) == NULL) {
			goto bailout;
		}

		/*
		 * deplen is large enough to fit the largest path-
		 * struct dirent includes one byte (the terminator)
		 * so we don't add 1 to the calculation here.
		 */
		deplen = pathconf(devpath, _PC_NAME_MAX) +
		    sizeof (struct dirent);
		dep = (struct dirent *)malloc(deplen);
		if (dep == NULL)
			goto bailout;

		while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
		    newdep != NULL) {

			assert(newdep == dep);

			if (strcmp(dep->d_name, ".") == 0 ||
			    strcmp(dep->d_name, "..") == 0 ||
			    (minor_portion = strchr(dep->d_name,
			    *MINOR_SEP)) == NULL)
				continue;

			*minor_portion = 0;
			if (strcmp(dep->d_name, name_part) != 0)
				continue;
			*minor_portion = *MINOR_SEP;

			(void) snprintf(minor_path, MAXPATHLEN,
			    "%s/%s", devpath, dep->d_name);

			if (stat(minor_path, &sb) < 0)
				continue;

			if (S_ISBLK(sb.st_mode))
				break;
		}

		(void) closedir(dp);
		free(dep);
		free(devpath);

		dp = NULL;
		dep = NULL;
		devpath = NULL;

		/*
		 * If there was an error, or we didn't exit the loop
		 * by finding a block or character device, bail out.
		 */
		if (err != 0 || newdep == NULL)
			goto bailout;

		/*
		 * Look for links to the physical path in /dev/dsk,
		 * since we ONLY looked for BLOCK devices above.
		 */
		(void) physpath_to_devlink("/dev/dsk",
		    minor_path, &devlink, &l_errno);

		/* postprocess and copy logical name here */
		if (devlink != NULL) {
			/*
			 * For disks, remove partition/slice info
			 */
			if ((cp = strstr(devlink, "dsk/")) != NULL) {
				/* cXtYdZ[(s[0..15])|(p[0..X])] */
				if ((p = strchr(cp + 4, 'd')) != NULL) {
					p++;	/* Skip the 'd' */
					while (*p != 0 && isdigit(*p))
						p++;
					*p = 0;
				}
				*dyncomp = strdup(cp);
			}

			free(devlink);
		}

		return (SATA_CFGA_OK);
	}

bailout:
	if (dp)
		(void) closedir(dp);
	if (devpath)
		free(devpath);
	if (dep)
		free(dep);
	return (CFGA_SATA_DYNAMIC_AP);
}