|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (C) IBM Corporation. 2007
|
|
Packit |
eace71 |
* Author: Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
|
|
Packit |
eace71 |
* Copyright (C) Red Hat, Inc. All rights reserved. 2008 - 2010
|
|
Packit |
eace71 |
* Copyright (C) Mike Christie 2008 - 2010
|
|
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 by
|
|
Packit |
eace71 |
* 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,
|
|
Packit |
eace71 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
eace71 |
* GNU General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
eace71 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define _XOPEN_SOURCE 500
|
|
Packit |
eace71 |
#define _DEFAULT_SOURCE
|
|
Packit |
eace71 |
#include <ftw.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <fcntl.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 |
|
|
Packit |
eace71 |
#include "sysfs.h"
|
|
Packit |
eace71 |
#include "fw_context.h"
|
|
Packit |
eace71 |
#include "fwparam.h"
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
#include "iscsi_net_util.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define ISCSI_BOOT_MAX 255
|
|
Packit |
eace71 |
#define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
|
|
Packit |
eace71 |
#define IBFT_SUBSYS "ibft"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define ISCSI_LLD_ROOT "/sys/firmware/"
|
|
Packit |
eace71 |
#define ISCSI_LLD_SUBSYS_PREFIX "iscsi_boot"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static char *target_list[ISCSI_BOOT_MAX];
|
|
Packit |
eace71 |
static char *nic_list[ISCSI_BOOT_MAX];
|
|
Packit |
eace71 |
static int nic_cnt;
|
|
Packit |
eace71 |
static int tgt_cnt;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int file_exist(const char *file)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct stat bootpath_stat;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return !stat(file, &bootpath_stat);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Finds the etherrnetX and targetX under the sysfs directory.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static int find_sysfs_dirs(const char *fpath, const struct stat *sb,
|
|
Packit |
eace71 |
int tflag, struct FTW *ftw)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (tflag == FTW_D && (strstr(fpath + ftw->base, "target"))) {
|
|
Packit |
eace71 |
if (tgt_cnt == ISCSI_BOOT_MAX) {
|
|
Packit |
eace71 |
printf("Too many targets found in iSCSI boot data."
|
|
Packit |
eace71 |
"Max number of targets %d\n", ISCSI_BOOT_MAX);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
target_list[tgt_cnt++] = strdup(strstr(fpath, "target"));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (tflag == FTW_D && (strstr(fpath + ftw->base, "ethernet"))) {
|
|
Packit |
eace71 |
if (nic_cnt == ISCSI_BOOT_MAX) {
|
|
Packit |
eace71 |
printf("Too many nics found in iSCSI boot data."
|
|
Packit |
eace71 |
"Max number of nics %d\n", ISCSI_BOOT_MAX);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
nic_list[nic_cnt++] = strdup(strstr(fpath, "ethernet"));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int get_iface_from_device(char *id, struct boot_context *context)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char dev_dir[FILENAMESZ];
|
|
Packit |
eace71 |
int rc = ENODEV;
|
|
Packit |
eace71 |
DIR *dirfd;
|
|
Packit |
eace71 |
struct dirent *dent;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(dev_dir, 0, FILENAMESZ);
|
|
Packit |
eace71 |
snprintf(dev_dir, FILENAMESZ, IBFT_SYSFS_ROOT"/%s/device", id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!file_exist(dev_dir))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
dirfd = opendir(dev_dir);
|
|
Packit |
eace71 |
if (!dirfd)
|
|
Packit |
eace71 |
return errno;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while ((dent = readdir(dirfd))) {
|
|
Packit |
eace71 |
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") ||
|
|
Packit |
eace71 |
strncmp(dent->d_name, "net:", 4))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strncmp(dent->d_name, "net:", 4)) {
|
|
Packit |
eace71 |
if ((strlen(dent->d_name) - 4) >
|
|
Packit |
eace71 |
(sizeof(context->iface) - 1)) {
|
|
Packit |
eace71 |
rc = EINVAL;
|
|
Packit |
eace71 |
printf("Net device %s too big for iface "
|
|
Packit |
eace71 |
"buffer.\n", dent->d_name);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (sscanf(dent->d_name, "net:%s", context->iface) != 1)
|
|
Packit |
eace71 |
rc = EINVAL;
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
printf("Could not read ethernet to net link.\n");
|
|
Packit |
eace71 |
rc = EOPNOTSUPP;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
closedir(dirfd);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc != ENODEV)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* If not found try again with newer kernel networkdev sysfs layout */
|
|
Packit |
eace71 |
strlcat(dev_dir, "/net", FILENAMESZ);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!file_exist(dev_dir))
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
dirfd = opendir(dev_dir);
|
|
Packit |
eace71 |
if (!dirfd)
|
|
Packit |
eace71 |
return errno;
|
|
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 |
/* Take the first "regular" directory entry */
|
|
Packit |
eace71 |
if (strlen(dent->d_name) > (sizeof(context->iface) - 1)) {
|
|
Packit |
eace71 |
rc = EINVAL;
|
|
Packit |
eace71 |
printf("Net device %s too big for iface buffer.\n",
|
|
Packit |
eace71 |
dent->d_name);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strcpy(context->iface, dent->d_name);
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
closedir(dirfd);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Routines to fill in the context values.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static int fill_nic_context(char *subsys, char *id,
|
|
Packit |
eace71 |
struct boot_context *context)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_int(id, subsys, "flags", &context->nic_flags);
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Per spec we would need to check against Bit 0
|
|
Packit |
eace71 |
* (Block Valid Flag), but some firmware only
|
|
Packit |
eace71 |
* sets Bit 1 (Firmware Booting Selected).
|
|
Packit |
eace71 |
* So any setting is deemed okay.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!rc && (context->nic_flags == 0))
|
|
Packit |
eace71 |
rc = ENODEV;
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_str(id, subsys, "mac", context->mac,
|
|
Packit |
eace71 |
sizeof(context->mac));
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Some offload cards like bnx2i use different MACs for the net and
|
|
Packit |
eace71 |
* iscsi functions, so we have to follow the sysfs links.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Other ibft implementations may not be tied to a pci function,
|
|
Packit |
eace71 |
* so there will not be any device/net link, so we drop down to
|
|
Packit |
eace71 |
* the MAC matching.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* And finally, some cards like be2iscsi and qla4xxx do not have
|
|
Packit |
eace71 |
* any linux network subsys representation. These hosts will
|
|
Packit |
eace71 |
* not have the ibft subsys. Instead the subsys is the scsi host
|
|
Packit |
eace71 |
* number.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!strcmp(IBFT_SUBSYS, subsys)) {
|
|
Packit |
eace71 |
rc = get_iface_from_device(id, context);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
rc = net_get_netdev_from_hwaddress(context->mac,
|
|
Packit |
eace71 |
context->iface);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
strlcpy(context->scsi_host_name, subsys,
|
|
Packit |
eace71 |
sizeof(context->scsi_host_name));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&context->boot_nic, 0, sizeof(context->boot_nic));
|
|
Packit |
eace71 |
snprintf(context->boot_nic, sizeof(context->boot_nic), "%s", id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "ip-addr", context->ipaddr,
|
|
Packit |
eace71 |
sizeof(context->ipaddr));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "vlan", context->vlan,
|
|
Packit |
eace71 |
sizeof(context->vlan));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "subnet-mask", context->mask,
|
|
Packit |
eace71 |
sizeof(context->mask));
|
|
Packit |
eace71 |
sysfs_get_int(id, subsys, "prefix-len", &context->prefix);
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "gateway", context->gateway,
|
|
Packit |
eace71 |
sizeof(context->gateway));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "primary-dns", context->primary_dns,
|
|
Packit |
eace71 |
sizeof(context->primary_dns));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "secondary-dns", context->secondary_dns,
|
|
Packit |
eace71 |
sizeof(context->secondary_dns));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "dhcp", context->dhcp,
|
|
Packit |
eace71 |
sizeof(context->dhcp));
|
|
Packit |
eace71 |
sysfs_get_int(id, subsys, "origin", (int *)&context->origin);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void fill_initiator_context(char *subsys, struct boot_context *context)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
sysfs_get_str("initiator", subsys, "initiator-name",
|
|
Packit |
eace71 |
context->initiatorname,
|
|
Packit |
eace71 |
sizeof(context->initiatorname));
|
|
Packit |
eace71 |
sysfs_get_str("initiator", subsys, "isid", context->isid,
|
|
Packit |
eace71 |
sizeof(context->isid));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(context->boot_root, subsys, sizeof(context->boot_root));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
static int fill_tgt_context(char *subsys, char *id,
|
|
Packit |
eace71 |
struct boot_context *context)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_int(id, subsys, "flags", &context->target_flags);
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Per spec we would need to check against Bit 0
|
|
Packit |
eace71 |
* (Block Valid Flag), but some firmware only
|
|
Packit |
eace71 |
* sets Bit 1 (Firmware Booting Selected).
|
|
Packit |
eace71 |
* So any setting is deemed okay.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!rc && (context->target_flags == 0))
|
|
Packit |
eace71 |
rc = ENODEV;
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_str(id, subsys, "target-name", context->targetname,
|
|
Packit |
eace71 |
sizeof(context->targetname));
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_str(id, subsys, "ip-addr", context->target_ipaddr,
|
|
Packit |
eace71 |
sizeof(context->target_ipaddr));
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&context->boot_target, 0, sizeof(context->boot_target));
|
|
Packit |
eace71 |
snprintf(context->boot_target, sizeof(context->boot_target), "%s", id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* We can live without the rest of they do not exist. If we
|
|
Packit |
eace71 |
* failed to get them we will figure it out when we login.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (sysfs_get_int(id, subsys, "port", &context->target_port))
|
|
Packit |
eace71 |
context->target_port = ISCSI_LISTEN_PORT;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "lun", context->lun,
|
|
Packit |
eace71 |
sizeof(context->lun));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "chap-name", context->chap_name,
|
|
Packit |
eace71 |
sizeof(context->chap_name));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "chap-secret", context->chap_password,
|
|
Packit |
eace71 |
sizeof(context->chap_password));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "rev-chap-name", context->chap_name_in,
|
|
Packit |
eace71 |
sizeof(context->chap_name_in));
|
|
Packit |
eace71 |
sysfs_get_str(id, subsys, "rev-chap-name-secret",
|
|
Packit |
eace71 |
context->chap_password_in,
|
|
Packit |
eace71 |
sizeof(context->chap_password_in));
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int find_boot_flag(char *subsys, char *list[], ssize_t size,
|
|
Packit |
eace71 |
int *boot_idx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = ENODEV;
|
|
Packit |
eace71 |
int i, flag = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < size; i++, flag = -1) {
|
|
Packit |
eace71 |
rc = sysfs_get_int(list[i], subsys, "flags", &flag;;
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (flag & IBFT_SYSFS_FLAG_FW_SEL_BOOT) {
|
|
Packit |
eace71 |
*boot_idx = i;
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
rc = ENODEV;
|
|
Packit |
eace71 |
flag = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void deallocate_lists(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < nic_cnt; i++)
|
|
Packit |
eace71 |
free(nic_list[i]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_cnt = 0;
|
|
Packit |
eace71 |
for (i = 0; i < tgt_cnt; i++)
|
|
Packit |
eace71 |
free(target_list[i]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
tgt_cnt = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int get_boot_info(struct boot_context *context, char *rootdir,
|
|
Packit |
eace71 |
char *subsys)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char initiator_dir[FILENAMESZ];
|
|
Packit |
eace71 |
int rc = ENODEV;
|
|
Packit |
eace71 |
int nic_idx = -1, tgt_idx = -1;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&initiator_dir, 0 , FILENAMESZ);
|
|
Packit |
eace71 |
snprintf(initiator_dir, FILENAMESZ, "%sinitiator", rootdir);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_cnt = 0;
|
|
Packit |
eace71 |
tgt_cnt = 0;
|
|
Packit |
eace71 |
if (file_exist(initiator_dir)) {
|
|
Packit |
eace71 |
/* Find the targets and the ethernets */
|
|
Packit |
eace71 |
rc = nftw(rootdir, find_sysfs_dirs, 20, 1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Find wihch target and which ethernet have
|
|
Packit |
eace71 |
the boot flag set. */
|
|
Packit |
eace71 |
rc = find_boot_flag(subsys, nic_list, nic_cnt, &nic_idx);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto free;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = find_boot_flag(subsys, target_list, tgt_cnt, &tgt_idx);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto free;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Fill in the context values */
|
|
Packit |
eace71 |
rc = fill_nic_context(subsys, nic_list[nic_idx], context);
|
|
Packit |
eace71 |
rc |= fill_tgt_context(subsys, target_list[tgt_idx], context);
|
|
Packit |
eace71 |
fill_initiator_context(subsys, context);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free:
|
|
Packit |
eace71 |
deallocate_lists();
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int fwparam_sysfs_boot_info(struct boot_context *context)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct dirent *dent;
|
|
Packit |
eace71 |
DIR *dirfd;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!get_boot_info(context, IBFT_SYSFS_ROOT, IBFT_SUBSYS))
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* We could have multiple iscsi llds and each lld could have
|
|
Packit |
eace71 |
* multiple targets/ethernet ports
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
dirfd = opendir(ISCSI_LLD_ROOT);
|
|
Packit |
eace71 |
if (!dirfd)
|
|
Packit |
eace71 |
return ISCSI_ERR_SYSFS_LOOKUP;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while ((dent = readdir(dirfd))) {
|
|
Packit |
eace71 |
char lld_root[FILENAMESZ];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&lld_root, 0 , FILENAMESZ);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp(dent->d_name, ISCSI_LLD_SUBSYS_PREFIX, 10))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
snprintf(lld_root, FILENAMESZ, ISCSI_LLD_ROOT"%s/",
|
|
Packit |
eace71 |
dent->d_name);
|
|
Packit |
eace71 |
if (!get_boot_info(context, lld_root, dent->d_name))
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
closedir(dirfd);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int get_targets(struct list_head *list, char *rootdir, char *subsys)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct boot_context *context;
|
|
Packit |
eace71 |
int rc = 0, i, nic_idx, nic;
|
|
Packit |
eace71 |
char initiator_dir[FILENAMESZ];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&initiator_dir, 0 , FILENAMESZ);
|
|
Packit |
eace71 |
snprintf(initiator_dir, FILENAMESZ, "%sinitiator", rootdir);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!file_exist(initiator_dir))
|
|
Packit |
eace71 |
return ENODEV;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
nic_cnt = 0;
|
|
Packit |
eace71 |
tgt_cnt = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Find the targets and the ethernets */
|
|
Packit |
eace71 |
nftw(rootdir, find_sysfs_dirs, 20, 1);
|
|
Packit |
eace71 |
for (i = 0; i < tgt_cnt; i++) {
|
|
Packit |
eace71 |
context = calloc(1, sizeof(*context));
|
|
Packit |
eace71 |
if (!context) {
|
|
Packit |
eace71 |
rc = ENOMEM;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = fill_tgt_context(subsys, target_list[i], context);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto cleanup;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_int(target_list[i], subsys, "nic-assoc",
|
|
Packit |
eace71 |
&nic_idx);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto cleanup;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (nic = 0; nic < nic_cnt; nic++) {
|
|
Packit |
eace71 |
int id;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = sysfs_get_int(nic_list[nic], subsys, "index",
|
|
Packit |
eace71 |
&id;;
|
|
Packit |
eace71 |
if (!rc && (id == nic_idx))
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (nic == nic_cnt) {
|
|
Packit |
eace71 |
printf("Invalid nic-assoc of %d. Max id %d.\n",
|
|
Packit |
eace71 |
nic_idx, nic_cnt);
|
|
Packit |
eace71 |
goto cleanup;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = fill_nic_context(subsys, nic_list[nic], context);
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
goto cleanup;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fill_initiator_context(subsys, context);
|
|
Packit |
eace71 |
list_add_tail(&context->list, list);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
cleanup:
|
|
Packit |
eace71 |
free(context);
|
|
Packit |
eace71 |
context = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
if (context)
|
|
Packit |
eace71 |
free(context);
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If there are some valid targets return them. Most likely,
|
|
Packit |
eace71 |
* the driver/ibft-implementation reported partial info
|
|
Packit |
eace71 |
* for targets/initiators that were not used for boot.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!list_empty(list))
|
|
Packit |
eace71 |
rc = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
deallocate_lists();
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int fwparam_sysfs_get_targets(struct list_head *list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct dirent *dent;
|
|
Packit |
eace71 |
DIR *dirfd;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* ibft only has one instance */
|
|
Packit |
eace71 |
get_targets(list, IBFT_SYSFS_ROOT, IBFT_SUBSYS);
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* We could have multiple iscsi llds and each lld could have
|
|
Packit |
eace71 |
* multiple targets/ethernet ports
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
dirfd = opendir(ISCSI_LLD_ROOT);
|
|
Packit |
eace71 |
if (!dirfd) {
|
|
Packit |
eace71 |
rc = ISCSI_ERR_SYSFS_LOOKUP;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
while ((dent = readdir(dirfd))) {
|
|
Packit |
eace71 |
char lld_root[FILENAMESZ];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&lld_root, 0 , FILENAMESZ);
|
|
Packit |
eace71 |
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp(dent->d_name, ISCSI_LLD_SUBSYS_PREFIX, 10))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
snprintf(lld_root, FILENAMESZ, ISCSI_LLD_ROOT"%s/",
|
|
Packit |
eace71 |
dent->d_name);
|
|
Packit |
eace71 |
get_targets(list, lld_root, dent->d_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
closedir(dirfd);
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
if (!rc && list_empty(list))
|
|
Packit |
eace71 |
rc = ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
if (rc)
|
|
Packit |
eace71 |
fw_free_targets(list);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|