Blame usr/iscsi_sysfs.c

Packit eace71
/*
Packit eace71
 * iSCSI sysfs
Packit eace71
 *
Packit eace71
 * Copyright (C) 2006 Mike Christie
Packit eace71
 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
Packit eace71
 *
Packit eace71
 * This program is free software; you can redistribute it and/or modify
Packit eace71
 * it under the terms of the GNU General Public License as published
Packit eace71
 * by the Free Software Foundation; either version 2 of the License, or
Packit eace71
 * (at your option) any later version.
Packit eace71
 *
Packit eace71
 * This program is distributed in the hope that it will be useful, but
Packit eace71
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eace71
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit eace71
 * General Public License for more details.
Packit eace71
 */
Packit eace71
#include <fcntl.h>
Packit eace71
#include <unistd.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <stdio.h>
Packit eace71
#include <ctype.h>
Packit eace71
#include <string.h>
Packit eace71
#include <errno.h>
Packit eace71
#include <dirent.h>
Packit eace71
#include <sys/types.h>
Packit eace71
#include <sys/stat.h>
Packit eace71
#include <sys/wait.h>
Packit eace71
Packit eace71
#include "log.h"
Packit eace71
#include "initiator.h"
Packit eace71
#include "transport.h"
Packit eace71
#include "idbm.h"
Packit eace71
#include "idbm_fields.h"
Packit eace71
#include "version.h"
Packit eace71
#include "iscsi_sysfs.h"
Packit eace71
#include "sysdeps.h"
Packit eace71
#include "iscsi_settings.h"
Packit eace71
#include "iface.h"
Packit eace71
#include "session_info.h"
Packit eace71
#include "host.h"
Packit eace71
#include "iscsi_err.h"
Packit eace71
#include "flashnode.h"
Packit eace71
Packit eace71
/*
Packit eace71
 * TODO: remove the _DIR defines and search for subsys dirs like
Packit eace71
 *  is done in sysfs.c.
Packit eace71
 */
Packit eace71
#define ISCSI_TRANSPORT_DIR	"/sys/class/iscsi_transport"
Packit eace71
#define ISCSI_SESSION_DIR	"/sys/class/iscsi_session"
Packit eace71
#define ISCSI_HOST_DIR		"/sys/class/iscsi_host"
Packit eace71
#define ISCSI_FLASHNODE_DIR	"/sys/bus/iscsi_flashnode/devices"
Packit eace71
Packit eace71
#define ISCSI_SESSION_SUBSYS		"iscsi_session"
Packit eace71
#define ISCSI_CONN_SUBSYS		"iscsi_connection"
Packit eace71
#define ISCSI_HOST_SUBSYS		"iscsi_host"
Packit eace71
#define ISCSI_TRANSPORT_SUBSYS		"iscsi_transport"
Packit eace71
#define ISCSI_IFACE_SUBSYS		"iscsi_iface"
Packit eace71
#define ISCSI_FLASHNODE_SUBSYS		"iscsi_flashnode"
Packit eace71
#define SCSI_HOST_SUBSYS		"scsi_host"
Packit eace71
#define SCSI_SUBSYS			"scsi"
Packit eace71
Packit eace71
#define ISCSI_SESSION_ID		"session%d"
Packit eace71
#define ISCSI_CONN_ID			"connection%d:0"
Packit eace71
#define ISCSI_HOST_ID			"host%d"
Packit eace71
#define ISCSI_FLASHNODE_SESS		"flashnode_sess-%d:%d"
Packit eace71
#define ISCSI_FLASHNODE_CONN		"flashnode_conn-%d:%d:0"
Packit eace71
Packit eace71
/*
Packit eace71
 * TODO: make this into a real API and check inputs better and add doc.
Packit eace71
 */
Packit eace71
Packit eace71
static int num_transports;
Packit eace71
LIST_HEAD(transports);
Packit eace71
Packit eace71
void free_transports(void)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t, *tmp;
Packit eace71
Packit eace71
	list_for_each_entry_safe(t, tmp, &transports, list) {
Packit eace71
		list_del(&t->list);
Packit eace71
		free(t);
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static int trans_filter(const struct dirent *dir)
Packit eace71
{
Packit eace71
	return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..");
Packit eace71
}
Packit eace71
Packit eace71
static int read_transports(void)
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int i, n, found;
Packit eace71
	struct iscsi_transport *t;
Packit eace71
Packit eace71
	log_debug(7, "in %s", __FUNCTION__);
Packit eace71
Packit eace71
	n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter,
Packit eace71
		    alphasort);
Packit eace71
	if (n < 0) {
Packit eace71
		log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR);
Packit eace71
		return n;
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		found = 0;
Packit eace71
Packit eace71
		list_for_each_entry(t, &transports, list) {
Packit eace71
			if (!strcmp(t->name, namelist[i]->d_name)) {
Packit eace71
				found = 1;
Packit eace71
				break;
Packit eace71
			}
Packit eace71
		}
Packit eace71
Packit eace71
		if (!found) {
Packit eace71
			/* copy new transport */
Packit eace71
			t = malloc(sizeof(*t));
Packit eace71
			if (!t)
Packit eace71
				continue;
Packit eace71
			log_debug(7, "Adding new transport %s",
Packit eace71
				  namelist[i]->d_name);
Packit eace71
Packit eace71
			INIT_LIST_HEAD(&t->sessions);
Packit eace71
			INIT_LIST_HEAD(&t->list);
Packit eace71
			strlcpy(t->name, namelist[i]->d_name,
Packit eace71
				ISCSI_TRANSPORT_NAME_MAXLEN);
Packit eace71
			if (set_transport_template(t)) {
Packit eace71
				free(t);
Packit eace71
				return -1;
Packit eace71
			}
Packit eace71
		} else
Packit eace71
			log_debug(7, "Updating transport %s",
Packit eace71
				  namelist[i]->d_name);
Packit eace71
Packit eace71
		if (sysfs_get_uint64(t->name, ISCSI_TRANSPORT_SUBSYS,
Packit eace71
				     "handle", &t->handle)) {
Packit eace71
			if (list_empty(&t->list))
Packit eace71
				free(t);
Packit eace71
			else
Packit eace71
				log_error("Could not update %s.",
Packit eace71
					  t->name);
Packit eace71
			continue;
Packit eace71
		}
Packit eace71
Packit eace71
		if (sysfs_get_uint(t->name, ISCSI_TRANSPORT_SUBSYS,
Packit eace71
				  "caps", &t->caps)) {
Packit eace71
			if (list_empty(&t->list))
Packit eace71
				free(t);
Packit eace71
			else
Packit eace71
				log_error("Could not update %s.",
Packit eace71
					  t->name);
Packit eace71
			continue;
Packit eace71
		}
Packit eace71
		/*
Packit eace71
		 * tmp hack for qla4xx compat
Packit eace71
		 */
Packit eace71
		if (!strcmp(t->name, "qla4xxx")) {
Packit eace71
			t->caps |= CAP_DATA_PATH_OFFLOAD;
Packit eace71
		}
Packit eace71
Packit eace71
		if (list_empty(&t->list))
Packit eace71
			list_add_tail(&t->list, &transports);
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
	num_transports = n;
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
/* caller must check lengths */
Packit eace71
void iscsi_sysfs_get_auth_conf(int sid, struct iscsi_auth_config *conf)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	memset(conf, 0, sizeof(*conf));
Packit eace71
	snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
Packit eace71
Packit eace71
	sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "username", conf->username,
Packit eace71
		      sizeof(conf->username));
Packit eace71
	sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "username_in",
Packit eace71
		      conf->username_in, sizeof(conf->username_in));
Packit eace71
Packit eace71
	sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "password",
Packit eace71
		      (char *)conf->password, sizeof(conf->password));
Packit eace71
	if (strlen((char *)conf->password))
Packit eace71
		conf->password_length = strlen((char *)conf->password);
Packit eace71
Packit eace71
	sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "password_in",
Packit eace71
		      (char *)conf->password_in, sizeof(conf->password_in));
Packit eace71
	if (strlen((char *)conf->password_in))
Packit eace71
		conf->password_in_length = strlen((char *)conf->password_in);
Packit eace71
}
Packit eace71
Packit eace71
/* called must check for -1=invalid value */
Packit eace71
void iscsi_sysfs_get_negotiated_conn_conf(int sid,
Packit eace71
				struct iscsi_conn_operational_config *conf)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	memset(conf, 0, sizeof(*conf));
Packit eace71
	snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
Packit eace71
Packit eace71
	sysfs_get_int(id, ISCSI_CONN_SUBSYS, "data_digest", &conf->DataDigest);
Packit eace71
	sysfs_get_int(id, ISCSI_CONN_SUBSYS, "header_digest",
Packit eace71
		      &conf->HeaderDigest);
Packit eace71
	sysfs_get_int(id, ISCSI_CONN_SUBSYS, "max_xmit_dlength",
Packit eace71
		      &conf->MaxXmitDataSegmentLength);
Packit eace71
	sysfs_get_int(id, ISCSI_CONN_SUBSYS, "max_recv_dlength",
Packit eace71
		       &conf->MaxRecvDataSegmentLength);
Packit eace71
}
Packit eace71
Packit eace71
/* called must check for -1=invalid value */
Packit eace71
void iscsi_sysfs_get_negotiated_session_conf(int sid,
Packit eace71
				struct iscsi_session_operational_config *conf)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	memset(conf, 0, sizeof(*conf));
Packit eace71
	snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
Packit eace71
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "data_pdu_in_order",
Packit eace71
		      &conf->DataPDUInOrder);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "data_seq_in_order",
Packit eace71
		      &conf->DataSequenceInOrder);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "erl", &conf->ERL);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "first_burst_len",
Packit eace71
		       &conf->FirstBurstLength);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "max_burst_len",
Packit eace71
		      &conf->MaxBurstLength);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "immediate_data",
Packit eace71
		      &conf->ImmediateData);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "initial_r2t",
Packit eace71
		      &conf->InitialR2T);
