On 08/02/2010 11:54 AM, James Bottomley wrote:
missing linux-scsi added to cc list.
On Tue, 2010-08-03 at 02:47 +1000, Stephen Rothwell wrote:
Hi all,
On Tue, 3 Aug 2010 02:44:45 +1000 Stephen Rothwell<sfr@xxxxxxxxxxxxxxxx> wrote:
After merging the final tree, today's linux-next build (powerpc allmodconfig)
failed like this:
ERROR: ".iscsi_boot_destroy_kset" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined!
ERROR: ".iscsi_boot_create_host_kset" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined!
ERROR: ".iscsi_boot_create_target" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined!
ERROR: ".iscsi_boot_create_initiator" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined!
ERROR: ".iscsi_boot_create_ethernet" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined!
Caused by commit a33e2a708b2e83ee6111e45c8d3d49a112c3c887 ("[SCSI]
be2iscsi: Add support for iscsi boot"). For some reason, commit
ed94aa526655d915076dcdbbf4fc962b2a67fcb5 ("[SCSI] be2iscsi: select
ISCSI_BOOT_SYSFS") was not sufficient to make sure that
CONFIG_ISCSI_BOOT_SYSFS is defined for this build.
It turns out that drivers/firmware/Kconfig is only included on x86, ia64
and blackfin.
OK, we need to turn this around then and make be2iscsi only use iscsi
boot if it's enabled ... that's going to be some fun #ifdefing in the
driver.
I think my mistake was to put iscsi_boot_sysfs in drivers/firmware. The
interface is generic and should be used on any arch and with anything
(ibft or iscsi driver) that wants to export iscsi boot info. The
attached patch moves iscsi_boot_sysfs to drivers/scsi. It was made over
linux-next. I have only compile tested it.
From 53bca457077618b2691e94fb1d1221065bd0ffdd Mon Sep 17 00:00:00 2001
From: Mike Christie <mchristi@xxxxxxxxxx>
Date: Mon, 2 Aug 2010 12:30:49 -0500
Subject: [PATCH] iscsi boot: mv iscsi_boot_sysfs to drivers/scsi
iscsi_boot_sysfs does not depend on firmware. Any iscsi driver
can use it. This patch moves iscsi_boot_sysfs to the scsi
dir, so that it can be used on any arch with any driver.
Signed-off-by: Mike Christie <mchristi@xxxxxxxxxx>
---
drivers/firmware/Kconfig | 8 -
drivers/firmware/Makefile | 1 -
drivers/firmware/iscsi_boot_sysfs.c | 481 -----------------------------------
drivers/scsi/Kconfig | 8 +
drivers/scsi/Makefile | 1 +
drivers/scsi/iscsi_boot_sysfs.c | 481 +++++++++++++++++++++++++++++++++++
6 files changed, 490 insertions(+), 490 deletions(-)
delete mode 100644 drivers/firmware/iscsi_boot_sysfs.c
create mode 100644 drivers/scsi/iscsi_boot_sysfs.c
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index a6c670b..f7cff38 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -122,14 +122,6 @@ config ISCSI_IBFT_FIND
is necessary for iSCSI Boot Firmware Table Attributes module to work
properly.
-config ISCSI_BOOT_SYSFS
- tristate "iSCSI Boot Sysfs Interface"
- default n
- help
- This option enables support for exposing iSCSI boot information
- via sysfs to userspace. If you wish to export this information,
- say Y. Otherwise, say N.
-
config ISCSI_IBFT
tristate "iSCSI Boot Firmware Table Attributes module"
select ISCSI_BOOT_SYSFS
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 5fe7e16..1c3c173 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,5 +10,4 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DMIID) += dmi-id.o
obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
-obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c
deleted file mode 100644
index df6bff7..0000000
--- a/drivers/firmware/iscsi_boot_sysfs.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Export the iSCSI boot info to userland via sysfs.
- *
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2010 Mike Christie
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/capability.h>
-#include <linux/iscsi_boot_sysfs.h>
-
-
-MODULE_AUTHOR("Mike Christie <michaelc@xxxxxxxxxxx>");
-MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
-MODULE_LICENSE("GPL");
-/*
- * The kobject and attribute structures.
- */
-struct iscsi_boot_attr {
- struct attribute attr;
- int type;
- ssize_t (*show) (void *data, int type, char *buf);
-};
-
-/*
- * The routine called for all sysfs attributes.
- */
-static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct iscsi_boot_kobj *boot_kobj =
- container_of(kobj, struct iscsi_boot_kobj, kobj);
- struct iscsi_boot_attr *boot_attr =
- container_of(attr, struct iscsi_boot_attr, attr);
- ssize_t ret = -EIO;
- char *str = buf;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (boot_kobj->show)
- ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
- return ret;
-}
-
-static const struct sysfs_ops iscsi_boot_attr_ops = {
- .show = iscsi_boot_show_attribute,
-};
-
-static void iscsi_boot_kobj_release(struct kobject *kobj)
-{
- struct iscsi_boot_kobj *boot_kobj =
- container_of(kobj, struct iscsi_boot_kobj, kobj);
-
- kfree(boot_kobj->data);
- kfree(boot_kobj);
-}
-
-static struct kobj_type iscsi_boot_ktype = {
- .release = iscsi_boot_kobj_release,
- .sysfs_ops = &iscsi_boot_attr_ops,
-};
-
-#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \
-static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \
- .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \
- .type = attr_type, \
-}
-
-/* Target attrs */
-iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
-iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
-iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
-iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
-iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
-iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
-iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
-iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
-iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
-iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
-iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
- ISCSI_BOOT_TGT_REV_CHAP_NAME);
-iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
- ISCSI_BOOT_TGT_REV_CHAP_SECRET);
-
-static struct attribute *target_attrs[] = {
- &iscsi_boot_attr_tgt_index.attr,
- &iscsi_boot_attr_tgt_flags.attr,
- &iscsi_boot_attr_tgt_ip.attr,
- &iscsi_boot_attr_tgt_port.attr,
- &iscsi_boot_attr_tgt_lun.attr,
- &iscsi_boot_attr_tgt_chap.attr,
- &iscsi_boot_attr_tgt_nic.attr,
- &iscsi_boot_attr_tgt_name.attr,
- &iscsi_boot_attr_tgt_chap_name.attr,
- &iscsi_boot_attr_tgt_chap_secret.attr,
- &iscsi_boot_attr_tgt_chap_rev_name.attr,
- &iscsi_boot_attr_tgt_chap_rev_secret.attr,
- NULL
-};
-
-static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
- struct attribute *attr, int i)
-{
- struct iscsi_boot_kobj *boot_kobj =
- container_of(kobj, struct iscsi_boot_kobj, kobj);
-
- if (attr == &iscsi_boot_attr_tgt_index.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_INDEX);
- else if (attr == &iscsi_boot_attr_tgt_flags.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_FLAGS);
- else if (attr == &iscsi_boot_attr_tgt_ip.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_IP_ADDR);
- else if (attr == &iscsi_boot_attr_tgt_port.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_PORT);
- else if (attr == &iscsi_boot_attr_tgt_lun.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_LUN);
- else if (attr == &iscsi_boot_attr_tgt_chap.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_CHAP_TYPE);
- else if (attr == &iscsi_boot_attr_tgt_nic.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_NIC_ASSOC);
- else if (attr == &iscsi_boot_attr_tgt_name.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_NAME);
- else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_CHAP_NAME);
- else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_CHAP_SECRET);
- else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_REV_CHAP_NAME);
- else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_TGT_REV_CHAP_SECRET);
- return 0;
-}
-
-static struct attribute_group iscsi_boot_target_attr_group = {
- .attrs = target_attrs,
- .is_visible = iscsi_boot_tgt_attr_is_visible,
-};
-
-/* Ethernet attrs */
-iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
-iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
-iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
-iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
-iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
-iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
-iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
-iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
- ISCSI_BOOT_ETH_SECONDARY_DNS);
-iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
-iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
-iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
-iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
-
-static struct attribute *ethernet_attrs[] = {
- &iscsi_boot_attr_eth_index.attr,
- &iscsi_boot_attr_eth_flags.attr,
- &iscsi_boot_attr_eth_ip.attr,
- &iscsi_boot_attr_eth_subnet.attr,
- &iscsi_boot_attr_eth_origin.attr,
- &iscsi_boot_attr_eth_gateway.attr,
- &iscsi_boot_attr_eth_primary_dns.attr,
- &iscsi_boot_attr_eth_secondary_dns.attr,
- &iscsi_boot_attr_eth_dhcp.attr,
- &iscsi_boot_attr_eth_vlan.attr,
- &iscsi_boot_attr_eth_mac.attr,
- &iscsi_boot_attr_eth_hostname.attr,
- NULL
-};
-
-static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
- struct attribute *attr, int i)
-{
- struct iscsi_boot_kobj *boot_kobj =
- container_of(kobj, struct iscsi_boot_kobj, kobj);
-
- if (attr == &iscsi_boot_attr_eth_index.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_INDEX);
- else if (attr == &iscsi_boot_attr_eth_flags.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_FLAGS);
- else if (attr == &iscsi_boot_attr_eth_ip.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_IP_ADDR);
- else if (attr == &iscsi_boot_attr_eth_subnet.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_SUBNET_MASK);
- else if (attr == &iscsi_boot_attr_eth_origin.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_ORIGIN);
- else if (attr == &iscsi_boot_attr_eth_gateway.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_GATEWAY);
- else if (attr == &iscsi_boot_attr_eth_primary_dns.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_PRIMARY_DNS);
- else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_SECONDARY_DNS);
- else if (attr == &iscsi_boot_attr_eth_dhcp.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_DHCP);
- else if (attr == &iscsi_boot_attr_eth_vlan.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_VLAN);
- else if (attr == &iscsi_boot_attr_eth_mac.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_MAC);
- else if (attr == &iscsi_boot_attr_eth_hostname.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_ETH_HOSTNAME);
- return 0;
-}
-
-static struct attribute_group iscsi_boot_ethernet_attr_group = {
- .attrs = ethernet_attrs,
- .is_visible = iscsi_boot_eth_attr_is_visible,
-};
-
-/* Initiator attrs */
-iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
-iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
-iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
-iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
-iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
- ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
-iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
- ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
-iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
-
-static struct attribute *initiator_attrs[] = {
- &iscsi_boot_attr_ini_index.attr,
- &iscsi_boot_attr_ini_flags.attr,
- &iscsi_boot_attr_ini_isns.attr,
- &iscsi_boot_attr_ini_slp.attr,
- &iscsi_boot_attr_ini_primary_radius.attr,
- &iscsi_boot_attr_ini_secondary_radius.attr,
- &iscsi_boot_attr_ini_name.attr,
- NULL
-};
-
-static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
- struct attribute *attr, int i)
-{
- struct iscsi_boot_kobj *boot_kobj =
- container_of(kobj, struct iscsi_boot_kobj, kobj);
-
- if (attr == &iscsi_boot_attr_ini_index.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_INDEX);
- if (attr == &iscsi_boot_attr_ini_flags.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_FLAGS);
- if (attr == &iscsi_boot_attr_ini_isns.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_ISNS_SERVER);
- if (attr == &iscsi_boot_attr_ini_slp.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_SLP_SERVER);
- if (attr == &iscsi_boot_attr_ini_primary_radius.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
- if (attr == &iscsi_boot_attr_ini_secondary_radius.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
- if (attr == &iscsi_boot_attr_ini_name.attr)
- return boot_kobj->is_visible(boot_kobj->data,
- ISCSI_BOOT_INI_INITIATOR_NAME);
-
- return 0;
-}
-
-static struct attribute_group iscsi_boot_initiator_attr_group = {
- .attrs = initiator_attrs,
- .is_visible = iscsi_boot_ini_attr_is_visible,
-};
-
-static struct iscsi_boot_kobj *
-iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
- struct attribute_group *attr_group,
- const char *name, int index, void *data,
- ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
-{
- struct iscsi_boot_kobj *boot_kobj;
-
- boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
- if (!boot_kobj)
- return NULL;
- INIT_LIST_HEAD(&boot_kobj->list);
-
- boot_kobj->kobj.kset = boot_kset->kset;
- if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
- NULL, name, index)) {
- kfree(boot_kobj);
- return NULL;
- }
- boot_kobj->data = data;
- boot_kobj->show = show;
- boot_kobj->is_visible = is_visible;
-
- if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
- /*
- * We do not want to free this because the caller
- * will assume that since the creation call failed
- * the boot kobj was not setup and the normal release
- * path is not being run.
- */
- boot_kobj->data = NULL;
- kobject_put(&boot_kobj->kobj);
- return NULL;
- }
- boot_kobj->attr_group = attr_group;
-
- kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
- /* Nothing broke so lets add it to the list. */
- list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
- return boot_kobj;
-}
-
-static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
-{
- list_del(&boot_kobj->list);
- sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
- kobject_put(&boot_kobj->kobj);
-}
-
-/**
- * iscsi_boot_create_target() - create boot target sysfs dir
- * @boot_kset: boot kset
- * @index: the target id
- * @data: driver specific data for target
- * @show: attr show function
- * @is_visible: attr visibility function
- *
- * Note: The boot sysfs lib will free the data passed in for the caller
- * when all refs to the target kobject have been released.
- */
-struct iscsi_boot_kobj *
-iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
- void *data,
- ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
-{
- return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
- "target%d", index, data, show, is_visible);
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
-
-/**
- * iscsi_boot_create_initiator() - create boot initiator sysfs dir
- * @boot_kset: boot kset
- * @index: the initiator id
- * @data: driver specific data
- * @show: attr show function
- * @is_visible: attr visibility function
- *
- * Note: The boot sysfs lib will free the data passed in for the caller
- * when all refs to the initiator kobject have been released.
- */
-struct iscsi_boot_kobj *
-iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
- void *data,
- ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
-{
- return iscsi_boot_create_kobj(boot_kset,
- &iscsi_boot_initiator_attr_group,
- "initiator", index, data, show,
- is_visible);
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
-
-/**
- * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
- * @boot_kset: boot kset
- * @index: the ethernet device id
- * @data: driver specific data
- * @show: attr show function
- * @is_visible: attr visibility function
- *
- * Note: The boot sysfs lib will free the data passed in for the caller
- * when all refs to the ethernet kobject have been released.
- */
-struct iscsi_boot_kobj *
-iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
- void *data,
- ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
-{
- return iscsi_boot_create_kobj(boot_kset,
- &iscsi_boot_ethernet_attr_group,
- "ethernet%d", index, data, show,
- is_visible);
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
-
-/**
- * iscsi_boot_create_kset() - creates root sysfs tree
- * @set_name: name of root dir
- */
-struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
-{
- struct iscsi_boot_kset *boot_kset;
-
- boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
- if (!boot_kset)
- return NULL;
-
- boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
- if (!boot_kset->kset) {
- kfree(boot_kset);
- return NULL;
- }
-
- INIT_LIST_HEAD(&boot_kset->kobj_list);
- return boot_kset;
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
-
-/**
- * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
- * @hostno: host number of scsi host
- */
-struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
-{
- struct iscsi_boot_kset *boot_kset;
- char *set_name;
-
- set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
- if (!set_name)
- return NULL;
-
- boot_kset = iscsi_boot_create_kset(set_name);
- kfree(set_name);
- return boot_kset;
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
-
-/**
- * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
- * @boot_kset: boot kset
- *
- * This will remove the kset and kobjects and attrs under it.
- */
-void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
-{
- struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
-
- list_for_each_entry_safe(boot_kobj, tmp_kobj,
- &boot_kset->kobj_list, list)
- iscsi_boot_remove_kobj(boot_kobj);
-
- kset_unregister(boot_kset->kset);
-}
-EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 158284f..a479b3b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -370,6 +370,14 @@ config ISCSI_TCP
http://open-iscsi.org
+config ISCSI_BOOT_SYSFS
+ tristate "iSCSI Boot Sysfs Interface"
+ default n
+ help
+ This option enables support for exposing iSCSI boot information
+ via sysfs to userspace. If you wish to export this information,
+ say Y. Otherwise, say N.
+
source "drivers/scsi/cxgb3i/Kconfig"
source "drivers/scsi/bnx2i/Kconfig"
source "drivers/scsi/be2iscsi/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2a3fca2..2703c6e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_FCOE) += fcoe/
obj-$(CONFIG_FCOE_FNIC) += fnic/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
+obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
new file mode 100644
index 0000000..df6bff7
--- /dev/null
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -0,0 +1,481 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/capability.h>
+#include <linux/iscsi_boot_sysfs.h>
+
+
+MODULE_AUTHOR("Mike Christie <michaelc@xxxxxxxxxxx>");
+MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
+MODULE_LICENSE("GPL");
+/*
+ * The kobject and attribute structures.
+ */
+struct iscsi_boot_attr {
+ struct attribute attr;
+ int type;
+ ssize_t (*show) (void *data, int type, char *buf);
+};
+
+/*
+ * The routine called for all sysfs attributes.
+ */
+static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+ struct iscsi_boot_attr *boot_attr =
+ container_of(attr, struct iscsi_boot_attr, attr);
+ ssize_t ret = -EIO;
+ char *str = buf;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (boot_kobj->show)
+ ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
+ return ret;
+}
+
+static const struct sysfs_ops iscsi_boot_attr_ops = {
+ .show = iscsi_boot_show_attribute,
+};
+
+static void iscsi_boot_kobj_release(struct kobject *kobj)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ kfree(boot_kobj->data);
+ kfree(boot_kobj);
+}
+
+static struct kobj_type iscsi_boot_ktype = {
+ .release = iscsi_boot_kobj_release,
+ .sysfs_ops = &iscsi_boot_attr_ops,
+};
+
+#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \
+static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \
+ .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \
+ .type = attr_type, \
+}
+
+/* Target attrs */
+iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
+iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
+iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
+iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
+iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
+iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
+iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
+iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
+iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
+iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+
+static struct attribute *target_attrs[] = {
+ &iscsi_boot_attr_tgt_index.attr,
+ &iscsi_boot_attr_tgt_flags.attr,
+ &iscsi_boot_attr_tgt_ip.attr,
+ &iscsi_boot_attr_tgt_port.attr,
+ &iscsi_boot_attr_tgt_lun.attr,
+ &iscsi_boot_attr_tgt_chap.attr,
+ &iscsi_boot_attr_tgt_nic.attr,
+ &iscsi_boot_attr_tgt_name.attr,
+ &iscsi_boot_attr_tgt_chap_name.attr,
+ &iscsi_boot_attr_tgt_chap_secret.attr,
+ &iscsi_boot_attr_tgt_chap_rev_name.attr,
+ &iscsi_boot_attr_tgt_chap_rev_secret.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_tgt_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_INDEX);
+ else if (attr == &iscsi_boot_attr_tgt_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_FLAGS);
+ else if (attr == &iscsi_boot_attr_tgt_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_tgt_port.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_PORT);
+ else if (attr == &iscsi_boot_attr_tgt_lun.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_LUN);
+ else if (attr == &iscsi_boot_attr_tgt_chap.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_TYPE);
+ else if (attr == &iscsi_boot_attr_tgt_nic.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NIC_ASSOC);
+ else if (attr == &iscsi_boot_attr_tgt_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_SECRET);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_target_attr_group = {
+ .attrs = target_attrs,
+ .is_visible = iscsi_boot_tgt_attr_is_visible,
+};
+
+/* Ethernet attrs */
+iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
+iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
+iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
+iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
+iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
+iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
+iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
+iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
+iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
+iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
+
+static struct attribute *ethernet_attrs[] = {
+ &iscsi_boot_attr_eth_index.attr,
+ &iscsi_boot_attr_eth_flags.attr,
+ &iscsi_boot_attr_eth_ip.attr,
+ &iscsi_boot_attr_eth_subnet.attr,
+ &iscsi_boot_attr_eth_origin.attr,
+ &iscsi_boot_attr_eth_gateway.attr,
+ &iscsi_boot_attr_eth_primary_dns.attr,
+ &iscsi_boot_attr_eth_secondary_dns.attr,
+ &iscsi_boot_attr_eth_dhcp.attr,
+ &iscsi_boot_attr_eth_vlan.attr,
+ &iscsi_boot_attr_eth_mac.attr,
+ &iscsi_boot_attr_eth_hostname.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_eth_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_INDEX);
+ else if (attr == &iscsi_boot_attr_eth_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_FLAGS);
+ else if (attr == &iscsi_boot_attr_eth_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_eth_subnet.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SUBNET_MASK);
+ else if (attr == &iscsi_boot_attr_eth_origin.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_ORIGIN);
+ else if (attr == &iscsi_boot_attr_eth_gateway.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_GATEWAY);
+ else if (attr == &iscsi_boot_attr_eth_primary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_PRIMARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_dhcp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_DHCP);
+ else if (attr == &iscsi_boot_attr_eth_vlan.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_VLAN);
+ else if (attr == &iscsi_boot_attr_eth_mac.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_MAC);
+ else if (attr == &iscsi_boot_attr_eth_hostname.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_HOSTNAME);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_ethernet_attr_group = {
+ .attrs = ethernet_attrs,
+ .is_visible = iscsi_boot_eth_attr_is_visible,
+};
+
+/* Initiator attrs */
+iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
+iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
+iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
+iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
+iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
+
+static struct attribute *initiator_attrs[] = {
+ &iscsi_boot_attr_ini_index.attr,
+ &iscsi_boot_attr_ini_flags.attr,
+ &iscsi_boot_attr_ini_isns.attr,
+ &iscsi_boot_attr_ini_slp.attr,
+ &iscsi_boot_attr_ini_primary_radius.attr,
+ &iscsi_boot_attr_ini_secondary_radius.attr,
+ &iscsi_boot_attr_ini_name.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_ini_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INDEX);
+ if (attr == &iscsi_boot_attr_ini_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_FLAGS);
+ if (attr == &iscsi_boot_attr_ini_isns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_ISNS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_slp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SLP_SERVER);
+ if (attr == &iscsi_boot_attr_ini_primary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_secondary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INITIATOR_NAME);
+
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_initiator_attr_group = {
+ .attrs = initiator_attrs,
+ .is_visible = iscsi_boot_ini_attr_is_visible,
+};
+
+static struct iscsi_boot_kobj *
+iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
+ struct attribute_group *attr_group,
+ const char *name, int index, void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ struct iscsi_boot_kobj *boot_kobj;
+
+ boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
+ if (!boot_kobj)
+ return NULL;
+ INIT_LIST_HEAD(&boot_kobj->list);
+
+ boot_kobj->kobj.kset = boot_kset->kset;
+ if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
+ NULL, name, index)) {
+ kfree(boot_kobj);
+ return NULL;
+ }
+ boot_kobj->data = data;
+ boot_kobj->show = show;
+ boot_kobj->is_visible = is_visible;
+
+ if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
+ /*
+ * We do not want to free this because the caller
+ * will assume that since the creation call failed
+ * the boot kobj was not setup and the normal release
+ * path is not being run.
+ */
+ boot_kobj->data = NULL;
+ kobject_put(&boot_kobj->kobj);
+ return NULL;
+ }
+ boot_kobj->attr_group = attr_group;
+
+ kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
+ /* Nothing broke so lets add it to the list. */
+ list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
+ return boot_kobj;
+}
+
+static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
+{
+ list_del(&boot_kobj->list);
+ sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
+ kobject_put(&boot_kobj->kobj);
+}
+
+/**
+ * iscsi_boot_create_target() - create boot target sysfs dir
+ * @boot_kset: boot kset
+ * @index: the target id
+ * @data: driver specific data for target
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the target kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
+ "target%d", index, data, show, is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
+
+/**
+ * iscsi_boot_create_initiator() - create boot initiator sysfs dir
+ * @boot_kset: boot kset
+ * @index: the initiator id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the initiator kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_initiator_attr_group,
+ "initiator", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
+
+/**
+ * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
+ * @boot_kset: boot kset
+ * @index: the ethernet device id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the ethernet kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_ethernet_attr_group,
+ "ethernet%d", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
+
+/**
+ * iscsi_boot_create_kset() - creates root sysfs tree
+ * @set_name: name of root dir
+ */
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
+{
+ struct iscsi_boot_kset *boot_kset;
+
+ boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
+ if (!boot_kset)
+ return NULL;
+
+ boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
+ if (!boot_kset->kset) {
+ kfree(boot_kset);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&boot_kset->kobj_list);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
+
+/**
+ * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
+ * @hostno: host number of scsi host
+ */
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
+{
+ struct iscsi_boot_kset *boot_kset;
+ char *set_name;
+
+ set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
+ if (!set_name)
+ return NULL;
+
+ boot_kset = iscsi_boot_create_kset(set_name);
+ kfree(set_name);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
+
+/**
+ * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
+ * @boot_kset: boot kset
+ *
+ * This will remove the kset and kobjects and attrs under it.
+ */
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
+{
+ struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+
+ list_for_each_entry_safe(boot_kobj, tmp_kobj,
+ &boot_kset->kobj_list, list)
+ iscsi_boot_remove_kobj(boot_kobj);
+
+ kset_unregister(boot_kset->kset);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
--
1.6.6.1