|
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 |
}
|