Packit eace71
	sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "max_outstanding_r2t",
Packit eace71
		      &conf->MaxOutstandingR2T);
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * iscsi_sysfs_session_user_created - return if session was setup by userspace
Packit eace71
 * @sid: id of session to test
Packit eace71
 *
Packit eace71
 * Returns -1 if we could not tell due to kernel not supporting the
Packit eace71
 * feature. 0 is returned if kernel created it. And 1 is returned
Packit eace71
 * if userspace created it.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_session_user_created(int sid)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	pid_t pid;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
Packit eace71
	if (sysfs_get_int(id, ISCSI_SESSION_SUBSYS, "creator", &pid))
Packit eace71
		return -1;
Packit eace71
Packit eace71
	if (pid == -1)
Packit eace71
		return 0;
Packit eace71
	else
Packit eace71
		return 1;
Packit eace71
}
Packit eace71
Packit eace71
uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
Packit eace71
{
Packit eace71
	struct sysfs_device *session_dev, *host_dev;
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	*err = 0;
Packit eace71
	snprintf(id, sizeof(id), "session%u", sid);
Packit eace71
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
					       ISCSI_SESSION_SUBSYS, id)) {
Packit eace71
		log_error("Could not lookup devpath for %s. Possible sysfs "
Packit eace71
			  "incompatibility.", id);
Packit eace71
		*err = ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		return 0;
Packit eace71
	}
Packit eace71
Packit eace71
	session_dev = sysfs_device_get(devpath);
Packit eace71
	if (!session_dev) {
Packit eace71
		log_error("Could not get dev for %s. Possible sysfs "
Packit eace71
			  "incompatibility.", id);
Packit eace71
		*err = ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		return 0;
Packit eace71
	}
Packit eace71
Packit eace71
	/*
Packit eace71
	 * 2.6.27 moved from scsi_host to scsi for the subsys when
Packit eace71
	 * sysfs compat is not on.
Packit eace71
	 */
Packit eace71
	host_dev = sysfs_device_get_parent_with_subsystem(session_dev,
Packit eace71
							  SCSI_SUBSYS);
Packit eace71
	if (!host_dev) {
Packit eace71
		struct sysfs_device *dev_parent;
Packit eace71
Packit eace71
		dev_parent = sysfs_device_get_parent(session_dev);
Packit eace71
		while (dev_parent != NULL) {
Packit eace71
			if (strncmp(dev_parent->kernel, "host", 4) == 0) {
Packit eace71
				host_dev = dev_parent;
Packit eace71
				break;
Packit eace71
			}
Packit eace71
			dev_parent = sysfs_device_get_parent(dev_parent);
Packit eace71
		}
Packit eace71
Packit eace71
		if (!host_dev) {
Packit eace71
			log_error("Could not get host dev for %s. Possible "
Packit eace71
				  "sysfs incompatibility.", id);
Packit eace71
			*err = ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
			return 0;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	return atol(host_dev->kernel_number);
Packit eace71
}
Packit eace71
Packit eace71
/* TODO: merge and make macro */
Packit eace71
static int __get_host_no_from_netdev(void *data, struct host_info *info)
Packit eace71
{
Packit eace71
	struct host_info *ret_info = data;
Packit eace71
Packit eace71
	if (!strcmp(ret_info->iface.netdev, info->iface.netdev)) {
Packit eace71
		ret_info->host_no = info->host_no;
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static uint32_t get_host_no_from_netdev(char *netdev, int *rc)
Packit eace71
{
Packit eace71
	uint32_t host_no = -1;
Packit eace71
	struct host_info *info;
Packit eace71
	int nr_found, local_rc;
Packit eace71
Packit eace71
	*rc = 0;
Packit eace71
Packit eace71
	info = calloc(1, sizeof(*info));
Packit eace71
	if (!info) {
Packit eace71
		*rc = ISCSI_ERR_NOMEM;
Packit eace71
		return -1;
Packit eace71
	}
Packit eace71
	strcpy(info->iface.netdev, netdev);
Packit eace71
Packit eace71
	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
Packit eace71
					     __get_host_no_from_netdev);
Packit eace71
	if (local_rc == 1)
Packit eace71
		host_no = info->host_no;
Packit eace71
	else
Packit eace71
		*rc = ISCSI_ERR_HOST_NOT_FOUND;
Packit eace71
	free(info);
Packit eace71
	return host_no;
Packit eace71
}
Packit eace71
Packit eace71
static int __get_host_no_from_hwaddress(void *data, struct host_info *info)
Packit eace71
{
Packit eace71
	struct host_info *ret_info = data;
Packit eace71
Packit eace71
	if (!strcasecmp(ret_info->iface.hwaddress, info->iface.hwaddress)) {
Packit eace71
		ret_info->host_no = info->host_no;
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int *rc)
Packit eace71
{
Packit eace71
	uint32_t host_no = -1;
Packit eace71
	struct host_info *info;
Packit eace71
	int nr_found, local_rc;
Packit eace71
Packit eace71
	*rc = 0;
Packit eace71
Packit eace71
	info = calloc(1, sizeof(*info));
Packit eace71
	if (!info) {
Packit eace71
		*rc = ISCSI_ERR_NOMEM;
Packit eace71
		return -1;
Packit eace71
	}
Packit eace71
	strcpy(info->iface.hwaddress, hwaddress);
Packit eace71
Packit eace71
	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
Packit eace71
					__get_host_no_from_hwaddress);
Packit eace71
	if (local_rc == 1)
Packit eace71
		host_no = info->host_no;
Packit eace71
	else
Packit eace71
		*rc = ISCSI_ERR_HOST_NOT_FOUND;
Packit eace71
	free(info);
Packit eace71
	return host_no;
Packit eace71
}
Packit eace71
Packit eace71
static int __get_host_no_from_ipaddress(void *data, struct host_info *info)
Packit eace71
{
Packit eace71
	struct host_info *ret_info = data;
Packit eace71
Packit eace71
	if (!strcmp(ret_info->iface.ipaddress, info->iface.ipaddress)) {
Packit eace71
		ret_info->host_no = info->host_no;
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static uint32_t get_host_no_from_ipaddress(char *address, int *rc)
Packit eace71
{
Packit eace71
	uint32_t host_no = -1;
Packit eace71
	struct host_info *info;
Packit eace71
	int nr_found;
Packit eace71
	int local_rc;
Packit eace71
Packit eace71
	*rc = 0;
Packit eace71
Packit eace71
	info = calloc(1, sizeof(*info));
Packit eace71
	if (!info) {
Packit eace71
		*rc = ISCSI_ERR_NOMEM;
Packit eace71
		return -1;
Packit eace71
	}
Packit eace71
	strcpy(info->iface.ipaddress, address);
Packit eace71
Packit eace71
	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
Packit eace71
					     __get_host_no_from_ipaddress);
Packit eace71
	if (local_rc == 1)
Packit eace71
		host_no = info->host_no;
Packit eace71
	else
Packit eace71
		*rc = ISCSI_ERR_HOST_NOT_FOUND;
Packit eace71
	free(info);
Packit eace71
	return host_no;
Packit eace71
}
Packit eace71
Packit eace71
uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, int *rc)
Packit eace71
{
Packit eace71
	int tmp_rc;
Packit eace71
	uint32_t host_no = -1;
Packit eace71
Packit eace71
	if (strlen(iface->hwaddress) &&
Packit eace71
	    strcasecmp(iface->hwaddress, DEFAULT_HWADDRESS))
Packit eace71
		host_no = iscsi_sysfs_get_host_no_from_hwaddress(
Packit eace71
						iface->hwaddress, &tmp_rc);
Packit eace71
	else if (strlen(iface->netdev) &&
Packit eace71
		strcasecmp(iface->netdev, DEFAULT_NETDEV))
Packit eace71
		host_no = get_host_no_from_netdev(iface->netdev, &tmp_rc);
Packit eace71
	else if (strlen(iface->ipaddress) &&
Packit eace71
		 strcasecmp(iface->ipaddress, DEFAULT_IPADDRESS))
Packit eace71
		host_no = get_host_no_from_ipaddress(iface->ipaddress, &tmp_rc);
Packit eace71
	else
Packit eace71
		tmp_rc = ISCSI_ERR_INVAL;
Packit eace71
Packit eace71
	*rc = tmp_rc;
Packit eace71
	return host_no;
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * Read the flash node attributes based on host and flash node index.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode,
Packit eace71
				   uint32_t host_no,
Packit eace71
				   uint32_t flashnode_idx)
Packit eace71
{
Packit eace71
	char sess_id[NAME_SIZE] = {'\0'};
Packit eace71
	char conn_id[NAME_SIZE] = {'\0'};
Packit eace71
	char fnode_path[PATH_SIZE] = {'\0'};
Packit eace71
	struct iscsi_transport *t;
Packit eace71
	int ret = 0;
Packit eace71
Packit eace71
	t = iscsi_sysfs_get_transport_by_hba(host_no);
Packit eace71
	if (!t)
Packit eace71
		log_debug(7, "could not get transport name for host%d",
Packit eace71
			  host_no);
Packit eace71
	else
Packit eace71
		strlcpy(fnode->transport_name, t->name,
Packit eace71
			ISCSI_TRANSPORT_NAME_MAXLEN);
Packit eace71
Packit eace71
	snprintf(sess_id, sizeof(sess_id), ISCSI_FLASHNODE_SESS, host_no,
Packit eace71
		 flashnode_idx);
Packit eace71
Packit eace71
	snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
Packit eace71
		 sess_id);
Packit eace71
	if (access(fnode_path, F_OK) != 0)
Packit eace71
		return errno;
Packit eace71
Packit eace71
	snprintf(conn_id, sizeof(conn_id), ISCSI_FLASHNODE_CONN, host_no,
Packit eace71
		 flashnode_idx);
Packit eace71
Packit eace71
	snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
Packit eace71
		 conn_id);
Packit eace71
	if (access(fnode_path, F_OK) != 0)
Packit eace71
		return errno;
Packit eace71
Packit eace71
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "is_fw_assigned_ipv6",
Packit eace71
			&((fnode->conn[0]).is_fw_assigned_ipv6));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "portal_type",
Packit eace71
		      (fnode->sess).portal_type,
Packit eace71
		      sizeof((fnode->sess).portal_type));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "auto_snd_tgt_disable",
Packit eace71
			&((fnode->sess).auto_snd_tgt_disable));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_session",
Packit eace71
			&((fnode->sess).discovery_session));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "entry_enable",
Packit eace71
			&((fnode->sess).entry_enable));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "header_digest",
Packit eace71
			&((fnode->conn[0]).header_digest_en));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "data_digest",
Packit eace71
			&((fnode->conn[0]).data_digest_en));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "immediate_data",
Packit eace71
			&((fnode->sess).immediate_data));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "initial_r2t",
Packit eace71
			&((fnode->sess).initial_r2t));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_seq_in_order",
Packit eace71
			&((fnode->sess).data_seq_in_order));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_pdu_in_order",
Packit eace71
			&((fnode->sess).data_pdu_in_order));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_auth",
Packit eace71
			&((fnode->sess).chap_auth_en));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "snack_req",
Packit eace71
			&((fnode->conn[0]).snack_req_en));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_logout",
Packit eace71
			&((fnode->sess).discovery_logout_en));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "bidi_chap",
Packit eace71
			&((fnode->sess).bidi_chap_en));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS,
Packit eace71
			"discovery_auth_optional",
Packit eace71
			&((fnode->sess).discovery_auth_optional));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "erl",
Packit eace71
			&((fnode->sess).erl));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_stat",
Packit eace71
			&((fnode->conn[0]).tcp_timestamp_stat));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_nagle_disable",
Packit eace71
			&((fnode->conn[0]).tcp_nagle_disable));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_wsf_disable",
Packit eace71
			&((fnode->conn[0]).tcp_wsf_disable));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timer_scale",
Packit eace71
			&((fnode->conn[0]).tcp_timer_scale));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_enable",
Packit eace71
			&((fnode->conn[0]).tcp_timestamp_en));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "fragment_disable",
Packit eace71
			&((fnode->conn[0]).fragment_disable));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_recv_dlength",
Packit eace71
		       &((fnode->conn[0]).max_recv_dlength));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_xmit_dlength",
Packit eace71
		       &((fnode->conn[0]).max_xmit_dlength));
Packit eace71
	sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "first_burst_len",
Packit eace71
		       &((fnode->sess).first_burst_len));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2wait",
Packit eace71
			 &((fnode->sess).def_time2wait));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2retain",
Packit eace71
			 &((fnode->sess).def_time2retain));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_outstanding_r2t",
Packit eace71
			 &((fnode->sess).max_outstanding_r2t));
Packit eace71
	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "keepalive_tmo",
Packit eace71
			 &((fnode->conn[0]).keepalive_tmo));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "isid",
Packit eace71
		      (fnode->sess).isid, sizeof((fnode->sess).isid));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tsid",
Packit eace71
			 &((fnode->sess).tsid));
Packit eace71
	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "port",
Packit eace71
			 &((fnode->conn[0]).port));
Packit eace71
	sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_burst_len",
Packit eace71
		       &((fnode->sess).max_burst_len));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_taskmgmt_tmo",
Packit eace71
			 &((fnode->sess).def_taskmgmt_tmo));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetalias",
Packit eace71
		      (fnode->sess).targetalias,
Packit eace71
		      sizeof((fnode->sess).targetalias));
Packit eace71
	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipaddress",
Packit eace71
		      (fnode->conn[0]).ipaddress,
Packit eace71
		      sizeof((fnode->conn[0]).ipaddress));
Packit eace71
	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "redirect_ipaddr",
Packit eace71
		      (fnode->conn[0]).redirect_ipaddr,
Packit eace71
		      sizeof((fnode->conn[0]).redirect_ipaddr));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_segment_size",
Packit eace71
		       &((fnode->conn[0]).max_segment_size));
Packit eace71
	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "local_port",
Packit eace71
			 &((fnode->conn[0]).local_port));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv4_tos",
Packit eace71
			&((fnode->conn[0]).ipv4_tos));
Packit eace71
	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_traffic_class",
Packit eace71
			&((fnode->conn[0]).ipv6_traffic_class));
Packit eace71
	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_flow_label",
Packit eace71
			 &((fnode->conn[0]).ipv6_flow_lbl));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetname",
Packit eace71
		      (fnode->sess).targetname,
Packit eace71
		      sizeof((fnode->sess).targetname));
Packit eace71
	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "link_local_ipv6",
Packit eace71
		      (fnode->conn[0]).link_local_ipv6,
Packit eace71
		      sizeof((fnode->conn[0]).link_local_ipv6));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS,
Packit eace71
			 "discovery_parent_idx",
Packit eace71
			 &((fnode->sess).discovery_parent_idx));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS,
Packit eace71
		      "discovery_parent_type",
Packit eace71
		      (fnode->sess).discovery_parent_type,
Packit eace71
		      sizeof((fnode->sess).discovery_parent_type));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tpgt",
Packit eace71
			 &((fnode->sess).tpgt));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_xmit_wsf",
Packit eace71
		       &((fnode->conn[0]).tcp_xmit_wsf));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_recv_wsf",
Packit eace71
		       &((fnode->conn[0]).tcp_recv_wsf));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_out_idx",
Packit eace71
			 &((fnode->sess).chap_out_idx));
Packit eace71
	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_in_idx",
Packit eace71
			 &((fnode->sess).chap_in_idx));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username",
Packit eace71
		      (fnode->sess).username, sizeof((fnode->sess).username));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username_in",
Packit eace71
		      (fnode->sess).username_in,
Packit eace71
		      sizeof((fnode->sess).username_in));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password",
Packit eace71
		      (fnode->sess).password, sizeof((fnode->sess).password));
Packit eace71
	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password_in",
Packit eace71
		      (fnode->sess).password_in,
Packit eace71
		      sizeof((fnode->sess).password_in));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "statsn",
Packit eace71
		       &((fnode->conn[0]).stat_sn));
Packit eace71
	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "exp_statsn",
Packit eace71
		       &((fnode->conn[0]).exp_stat_sn));
Packit eace71
	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "is_boot_target",
Packit eace71
			&((fnode->sess).is_boot_target));
Packit eace71
	return ret;
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * For each flash node of the given host, perform operation specified in fn.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no, int *nr_found,
Packit eace71
				   iscsi_sysfs_flashnode_op_fn *fn)
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int rc = 0, i, n;
Packit eace71
	struct flashnode_rec *fnode;
Packit eace71
	uint32_t flashnode_idx;
Packit eace71
	uint32_t hostno;
Packit eace71
Packit eace71
	fnode = malloc(sizeof(*fnode));
Packit eace71
	if (!fnode)
Packit eace71
		return ISCSI_ERR_NOMEM;
Packit eace71
Packit eace71
	n = scandir(ISCSI_FLASHNODE_DIR, &namelist, trans_filter, alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		goto free_fnode;
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		memset(fnode, 0, sizeof(*fnode));
Packit eace71
Packit eace71
		if (!strncmp(namelist[i]->d_name, "flashnode_conn",
Packit eace71
			     strlen("flashnode_conn")))
Packit eace71
			continue;
Packit eace71
Packit eace71
		if (sscanf(namelist[i]->d_name, ISCSI_FLASHNODE_SESS,
Packit eace71
			   &hostno, &flashnode_idx) != 2) {
Packit eace71
			log_error("Invalid iscsi target dir: %s",
Packit eace71
				  namelist[i]->d_name);
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		if (host_no != hostno)
Packit eace71
			continue;
Packit eace71
Packit eace71
		rc = iscsi_sysfs_get_flashnode_info(fnode, host_no,
Packit eace71
						    flashnode_idx);
Packit eace71
		if (rc)
Packit eace71
			break;
Packit eace71
Packit eace71
		rc = fn(data, fnode, host_no, flashnode_idx);
Packit eace71
		if (rc != 0)
Packit eace71
			break;
Packit eace71
		(*nr_found)++;
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
Packit eace71
free_fnode:
Packit eace71
	free(fnode);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
static int iscsi_sysfs_read_boot(struct iface_rec *iface, char *session)
Packit eace71
{
Packit eace71
	char boot_root[BOOT_NAME_MAXLEN], boot_nic[BOOT_NAME_MAXLEN];
Packit eace71
	char boot_name[BOOT_NAME_MAXLEN], boot_content[BOOT_NAME_MAXLEN];
Packit eace71
Packit eace71
	/* Extract boot info */
Packit eace71
	strlcpy(boot_name, "boot_target", sizeof(boot_name));
Packit eace71
	if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name,
Packit eace71
			  boot_content, BOOT_NAME_MAXLEN))
Packit eace71
		return -1;
Packit eace71
	strlcpy(boot_name, "boot_nic", sizeof(boot_name));
Packit eace71
	if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_nic,
Packit eace71
			  BOOT_NAME_MAXLEN))
Packit eace71
		return -1;
Packit eace71
	strlcpy(boot_name, "boot_root", sizeof(boot_name));
Packit eace71
	if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_root,
Packit eace71
			  BOOT_NAME_MAXLEN))
Packit eace71
		return -1;
Packit eace71
Packit eace71
	/* If all boot_root/boot_target/boot_nic exist, then extract the
Packit eace71
	   info from the boot nic */
Packit eace71
	if (sysfs_get_str(boot_nic, boot_root, "vlan", boot_content,
Packit eace71
			  BOOT_NAME_MAXLEN))
Packit eace71
		log_debug(5, "could not read %s/%s/vlan", boot_root, boot_nic);
Packit eace71
	else
Packit eace71
		iface->vlan_id = atoi(boot_content);
Packit eace71
Packit eace71
	if (sysfs_get_str(boot_nic, boot_root, "subnet-mask",
Packit eace71
			  iface->subnet_mask, NI_MAXHOST))
Packit eace71
		log_debug(5, "could not read %s/%s/subnet", boot_root,
Packit eace71
			  boot_nic);
Packit eace71
Packit eace71
	if (sysfs_get_str(boot_nic, boot_root, "gateway",
Packit eace71
			  iface->gateway, NI_MAXHOST))
Packit eace71
		log_debug(5, "could not read %s/%s/gateway", boot_root,
Packit eace71
			  boot_nic);
Packit eace71
Packit eace71
	log_debug(5, "sysfs read boot returns %s/%s/ vlan = %d subnet = %s",
Packit eace71
		  boot_root, boot_nic, iface->vlan_id, iface->subnet_mask);
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * Read in iface settings based on host and session values. If
Packit eace71
 * session is not passed in, then the ifacename will not be set. And
Packit eace71
 * if the session is not passed in then iname will only be set for
Packit eace71
 * qla4xxx.
Packit eace71
 */
Packit eace71
static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
Packit eace71
				  char *session, char *iface_kern_id)
Packit eace71
{
Packit eace71
	uint32_t tmp_host_no, iface_num;
Packit eace71
	char host_id[NAME_SIZE];
Packit eace71
	struct iscsi_transport *t;
Packit eace71
	int ret, iface_type;
Packit eace71
Packit eace71
	t = iscsi_sysfs_get_transport_by_hba(host_no);
Packit eace71
	if (!t)
Packit eace71
		log_debug(7, "could not get transport name for host%d",
Packit eace71
			  host_no);
Packit eace71
	else
Packit eace71
		strcpy(iface->transport_name, t->name);
Packit eace71
Packit eace71
	snprintf(host_id, sizeof(host_id), ISCSI_HOST_ID, host_no);
Packit eace71
	/*
Packit eace71
	 * backward compat
Packit eace71
	 * If we cannot get the address we assume we are doing the old
Packit eace71
	 * style and use default.
Packit eace71
	 */
Packit eace71
	ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "hwaddress",
Packit eace71
			    iface->hwaddress, sizeof(iface->hwaddress));
Packit eace71
	if (ret)
Packit eace71
		log_debug(7, "could not read hwaddress for host%d", host_no);
Packit eace71
Packit eace71
	if (iface_kern_id)
Packit eace71
		ret = sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				    "ipaddress",
Packit eace71
				    iface->ipaddress, sizeof(iface->ipaddress));
Packit eace71
	else
Packit eace71
		/* if not found just print out default */
Packit eace71
		ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "ipaddress",
Packit eace71
				    iface->ipaddress, sizeof(iface->ipaddress));
Packit eace71
	if (ret)
Packit eace71
		log_debug(7, "could not read local address for host%d",
Packit eace71
			  host_no);
Packit eace71
Packit eace71
	/* if not found just print out default */
Packit eace71
	ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "netdev",
Packit eace71
			    iface->netdev, sizeof(iface->netdev));
Packit eace71
	if (ret)
Packit eace71
		log_debug(7, "could not read netdev for host%d", host_no);
Packit eace71
Packit eace71
	/*
Packit eace71
	 * For drivers like qla4xxx we can only set the iname at the
Packit eace71
	 * host level because we cannot create different initiator ports
Packit eace71
	 * (cannot set isid either). The LLD also exports the iname at the
Packit eace71
	 * hba level so apps can see it, but we no longer set the iname for
Packit eace71
	 * each iscsid controlled host since bnx2i cxgbi can support multiple
Packit eace71
	 * initiator names and of course software iscsi can support anything.
Packit eace71
	 */
Packit eace71
	ret = 1;
Packit eace71
	memset(iface->iname, 0, sizeof(iface->iname));
Packit eace71
	if (session) {
Packit eace71
		ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS,
Packit eace71
				    "initiatorname",
Packit eace71
				    iface->iname, sizeof(iface->iname));
Packit eace71
		/*
Packit eace71
		 * qlaxxx will not set this at the session level so we
Packit eace71
		 * always drop down for it.
Packit eace71
		 *
Packit eace71
		 * And.
Packit eace71
		 *
Packit eace71
		 * For older kernels/tools (2.6.26 and below and 2.0.870)
Packit eace71
		 * we will not have a session level initiator name, so
Packit eace71
		 * we will drop down.
Packit eace71
		 */
Packit eace71
	}
Packit eace71
Packit eace71
	if (ret) {
Packit eace71
		ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "initiatorname",
Packit eace71
				    iface->iname, sizeof(iface->iname));
Packit eace71
		if (ret)
Packit eace71
			/*
Packit eace71
			 * default iname is picked up later from
Packit eace71
			 * initiatorname.iscsi if software/partial-offload.
Packit eace71
			 *
Packit eace71
			 * TODO: we should make it easier to get the
Packit eace71
			 * global iname so we can just fill it in here.
Packit eace71
			 */
Packit eace71
			log_debug(7, "Could not read initiatorname for "
Packit eace71
				  "host%d", host_no);
Packit eace71
		/* optional so do not return error */
Packit eace71
		ret = 0;
Packit eace71
	}
Packit eace71
Packit eace71
	sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "port_state",
Packit eace71
		      iface->port_state, sizeof(iface->port_state));
Packit eace71
Packit eace71
	sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "port_speed",
Packit eace71
		      iface->port_speed, sizeof(iface->port_speed));
Packit eace71
Packit eace71
	/*
Packit eace71
	 * this is on the session, because we support multiple bindings
Packit eace71
	 * per device.
Packit eace71
	 */
Packit eace71
	memset(iface->name, 0, sizeof(iface->name));
Packit eace71
	if (session) {
Packit eace71
		/*
Packit eace71
		 * this was added after 2.0.869 so we could be doing iscsi_tcp
Packit eace71
		 * session binding, but there may not be an ifacename set
Packit eace71
		 * if binding is not used.
Packit eace71
		 */
Packit eace71
		ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "ifacename",
Packit eace71
				    iface->name, sizeof(iface->name));
Packit eace71
		if (ret) {
Packit eace71
			log_debug(7, "could not read iface name for "
Packit eace71
				  "session %s", session);
Packit eace71
			/*
Packit eace71
			 * if the ifacename file is not there then we are
Packit eace71
			 * using a older kernel and can try to find the
Packit eace71
			 * binding by the net info which was used on these
Packit eace71
			 * older kernels.
Packit eace71
			 */
Packit eace71
			if (iface_get_by_net_binding(iface, iface))
Packit eace71
				log_debug(7, "Could not find iface for session "
Packit eace71
					  "bound to:" iface_fmt "",
Packit eace71
					  iface_str(iface));
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (session && t->template->use_boot_info)
Packit eace71
		iscsi_sysfs_read_boot(iface, session);
Packit eace71
Packit eace71
	if (!iface_kern_id)
Packit eace71
		goto done;
Packit eace71
Packit eace71
	strlcpy(iface->name, iface_kern_id, sizeof(iface->name));
Packit eace71
Packit eace71
	if (!strncmp(iface_kern_id, "ipv4", 4)) {
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "bootproto",
Packit eace71
			      iface->bootproto, sizeof(iface->bootproto));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "gateway",
Packit eace71
			      iface->gateway, sizeof(iface->gateway));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "subnet",
Packit eace71
			      iface->subnet_mask, sizeof(iface->subnet_mask));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_alt_client_id_en",
Packit eace71
			      iface->dhcp_alt_client_id_state,
Packit eace71
			      sizeof(iface->dhcp_alt_client_id_state));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_alt_client_id",
Packit eace71
			      iface->dhcp_alt_client_id,
Packit eace71
			      sizeof(iface->dhcp_alt_client_id));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_dns_address_en",
Packit eace71
			      iface->dhcp_dns, sizeof(iface->dhcp_dns));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_learn_iqn_en",
Packit eace71
			      iface->dhcp_learn_iqn,
Packit eace71
			      sizeof(iface->dhcp_learn_iqn));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_req_vendor_id_en",
Packit eace71
			      iface->dhcp_req_vendor_id_state,
Packit eace71
			      sizeof(iface->dhcp_req_vendor_id_state));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_use_vendor_id_en",
Packit eace71
			      iface->dhcp_vendor_id_state,
Packit eace71
			      sizeof(iface->dhcp_vendor_id_state));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_vendor_id",
Packit eace71
			      iface->dhcp_vendor_id,
Packit eace71
			      sizeof(iface->dhcp_vendor_id));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "dhcp_slp_da_info_en",
Packit eace71
			      iface->dhcp_slp_da, sizeof(iface->dhcp_slp_da));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "fragment_disable",
Packit eace71
			      iface->fragmentation,
Packit eace71
			      sizeof(iface->fragmentation));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "grat_arp_en",
Packit eace71
			      iface->gratuitous_arp,
Packit eace71
			      sizeof(iface->gratuitous_arp));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "incoming_forwarding_en",
Packit eace71
			      iface->incoming_forwarding,
Packit eace71
			      sizeof(iface->incoming_forwarding));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "tos_en",
Packit eace71
			      iface->tos_state, sizeof(iface->tos_state));
Packit eace71
Packit eace71
		if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				    "tos", &iface->tos))
Packit eace71
			iface->tos = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				    "ttl", &iface->ttl))
Packit eace71
			iface->ttl = 0;
Packit eace71
	} else {
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "ipaddr_autocfg",
Packit eace71
			      iface->ipv6_autocfg, sizeof(iface->ipv6_autocfg));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "link_local_addr", iface->ipv6_linklocal,
Packit eace71
			      sizeof(iface->ipv6_linklocal));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "link_local_autocfg", iface->linklocal_autocfg,
Packit eace71
			      sizeof(iface->linklocal_autocfg));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_addr",
Packit eace71
			      iface->ipv6_router,
Packit eace71
			      sizeof(iface->ipv6_router));
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_state",
Packit eace71
			      iface->router_autocfg,
Packit eace71
			      sizeof(iface->router_autocfg));
Packit eace71
Packit eace71
		if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				    "dup_addr_detect_cnt",
Packit eace71
				    &iface->dup_addr_detect_cnt))
Packit eace71
			iface->dup_addr_detect_cnt = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "flow_label", &iface->flow_label))
Packit eace71
			iface->flow_label = 0;
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			      "grat_neighbor_adv_en",
Packit eace71
			      iface->gratuitous_neighbor_adv,
Packit eace71
			      sizeof(iface->gratuitous_neighbor_adv));
Packit eace71
Packit eace71
		if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				    "hop_limit", &iface->hop_limit))
Packit eace71
			iface->hop_limit = 0;
Packit eace71
Packit eace71
		sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "mld_en",
Packit eace71
			      iface->mld, sizeof(iface->mld));
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "nd_reachable_tmo",
Packit eace71
				   &iface->nd_reachable_tmo))
Packit eace71
			iface->nd_reachable_tmo = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "nd_rexmit_time", &iface->nd_rexmit_time))
Packit eace71
			iface->nd_rexmit_time = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "nd_stale_tmo", &iface->nd_stale_tmo))
Packit eace71
			iface->nd_stale_tmo = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "router_adv_link_mtu",
Packit eace71
				   &iface->router_adv_link_mtu))
Packit eace71
			iface->router_adv_link_mtu = 0;
Packit eace71
Packit eace71
		if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
				   "traffic_class", &iface->traffic_class))
Packit eace71
			iface->traffic_class = 0;
Packit eace71
	}
Packit eace71
Packit eace71
	if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "port",
Packit eace71
			     &iface->port))
Packit eace71
		iface->port = 0;
Packit eace71
	if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "mtu",
Packit eace71
			     &iface->mtu))
Packit eace71
		iface->mtu = 0;
Packit eace71
	if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_id",
Packit eace71
			     &iface->vlan_id))
Packit eace71
		iface->vlan_id = UINT16_MAX;
Packit eace71
Packit eace71
	if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_priority",
Packit eace71
			    &iface->vlan_priority))
Packit eace71
		iface->vlan_priority = UINT8_MAX;
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_enabled",
Packit eace71
		      iface->vlan_state, sizeof(iface->vlan_state));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "enabled",
Packit eace71
		      iface->state, sizeof(iface->state));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "delayed_ack_en",
Packit eace71
		      iface->delayed_ack, sizeof(iface->delayed_ack));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_nagle_disable",
Packit eace71
		      iface->nagle, sizeof(iface->nagle));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf_disable",
Packit eace71
		      iface->tcp_wsf_state, sizeof(iface->tcp_wsf_state));
Packit eace71
Packit eace71
	if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf",
Packit eace71
			    &iface->tcp_wsf))
Packit eace71
		iface->tcp_wsf = 0;
Packit eace71
Packit eace71
	if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			    "tcp_timer_scale", &iface->tcp_timer_scale))
Packit eace71
		iface->tcp_timer_scale = 0;
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_timestamp_en",
Packit eace71
		      iface->tcp_timestamp, sizeof(iface->tcp_timestamp));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "redirect_en",
Packit eace71
		      iface->redirect, sizeof(iface->redirect));
Packit eace71
Packit eace71
	if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			     "def_taskmgmt_tmo", &iface->def_task_mgmt_tmo))
Packit eace71
		iface->def_task_mgmt_tmo = 0;
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "header_digest",
Packit eace71
		      iface->header_digest, sizeof(iface->header_digest));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_digest",
Packit eace71
		      iface->data_digest, sizeof(iface->data_digest));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "immediate_data",
Packit eace71
		      iface->immediate_data, sizeof(iface->immediate_data));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "initial_r2t",
Packit eace71
		      iface->initial_r2t, sizeof(iface->initial_r2t));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_seq_in_order",
Packit eace71
		      iface->data_seq_inorder, sizeof(iface->data_seq_inorder));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_pdu_in_order",
Packit eace71
		      iface->data_pdu_inorder, sizeof(iface->data_pdu_inorder));
Packit eace71
Packit eace71
	if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "erl",
Packit eace71
			    &iface->erl))
Packit eace71
		iface->erl = 0;
Packit eace71
Packit eace71
	if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			   "max_recv_dlength", &iface->max_recv_dlength))
Packit eace71
		iface->max_recv_dlength = 0;
Packit eace71
Packit eace71
	if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			   "first_burst_len", &iface->first_burst_len))
Packit eace71
		iface->first_burst_len = 0;
Packit eace71
Packit eace71
	if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			     "max_outstanding_r2t", &iface->max_out_r2t))
Packit eace71
		iface->max_out_r2t = 0;
Packit eace71
Packit eace71
	if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
			   "max_burst_len", &iface->max_burst_len))
Packit eace71
		iface->max_burst_len = 0;
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "chap_auth",
Packit eace71
		      iface->chap_auth, sizeof(iface->chap_auth));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "bidi_chap",
Packit eace71
		      iface->bidi_chap, sizeof(iface->bidi_chap));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "strict_login_comp_en",
Packit eace71
		      iface->strict_login_comp,
Packit eace71
		      sizeof(iface->strict_login_comp));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
Packit eace71
		      "discovery_auth_optional",
Packit eace71
		      iface->discovery_auth, sizeof(iface->discovery_auth));
Packit eace71
Packit eace71
	sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "discovery_logout",
Packit eace71
		      iface->discovery_logout, sizeof(iface->discovery_logout));
Packit eace71
Packit eace71
	if (sscanf(iface_kern_id, "ipv%d-iface-%u-%u", &iface_type,
Packit eace71
		   &tmp_host_no, &iface_num) == 3)
Packit eace71
		iface->iface_num = iface_num;
Packit eace71
Packit eace71
done:
Packit eace71
	if (ret)
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	else
Packit eace71
		return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo)
Packit eace71
{
Packit eace71
	return iscsi_sysfs_read_iface(&hinfo->iface, hinfo->host_no, NULL,
Packit eace71
				      NULL);
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_for_each_host(void *data, int *nr_found,
Packit eace71
			      iscsi_sysfs_host_op_fn *fn)
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int rc = 0, i, n;
Packit eace71
	struct host_info *info;
Packit eace71
Packit eace71
	info = malloc(sizeof(*info));
Packit eace71
	if (!info)
Packit eace71
		return ISCSI_ERR_NOMEM;
Packit eace71
Packit eace71
	n = scandir(ISCSI_HOST_DIR, &namelist, trans_filter,
Packit eace71
		    alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		goto free_info;
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		memset(info, 0, sizeof(*info));
Packit eace71
		if (sscanf(namelist[i]->d_name, "host%u", &info->host_no) !=
Packit eace71
			   1) {
Packit eace71
			log_error("Invalid iscsi host dir: %s",
Packit eace71
				  namelist[i]->d_name);
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		iscsi_sysfs_get_hostinfo_by_host_no(info);
Packit eace71
		rc = fn(data, info);
Packit eace71
		if (rc != 0)
Packit eace71
			break;
Packit eace71
		(*nr_found)++;
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
Packit eace71
free_info:
Packit eace71
	free(info);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
Packit eace71
				       int *nr_found,
Packit eace71
				       iscsi_sysfs_iface_op_fn *fn)
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int rc = 0, i, n;
Packit eace71
	struct iface_rec iface;
Packit eace71
        char devpath[PATH_SIZE];
Packit eace71
        char sysfs_dev_iscsi_iface_path[PATH_SIZE];
Packit eace71
        char id[NAME_SIZE];
Packit eace71
Packit eace71
        snprintf(id, sizeof(id), "host%u", host_no);
Packit eace71
        if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
                                               SCSI_SUBSYS, id)) {
Packit eace71
                log_error("Could not look up host's ifaces via scsi bus.");
Packit eace71
                return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
        }
Packit eace71
Packit eace71
	sprintf(sysfs_dev_iscsi_iface_path, "/sys");
Packit eace71
	strlcat(sysfs_dev_iscsi_iface_path, devpath, sizeof(sysfs_dev_iscsi_iface_path));
Packit eace71
	strlcat(sysfs_dev_iscsi_iface_path, "/iscsi_iface", sizeof(sysfs_dev_iscsi_iface_path));
Packit eace71
Packit eace71
	n = scandir(sysfs_dev_iscsi_iface_path, &namelist, trans_filter, alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		/* older kernels or some drivers will not have ifaces */
Packit eace71
		return 0;
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		memset(&iface, 0, sizeof(iface));
Packit eace71
Packit eace71
		iscsi_sysfs_read_iface(&iface, host_no, NULL,
Packit eace71
				       namelist[i]->d_name);
Packit eace71
		rc = fn(data, &iface);
Packit eace71
		if (rc != 0)
Packit eace71
			break;
Packit eace71
		(*nr_found)++;
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
/**
Packit eace71
 * sysfs_session_has_leadconn - checks if session has lead conn in kernel
Packit eace71
 * @sid: session id
Packit eace71
 *
Packit eace71
 * return 1 if session has lead conn and 0 if not.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_session_has_leadconn(uint32_t sid)
Packit eace71
{
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "connection%u:0", sid);
Packit eace71
	return sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
						 ISCSI_CONN_SUBSYS, id);
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * iscsi_sysfs_get_sid_from_path - parse a string for the sid
Packit eace71
 * @session: session path
Packit eace71
 *
Packit eace71
 * Given sysfs_device is a directory name of the form:
Packit eace71
 *
Packit eace71
 * /sys/devices/platform/hostH/sessionS/targetH:B:I/H:B:I:L
Packit eace71
 * /sys/devices/platform/hostH/sessionS/targetH:B:I
Packit eace71
 * /sys/devices/platform/hostH/sessionS
Packit eace71
 *
Packit eace71
 * return the sid S. If just the sid is passed in it will be converted
Packit eace71
 * to an int.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_get_sid_from_path(char *session)
Packit eace71
{
Packit eace71
	struct sysfs_device *dev_parent, *dev;
Packit eace71
	struct stat statb;
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char *end;
Packit eace71
	int sid;
Packit eace71
Packit eace71
	sid = strtol(session, &end, 10);
Packit eace71
	if (sid > 0 && *session != '\0' && *end == '\0')
Packit eace71
		return sid;
Packit eace71
Packit eace71
	if (lstat(session, &statb)) {
Packit eace71
		log_error("%s is an invalid session ID or path", session);
Packit eace71
		exit(1);
Packit eace71
	}
Packit eace71
Packit eace71
	if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) {
Packit eace71
		log_error("%s is not a directory", session);
Packit eace71
		exit(1);
Packit eace71
	}
Packit eace71
Packit eace71
	if (!strncmp(session, "/sys", 4))
Packit eace71
		strlcpy(devpath, session + 4, sizeof(devpath));
Packit eace71
	else
Packit eace71
		strlcpy(devpath, session, sizeof(devpath));
Packit eace71
Packit eace71
	dev = sysfs_device_get(devpath);
Packit eace71
	if (!dev) {
Packit eace71
		log_error("Could not get dev for %s. Possible sysfs "
Packit eace71
			  "incompatibility.", devpath);
Packit eace71
		return -1;
Packit eace71
	}
Packit eace71
Packit eace71
	if (!strncmp(dev->kernel, "session", 7))
Packit eace71
		return atoi(dev->kernel_number);
Packit eace71
Packit eace71
	dev_parent = sysfs_device_get_parent(dev);
Packit eace71
	while (dev_parent != NULL) {
Packit eace71
		if (strncmp(dev_parent->kernel, "session", 7) == 0)
Packit eace71
			return atoi(dev_parent->kernel_number);
Packit eace71
		dev_parent = sysfs_device_get_parent(dev_parent);
Packit eace71
	}
Packit eace71
Packit eace71
	log_error("Unable to find sid in path %s", session);
Packit eace71
	return -1;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info, char *session)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	int ret, pers_failed = 0;
Packit eace71
	uint32_t host_no;
Packit eace71
Packit eace71
	if (sscanf(session, "session%d", &info->sid) != 1) {
Packit eace71
		log_error("invalid session '%s'", session);
Packit eace71
		return ISCSI_ERR_INVAL;
Packit eace71
	}
Packit eace71
Packit eace71
	ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "targetname",
Packit eace71
			    info->targetname, sizeof(info->targetname));
Packit eace71
	if (ret) {
Packit eace71
		log_error("could not read session targetname: %d", ret);
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	}
Packit eace71
Packit eace71
	ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "username",
Packit eace71
				(info->chap).username,
Packit eace71
				sizeof((info->chap).username));
Packit eace71
	if (ret)
Packit eace71
		log_debug(5, "could not read username: %d", ret);
Packit eace71
Packit eace71
	ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "password",
Packit eace71
				(info->chap).password,
Packit eace71
				sizeof((info->chap).password));
Packit eace71
	if (ret)
Packit eace71
		log_debug(5, "could not read password: %d", ret);
Packit eace71
Packit eace71
	ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "username_in",
Packit eace71
				(info->chap).username_in,
Packit eace71
				sizeof((info->chap).username_in));
Packit eace71
	if (ret)
Packit eace71
		log_debug(5, "could not read username in: %d", ret);
Packit eace71
Packit eace71
	ret = sysfs_get_str(session, ISCSI_SESSION_SUBSYS, "password_in",
Packit eace71
				(info->chap).password_in,
Packit eace71
				sizeof((info->chap).password_in));
Packit eace71
	if (ret)
Packit eace71
		log_debug(5, "could not read password in: %d", ret);
Packit eace71
Packit eace71
	ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "recovery_tmo",
Packit eace71
				&((info->tmo).recovery_tmo));
Packit eace71
	if (ret)
Packit eace71
		(info->tmo).recovery_tmo = -1;
Packit eace71
Packit eace71
	ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "lu_reset_tmo",
Packit eace71
				&((info->tmo).lu_reset_tmo));
Packit eace71
	if (ret)
Packit eace71
		(info->tmo).lu_reset_tmo = -1;
Packit eace71
Packit eace71
	ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "tgt_reset_tmo",
Packit eace71
				&((info->tmo).tgt_reset_tmo));
Packit eace71
	if (ret)
Packit eace71
		(info->tmo).lu_reset_tmo = -1;
Packit eace71
Packit eace71
	sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "abort_tmo",
Packit eace71
				&((info->tmo).abort_tmo));
Packit eace71
	if (ret)
Packit eace71
		(info->tmo).abort_tmo = -1;
Packit eace71
Packit eace71
	ret = sysfs_get_int(session, ISCSI_SESSION_SUBSYS, "tpgt",
Packit eace71
			    &info->tpgt);
Packit eace71
	if (ret) {
Packit eace71
		log_error("could not read session tpgt: %d", ret);
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	}
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_CONN_ID, info->sid);
Packit eace71
	/* some HW drivers do not export addr and port */
Packit eace71
	memset(info->persistent_address, 0, NI_MAXHOST);
Packit eace71
	ret = sysfs_get_str(id, ISCSI_CONN_SUBSYS, "persistent_address",
Packit eace71
			    info->persistent_address,
Packit eace71
			    sizeof(info->persistent_address));
Packit eace71
	if (ret) {
Packit eace71
		pers_failed = 1;
Packit eace71
		/* older qlogic does not support this */
Packit eace71
		log_debug(5, "could not read pers conn addr: %d", ret);
Packit eace71
	}
Packit eace71
Packit eace71
	memset(info->address, 0, NI_MAXHOST);
Packit eace71
	ret = sysfs_get_str(id, ISCSI_CONN_SUBSYS, "address",
Packit eace71
			    info->address, sizeof(info->address));
Packit eace71
	if (ret) {
Packit eace71
		log_debug(5, "could not read curr addr: %d", ret);
Packit eace71
		/* iser did not export this */
Packit eace71
		if (!pers_failed)
Packit eace71
			strcpy(info->address, info->persistent_address);
Packit eace71
	} else if (pers_failed)
Packit eace71
		/*
Packit eace71
		 * for qla if we could not get the persistent addr
Packit eace71
		 * we will use the current for both addrs
Packit eace71
		 */
Packit eace71
		strcpy(info->persistent_address, info->address);
Packit eace71
	pers_failed = 0;
Packit eace71
Packit eace71
	info->persistent_port = -1;
Packit eace71
	ret = sysfs_get_int(id, ISCSI_CONN_SUBSYS, "persistent_port",
Packit eace71
			    &info->persistent_port);
Packit eace71
	if (ret) {
Packit eace71
		pers_failed = 1;
Packit eace71
		log_debug(5, "Could not read pers conn port %d", ret);
Packit eace71
	}
Packit eace71
Packit eace71
	info->port = -1;
Packit eace71
	ret = sysfs_get_int(id, ISCSI_CONN_SUBSYS, "port", &info->port);
Packit eace71
	if (ret) {
Packit eace71
		/* iser did not export this */
Packit eace71
		if (!pers_failed)
Packit eace71
			info->port = info->persistent_port;
Packit eace71
		log_debug(5, "Could not read curr conn port %d", ret);
Packit eace71
	} else if (pers_failed)
Packit eace71
		/*
Packit eace71
		 * for qla if we could not get the persistent addr
Packit eace71
		 * we will use the current for both addrs
Packit eace71
		 */
Packit eace71
		info->persistent_port = info->port;
Packit eace71
Packit eace71
	ret = 0;
Packit eace71
	host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &ret;;
Packit eace71
	if (ret) {
Packit eace71
		log_error("could not get host_no for session%d: %s.",
Packit eace71
			  info->sid, iscsi_err_to_str(ret));
Packit eace71
		return ret;
Packit eace71
	}
Packit eace71
Packit eace71
	iscsi_sysfs_read_iface(&info->iface, host_no, session, NULL);
Packit eace71
Packit eace71
	log_debug(7, "found targetname %s address %s pers address %s port %d "
Packit eace71
		 "pers port %d driver %s iface name %s ipaddress %s "
Packit eace71
		 "netdev %s hwaddress %s iname %s",
Packit eace71
		  info->targetname, info->address ? info->address : "NA",
Packit eace71
		  info->persistent_address ? info->persistent_address : "NA",
Packit eace71
		  info->port, info->persistent_port, info->iface.transport_name,
Packit eace71
		  info->iface.name, info->iface.ipaddress,
Packit eace71
		  info->iface.netdev, info->iface.hwaddress,
Packit eace71
		  info->iface.iname);
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_for_each_session(void *data, int *nr_found,
Packit eace71
				 iscsi_sysfs_session_op_fn *fn,
Packit eace71
				 int in_parallel)
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int rc = 0, n, i, chldrc = 0;
Packit eace71
	struct session_info *info;
Packit eace71
	pid_t pid = 0;
Packit eace71
Packit eace71
	info = calloc(1, sizeof(*info));
Packit eace71
	if (!info)
Packit eace71
		return ISCSI_ERR_NOMEM;
Packit eace71
Packit eace71
	info->iscsid_req_tmo = -1;
Packit eace71
	n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter,
Packit eace71
		    alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		goto free_info;
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		rc = iscsi_sysfs_get_sessioninfo_by_id(info,
Packit eace71
						       namelist[i]->d_name);
Packit eace71
		if (rc) {
Packit eace71
			log_error("could not find session info for %s",
Packit eace71
				   namelist[i]->d_name);
Packit eace71
			/* raced. session was shutdown while looping */
Packit eace71
			rc = 0;
Packit eace71
			continue;
Packit eace71
		}
Packit eace71
Packit eace71
		if (in_parallel) {
Packit eace71
			pid = fork();
Packit eace71
		}
Packit eace71
		if (pid == 0) {
Packit eace71
			rc = fn(data, info);
Packit eace71
			if (in_parallel) {
Packit eace71
				exit(rc);
Packit eace71
			} else {
Packit eace71
				if (rc > 0) {
Packit eace71
					break;
Packit eace71
				} else if (rc == 0) {
Packit eace71
					(*nr_found)++;
Packit eace71
				} else {
Packit eace71
					/* if less than zero it means it was not a match */
Packit eace71
					rc = 0;
Packit eace71
				}
Packit eace71
			}
Packit eace71
		} else if (pid < 0) {
Packit eace71
			log_error("could not fork() for session %s, err %d",
Packit eace71
				   namelist[i]->d_name, errno);
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (in_parallel) {
Packit eace71
		while (1) {
Packit eace71
			if (wait(&chldrc) < 0) {
Packit eace71
				/*
Packit eace71
				 * ECHILD means no more children which is
Packit eace71
				 * expected to happen sooner or later.
Packit eace71
				 */
Packit eace71
				if (errno != ECHILD) {
Packit eace71
					rc = errno;
Packit eace71
				}
Packit eace71
				break;
Packit eace71
			}
Packit eace71
Packit eace71
			if (!WIFEXITED(chldrc)) {
Packit eace71
				/*
Packit eace71
				 * abnormal termination (signal, exception, etc.)
Packit eace71
				 *
Packit eace71
				 * The non-parallel code path returns the first
Packit eace71
				 * error so this keeps the same semantics.
Packit eace71
				 */
Packit eace71
				if (rc == 0)
Packit eace71
					rc = ISCSI_ERR_CHILD_TERMINATED;
Packit eace71
			} else if ((WEXITSTATUS(chldrc) != 0) &&
Packit eace71
			           (WEXITSTATUS(chldrc) != 255)) {
Packit eace71
				/*
Packit eace71
				 * 0 is success
Packit eace71
				 * 255 is a truncated return code from exit(-1)
Packit eace71
				 *     and means no match
Packit eace71
				 * anything else (this case) is an error
Packit eace71
				 */
Packit eace71
				if (rc == 0)
Packit eace71
					rc = WEXITSTATUS(chldrc);
Packit eace71
			} else if (WEXITSTATUS(chldrc) == 0) {
Packit eace71
				/* success */
Packit eace71
				(*nr_found)++;
Packit eace71
			}
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
Packit eace71
free_info:
Packit eace71
	free(info);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * count the number of sessions -- a much-simplified
Packit eace71
 * version of iscsi_sysfs_for_each_session
Packit eace71
 *
Packit eace71
 * TODO: return an array of the session info we find, for use
Packit eace71
 * by iscsi_sysfs_for_each_session(), so it doesn't have to
Packit eace71
 * do it all over again
Packit eace71
 */
Packit eace71
int iscsi_sysfs_count_sessions(void)
Packit eace71
{
Packit eace71
	struct dirent **namelist = NULL;
Packit eace71
	int n, i;
Packit eace71
	struct session_info *info;
Packit eace71
Packit eace71
Packit eace71
	info = calloc(1, sizeof(*info));
Packit eace71
	if (!info)
Packit eace71
		/* no sessions found */
Packit eace71
		return 0;
Packit eace71
	info->iscsid_req_tmo = -1;
Packit eace71
Packit eace71
	n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter, alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		/* no sessions found */
Packit eace71
		goto free_info;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * try to get session info for each session found, but ignore
Packit eace71
	 * errors if any since it may be a race condition
Packit eace71
	 */
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		if (iscsi_sysfs_get_sessioninfo_by_id(info,
Packit eace71
					namelist[i]->d_name) != 0)
Packit eace71
			log_warning("could not find session info for %s",
Packit eace71
					namelist[i]->d_name);
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
Packit eace71
free_info:
Packit eace71
	free(info);
Packit eace71
	return n;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_get_session_state(char *state, int sid)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_SESSION_ID, sid);
Packit eace71
	if (sysfs_get_str(id, ISCSI_SESSION_SUBSYS, "state", state,
Packit eace71
			  SCSI_MAX_STATE_VALUE))
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_get_host_state(char *state, int host_no)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
Packit eace71
	if (sysfs_get_str(id, SCSI_HOST_SUBSYS, "state", state,
Packit eace71
			  SCSI_MAX_STATE_VALUE))
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_get_device_state(char *state, int host_no, int target, int lun)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
Packit eace71
	if (sysfs_get_str(id, SCSI_SUBSYS, "state", state,
Packit eace71
			  SCSI_MAX_STATE_VALUE)) {
Packit eace71
		log_debug(3, "Could not read attr state for %s", id);
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
Packit eace71
{
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char path_full[PATH_SIZE];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	DIR *dirfd;
Packit eace71
	struct dirent *dent;
Packit eace71
	size_t sysfs_len;
Packit eace71
	struct stat statbuf;
Packit eace71
	char *blockdev, *blockdup = NULL;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
Packit eace71
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
					       SCSI_SUBSYS, id)) {
Packit eace71
		log_debug(3, "Could not lookup devpath for %s %s",
Packit eace71
			  SCSI_SUBSYS, id);
Packit eace71
		return NULL;
Packit eace71
	}
Packit eace71
Packit eace71
	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
Packit eace71
	if (sysfs_len >= sizeof(path_full))
Packit eace71
		sysfs_len = sizeof(path_full) - 1;
Packit eace71
	strlcat(path_full, devpath, sizeof(path_full));
Packit eace71
Packit eace71
	dirfd = opendir(path_full);
Packit eace71
	if (!dirfd)
Packit eace71
		return NULL;
Packit eace71
Packit eace71
	while ((dent = readdir(dirfd))) {
Packit eace71
		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
Packit eace71
			continue;
Packit eace71
Packit eace71
		/* not sure what tape looks like */
Packit eace71
		if (strncmp(dent->d_name, "block:", 5))
Packit eace71
			continue;
Packit eace71
Packit eace71
		strlcat(path_full, "/", sizeof(path_full));
Packit eace71
		strlcat(path_full, dent->d_name, sizeof(path_full));
Packit eace71
		/*
Packit eace71
		 * 2.6.25 dropped the symlink and now block is a dir.
Packit eace71
		 */
Packit eace71
		if (lstat(path_full, &statbuf)) {
Packit eace71
			log_error("Could not stat block path %s err %d",
Packit eace71
				  path_full, errno);
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		if (S_ISLNK(statbuf.st_mode)) {
Packit eace71
			blockdev = strchr(dent->d_name, ':');
Packit eace71
			if (!blockdev)
Packit eace71
				break;
Packit eace71
			/* increment past colon */
Packit eace71
			blockdev++;
Packit eace71
			blockdup = strdup(blockdev);
Packit eace71
		} else if (S_ISDIR(statbuf.st_mode)) {
Packit eace71
			DIR *blk_dirfd;
Packit eace71
			struct dirent *blk_dent;
Packit eace71
Packit eace71
			/* it should not be this hard should it? :) */
Packit eace71
			blk_dirfd = opendir(path_full);
Packit eace71
			if (!blk_dirfd) {
Packit eace71
				log_debug(3, "Could not open blk path %s",
Packit eace71
					  path_full);
Packit eace71
				break;
Packit eace71
			}
Packit eace71
Packit eace71
			while ((blk_dent = readdir(blk_dirfd))) {
Packit eace71
				if (!strcmp(blk_dent->d_name, ".") ||
Packit eace71
				    !strcmp(blk_dent->d_name, ".."))
Packit eace71
					continue;
Packit eace71
				blockdup = strdup(blk_dent->d_name);
Packit eace71
				break;
Packit eace71
			}
Packit eace71
			closedir(blk_dirfd);
Packit eace71
		}
Packit eace71
Packit eace71
		break;
Packit eace71
	}
Packit eace71
	closedir(dirfd);
Packit eace71
	return blockdup;
Packit eace71
}
Packit eace71
Packit eace71
static uint32_t get_target_no_from_sid(uint32_t sid, int *err)
Packit eace71
{
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char path_full[PATH_SIZE];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	DIR *dirfd;
Packit eace71
	struct dirent *dent;
Packit eace71
	uint32_t host, bus, target = 0;
Packit eace71
	size_t sysfs_len;
Packit eace71
Packit eace71
	*err = ISCSI_ERR_SESS_NOT_FOUND;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "session%u", sid);
Packit eace71
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
					       ISCSI_SESSION_SUBSYS, id)) {
Packit eace71
		log_debug(3, "Could not lookup devpath for %s %s",
Packit eace71
			  ISCSI_SESSION_SUBSYS, id);
Packit eace71
		return 0;
Packit eace71
	}
Packit eace71
Packit eace71
	/*
Packit eace71
	 * This does not seem safe from future changes, but we currently
Packit eace71
	 * want /devices/platform/hostY/sessionX, but we come from the
Packit eace71
	 * /class/iscsi_session/sessionX/device.
Packit eace71
	 */
Packit eace71
	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
Packit eace71
	if (sysfs_len >= sizeof(path_full))
Packit eace71
		sysfs_len = sizeof(path_full) - 1;
Packit eace71
	strlcat(path_full, devpath, sizeof(path_full));
Packit eace71
	strlcat(path_full, "/device", sizeof(devpath));
Packit eace71
Packit eace71
	dirfd = opendir(path_full);
Packit eace71
	if (!dirfd)
Packit eace71
		return 0;
Packit eace71
Packit eace71
	while ((dent = readdir(dirfd))) {
Packit eace71
		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
Packit eace71
			continue;
Packit eace71
Packit eace71
		if (strncmp(dent->d_name, "target", 6))
Packit eace71
			continue;
Packit eace71
Packit eace71
		if (sscanf(dent->d_name, "target%u:%u:%u",
Packit eace71
			   &host, &bus, &target) != 3)
Packit eace71
			break;
Packit eace71
Packit eace71
		*err = 0;
Packit eace71
		break;
Packit eace71
Packit eace71
	}
Packit eace71
	closedir(dirfd);
Packit eace71
	return target;
Packit eace71
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_is_transport_loaded(char *transport_name)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t;
Packit eace71
Packit eace71
	/* sync up kernel and userspace */
Packit eace71
	read_transports();
Packit eace71
Packit eace71
	/* check if the transport is loaded and matches */
Packit eace71
	list_for_each_entry(t, &transports, list) {
Packit eace71
		if (t->handle && !strncmp(t->name, transport_name,
Packit eace71
					  ISCSI_TRANSPORT_NAME_MAXLEN))
Packit eace71
			return 1;
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t;
Packit eace71
	int retry = 0;
Packit eace71
Packit eace71
retry:
Packit eace71
	/* sync up kernel and userspace */
Packit eace71
	read_transports();
Packit eace71
Packit eace71
	/* check if the transport is loaded and matches */
Packit eace71
	list_for_each_entry(t, &transports, list) {
Packit eace71
		if (t->handle && !strncmp(t->name, transport_name,
Packit eace71
					  ISCSI_TRANSPORT_NAME_MAXLEN))
Packit eace71
			return t;
Packit eace71
	}
Packit eace71
Packit eace71
	if (retry < 1) {
Packit eace71
		retry++;
Packit eace71
		if (!transport_load_kmod(transport_name))
Packit eace71
			goto retry;
Packit eace71
	}
Packit eace71
Packit eace71
	return NULL;
Packit eace71
}
Packit eace71
Packit eace71
/* TODO: replace the following functions with some decent sysfs links */
Packit eace71
struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(uint32_t host_no)
Packit eace71
{
Packit eace71
	char name[ISCSI_TRANSPORT_NAME_MAXLEN];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	int rc;
Packit eace71
Packit eace71
	if (host_no == -1)
Packit eace71
		return NULL;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
Packit eace71
	rc = sysfs_get_str(id, SCSI_HOST_SUBSYS, "proc_name", name,
Packit eace71
			   ISCSI_TRANSPORT_NAME_MAXLEN);
Packit eace71
	if (rc) {
Packit eace71
		log_error("Could not read proc_name for host%u rc %d.",
Packit eace71
			  host_no, rc);
Packit eace71
		return NULL;
Packit eace71
	}
Packit eace71
Packit eace71
	/*
Packit eace71
	 * stupid, stupid. We named the transports tcp or iser, but the
Packit eace71
	 * the modules are named iscsi_tcp and iscsi_iser
Packit eace71
	 */
Packit eace71
	if (strstr(name, "iscsi_"))
Packit eace71
		return iscsi_sysfs_get_transport_by_name(name + 6);
Packit eace71
	else
Packit eace71
		return iscsi_sysfs_get_transport_by_name(name);
Packit eace71
}
Packit eace71
Packit eace71
struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid)
Packit eace71
{
Packit eace71
	uint32_t host_no;
Packit eace71
	int err;
Packit eace71
Packit eace71
	host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err;;
Packit eace71
	if (err)
Packit eace71
		return NULL;
Packit eace71
	return iscsi_sysfs_get_transport_by_hba(host_no);
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * For connection reinstatement we need to send the exp_statsn from
Packit eace71
 * the previous connection
Packit eace71
 *
Packit eace71
 * This is only called when the connection is halted so exp_statsn is safe
Packit eace71
 * to read without racing.
Packit eace71
 */
Packit eace71
int iscsi_sysfs_get_exp_statsn(int sid)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	uint32_t exp_statsn = 0;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
Packit eace71
	if (sysfs_get_uint(id, ISCSI_CONN_SUBSYS, "exp_statsn",
Packit eace71
			   &exp_statsn)) {
Packit eace71
		log_error("Could not read expstatsn for sid %d. "
Packit eace71
			  "Using zero for exp_statsn.", sid);
Packit eace71
		exp_statsn = 0;
Packit eace71
	}
Packit eace71
	return exp_statsn;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_session_supports_nop(int sid)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	uint32_t ping_tmo = 0;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), ISCSI_CONN_ID, sid);
Packit eace71
	if (sysfs_get_uint(id, ISCSI_CONN_SUBSYS, "ping_tmo",
Packit eace71
			   &ping_tmo)) {
Packit eace71
		return 0;
Packit eace71
	}
Packit eace71
	return 1;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid,
Packit eace71
				void (* fn)(void *data, int host_no,
Packit eace71
					    int target, int lun))
Packit eace71
{
Packit eace71
	struct dirent **namelist;
Packit eace71
	int h, b, t, l, i, n, err = 0, target;
Packit eace71
	char devpath[PATH_SIZE];
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	char path_full[3*PATH_SIZE];
Packit eace71
Packit eace71
	target = get_target_no_from_sid(sid, &err;;
Packit eace71
	if (err)
Packit eace71
		return err;
Packit eace71
	snprintf(id, sizeof(id), "session%u", sid);
Packit eace71
	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
Packit eace71
					       ISCSI_SESSION_SUBSYS, id)) {
Packit eace71
		log_debug(3, "Could not lookup devpath for %s %s",
Packit eace71
			  ISCSI_SESSION_SUBSYS, id);
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	}
Packit eace71
Packit eace71
	snprintf(path_full, sizeof(path_full), "%s%s/device/target%d:0:%d",
Packit eace71
		 sysfs_path, devpath, host_no, target);
Packit eace71
Packit eace71
	if (strlen(path_full) > PATH_SIZE) {
Packit eace71
		log_debug(3, "Could not lookup devpath for %s %s (too long)",
Packit eace71
			  ISCSI_SESSION_SUBSYS, id);
Packit eace71
		return ISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
	}
Packit eace71
Packit eace71
	n = scandir(path_full, &namelist, trans_filter,
Packit eace71
		    alphasort);
Packit eace71
	if (n <= 0)
Packit eace71
		return 0;
Packit eace71
Packit eace71
	for (i = 0; i < n; i++) {
Packit eace71
		if (sscanf(namelist[i]->d_name, "%d:%d:%d:%d\n",
Packit eace71
			   &h, &b, &t, &l) != 4)
Packit eace71
			continue;
Packit eace71
		fn(data, h, t, l);
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < n; i++)
Packit eace71
		free(namelist[i]);
Packit eace71
	free(namelist);
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
void iscsi_sysfs_set_queue_depth(void *data, int hostno, int target, int lun)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	char write_buf[20];
Packit eace71
	int err, qdepth = *((int *)data);
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
Packit eace71
	snprintf(write_buf, sizeof(write_buf), "%d", qdepth);
Packit eace71
	log_debug(4, "set queue depth for %s to %s", id, write_buf);
Packit eace71
Packit eace71
	err = sysfs_set_param(id, SCSI_SUBSYS, "queue_depth", write_buf,
Packit eace71
			      strlen(write_buf));
Packit eace71
	if (err && err != EINVAL)
Packit eace71
		log_error("Could not queue depth for LUN %d err %d.", lun, err);
Packit eace71
}
Packit eace71
Packit eace71
void iscsi_sysfs_set_device_online(void *data, int hostno, int target, int lun)
Packit eace71
{
Packit eace71
	char *write_buf = "running\n";
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	int err;
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
Packit eace71
	log_debug(4, "online device %s", id);
Packit eace71
Packit eace71
	err = sysfs_set_param(id, SCSI_SUBSYS, "state", write_buf,
Packit eace71
			      strlen(write_buf));
Packit eace71
	if (err && err != EINVAL)
Packit eace71
		/* we should read the state */
Packit eace71
		log_error("Could not online LUN %d err %d.", lun, err);
Packit eace71
}
Packit eace71
Packit eace71
void iscsi_sysfs_rescan_device(void *data, int hostno, int target, int lun)
Packit eace71
{
Packit eace71
	char *write_buf = "1";
Packit eace71
	char id[NAME_SIZE];
Packit eace71
Packit eace71
	snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
Packit eace71
	log_debug(4, "rescanning device %s", id);
Packit eace71
	sysfs_set_param(id, SCSI_SUBSYS, "rescan", write_buf,
Packit eace71
			strlen(write_buf));
Packit eace71
}
Packit eace71
Packit eace71
pid_t iscsi_sysfs_scan_host(int hostno, int async, int autoscan)
Packit eace71
{
Packit eace71
	char id[NAME_SIZE];
Packit eace71
	char *write_buf = "- - -";
Packit eace71
	pid_t pid = 0;
Packit eace71
Packit eace71
	if (async)
Packit eace71
		pid = fork();
Packit eace71
Packit eace71
	if (pid >= 0 && !autoscan) {
Packit eace71
		if (pid)
Packit eace71
			log_debug(4, "host%d in manual scan mode, skipping scan", hostno);
Packit eace71
	} else if (pid == 0) {
Packit eace71
		/* child */
Packit eace71
		log_debug(4, "scanning host%d", hostno);
Packit eace71
Packit eace71
		snprintf(id, sizeof(id), ISCSI_HOST_ID, hostno);
Packit eace71
		sysfs_set_param(id, SCSI_HOST_SUBSYS, "scan", write_buf,
Packit eace71
				strlen(write_buf));
Packit eace71
		log_debug(4, "scanning host%d completed", hostno);
Packit eace71
	} else if (pid > 0) {
Packit eace71
		log_debug(4, "scanning host%d from pid %d", hostno, pid);
Packit eace71
	} else
Packit eace71
		/*
Packit eace71
		 * Session is fine, so log the error and let the user
Packit eace71
		 * scan by hand
Packit eace71
		  */
Packit eace71
		log_error("Could not start scanning process for host %d "
Packit eace71
			  "err %d. Try scanning through sysfs.", hostno,
Packit eace71
			  errno);
Packit eace71
	return pid;
Packit eace71
}
Packit eace71
Packit eace71
struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session)
Packit eace71
{
Packit eace71
	uint32_t sid;
Packit eace71
Packit eace71
        if (sscanf(sys_session, "session%u", &sid) != 1) {
Packit eace71
                log_error("invalid session '%s'.", sys_session);
Packit eace71
                return NULL;
Packit eace71
        }
Packit eace71
Packit eace71
	return iscsi_sysfs_get_transport_by_sid(sid);
Packit eace71
}
Packit eace71
Packit eace71
char *iscsi_sysfs_get_iscsi_kernel_version(void)
Packit eace71
{
Packit eace71
	return sysfs_attr_get_value("/module/scsi_transport_iscsi", "version");
Packit eace71
}