From: Adheer Chandravanshi <adheer.chandravan...@qlogic.com>

This patch allows iscsiadm to manage iSCSI target information stored on
adapter flash on per host basis.

The sysfs entries will look as cited below:
 /sys/firmware/iscsi_offload/host1/new
 /sys/firmware/iscsi_offload/host1/delete
 /sys/firmware/iscsi_offload/host1/tgt0/logout
 /sys/firmware/iscsi_offload/host1/tgt0/login
 /sys/firmware/iscsi_offload/host1/tgt0/apply
 /sys/firmware/iscsi_offload/host1/tgt0/<Target attributes>

 Here - new, delete, login, logout and apply are the operations which iscsiadm
 can perform on each target entry.

Signed-off-by: Adheer Chandravanshi <adheer.chandravan...@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudh...@qlogic.com>
---
 drivers/scsi/Kconfig             |    8 +
 drivers/scsi/Makefile            |    1 +
 drivers/scsi/iscsi_flash_sysfs.c |  600 ++++++++++++++++++++++++++++++++++++++
 include/scsi/iscsi_flash_sysfs.h |  152 ++++++++++
 4 files changed, 761 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/iscsi_flash_sysfs.c
 create mode 100644 include/scsi/iscsi_flash_sysfs.h

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 74bf1aa..659091b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -363,6 +363,14 @@ config ISCSI_BOOT_SYSFS
          via sysfs to userspace. If you wish to export this information,
          say Y. Otherwise, say N.
 
+config ISCSI_FLASH_SYSFS
+       tristate "iSCSI Flash Target Sysfs Interface"
+       default n
+       help
+         This option enables support for exporting iSCSI flash target
+         information, stored on iSCSI adapter, through sysfs to userspace.
+         If you wish to export this information, say Y. Otherwise, say N.
+
 source "drivers/scsi/cxgbi/Kconfig"
 source "drivers/scsi/bnx2i/Kconfig"
 source "drivers/scsi/bnx2fc/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 888f73a..d6cabe5 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SCSI_BNX2X_FCOE) += libfc/ fcoe/ bnx2fc/
 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_ISCSI_FLASH_SYSFS)        += iscsi_flash_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_flash_sysfs.c b/drivers/scsi/iscsi_flash_sysfs.c
new file mode 100644
index 0000000..f09672d
--- /dev/null
+++ b/drivers/scsi/iscsi_flash_sysfs.c
@@ -0,0 +1,600 @@
+/*
+ * Export the iSCSI flash target info to userland through sysfs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/kobject.h>
+#include <scsi/iscsi_flash_sysfs.h>
+
+/*
+ * kobject for iscsi_offload
+ */
+static struct kobject *iscsi_offload_kobj;
+
+/**
+ * iscsi_flash_tgt_kobj_release() - release the tgt kobject
+ * The routine gets called for all tgt sysfs attributes.
+ */
+static void iscsi_flash_tgt_kobj_release(struct kobject *kobj)
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj =
+                       container_of(kobj, struct iscsi_flash_tgt_kobj, kobj);
+
+       if (tgt_kobj->release)
+               tgt_kobj->release(tgt_kobj->data);
+       kfree(tgt_kobj);
+}
+
+/**
+ * iscsi_flash_tgt_attr_show() - show the attr value
+ * The routine gets called for all tgt sysfs attributes.
+ */
+static ssize_t iscsi_flash_tgt_attr_show(struct kobject *kobj,
+                                        struct attribute *attr, char *buf)
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj =
+                       container_of(kobj, struct iscsi_flash_tgt_kobj, kobj);
+       struct iscsi_flash_tgt_attr *tgt_attr =
+                       container_of(attr, struct iscsi_flash_tgt_attr, attr);
+       char *str = buf;
+
+       if (!tgt_kobj->show)
+               return -EIO;
+
+       return tgt_kobj->show(tgt_kobj->data, tgt_attr->type, str);
+}
+
+/**
+ * iscsi_flash_tgt_attr_store() - set the attr value
+ * The routine gets called for all tgt sysfs attributes.
+ */
+static ssize_t iscsi_flash_tgt_attr_store(struct kobject *kobj,
+                                         struct attribute *attr,
+                                         const char *buf, size_t size)
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj =
+                       container_of(kobj, struct iscsi_flash_tgt_kobj, kobj);
+       struct iscsi_flash_tgt_attr *tgt_attr =
+                       container_of(attr, struct iscsi_flash_tgt_attr, attr);
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!tgt_kobj->store)
+               return -EIO;
+
+       return tgt_kobj->store(tgt_kobj->data, tgt_attr->type, buf, size);
+}
+
+static const struct sysfs_ops iscsi_flash_tgt_attr_ops = {
+       .show = iscsi_flash_tgt_attr_show,
+       .store = iscsi_flash_tgt_attr_store,
+};
+
+static struct kobj_type iscsi_flash_tgt_ktype = {
+       .release = iscsi_flash_tgt_kobj_release,
+       .sysfs_ops = &iscsi_flash_tgt_attr_ops,
+};
+
+#define iscsi_flash_tgt_rw_attr(fnname, sysfs_name, attr_type)       \
+static struct iscsi_flash_tgt_attr iscsi_flash_tgt_##fnname = {      \
+       .attr   = { .name = __stringify(sysfs_name), .mode = 0644 }, \
+       .type   = attr_type,                                         \
+}
+
+/* Target attributes */
+
+iscsi_flash_tgt_rw_attr(ip, ipaddress, FLASH_TGT_IP_ADDR);
+iscsi_flash_tgt_rw_attr(port, port, FLASH_TGT_PORT);
+iscsi_flash_tgt_rw_attr(options, target_options, FLASH_TGT_OPTIONS);
+iscsi_flash_tgt_rw_attr(iscsi_options, iscsi_options,
+                       FLASH_TGT_ISCSI_OPTIONS);
+iscsi_flash_tgt_rw_attr(tcp_options, tcp_options,
+                       FLASH_TGT_TCP_OPTIONS);
+iscsi_flash_tgt_rw_attr(ip_options, ip_options, FLASH_TGT_IP_OPTIONS);
+iscsi_flash_tgt_rw_attr(max_recv_ds_len, max_recv_data_segment_length,
+                       FLASH_TGT_MAX_RECV_DS_LEN);
+iscsi_flash_tgt_rw_attr(max_xmit_ds_len, max_xmit_data_segment_length,
+                       FLASH_TGT_MAX_XMIT_DS_LEN);
+iscsi_flash_tgt_rw_attr(first_burst_len, first_burst_length,
+                       FLASH_TGT_FIRST_BURST_LEN);
+iscsi_flash_tgt_rw_attr(def_time2wait, default_time2wait,
+                       FLASH_TGT_DEF_TIME2WAIT);
+iscsi_flash_tgt_rw_attr(def_time2retain, default_time2retain,
+                       FLASH_TGT_DEF_TIME2RETAIN);
+iscsi_flash_tgt_rw_attr(max_outstanding_r2t, max_outstanding_r2t,
+                       FLASH_TGT_MAX_OUTSTANDING_R2T);
+iscsi_flash_tgt_rw_attr(noop_out_interval, noop_out_interval,
+                       FLASH_TGT_NOOP_OUT_INTERVAL);
+iscsi_flash_tgt_rw_attr(isid, isid, FLASH_TGT_ISID);
+iscsi_flash_tgt_rw_attr(tsid, tsid, FLASH_TGT_TSID);
+iscsi_flash_tgt_rw_attr(max_burst_len, max_burst_length,
+                       FLASH_TGT_MAX_BURST_LEN);
+iscsi_flash_tgt_rw_attr(fw_cmd_timeout, firmware_cmd_timeout,
+                       FLASH_TGT_FW_CMD_TIMEOUT);
+iscsi_flash_tgt_rw_attr(iscsi_alias, iscsi_alias,
+                       FLASH_TGT_ISCSI_ALIAS);
+iscsi_flash_tgt_rw_attr(address, target_address, FLASH_TGT_ADDRESS);
+iscsi_flash_tgt_rw_attr(name, name, FLASH_TGT_NAME);
+iscsi_flash_tgt_rw_attr(tpgt, tpgt, FLASH_TGT_TPGT);
+iscsi_flash_tgt_rw_attr(chap_tbl_idx, chap_tbl_idx, FLASH_TGT_CHAP_TBL_IDX);
+iscsi_flash_tgt_rw_attr(is_persistent, is_persistent, FLASH_TGT_IS_PERSISTENT);
+iscsi_flash_tgt_rw_attr(login, login, FLASH_TGT_LOGIN);
+iscsi_flash_tgt_rw_attr(logout, logout, FLASH_TGT_LOGOUT);
+iscsi_flash_tgt_rw_attr(apply, apply, FLASH_TGT_APPLY);
+
+
+static struct attribute *target_attrs[] = {
+       &iscsi_flash_tgt_ip.attr,
+       &iscsi_flash_tgt_port.attr,
+       &iscsi_flash_tgt_name.attr,
+       &iscsi_flash_tgt_options.attr,
+       &iscsi_flash_tgt_iscsi_options.attr,
+       &iscsi_flash_tgt_tcp_options.attr,
+       &iscsi_flash_tgt_ip_options.attr,
+       &iscsi_flash_tgt_max_recv_ds_len.attr,
+       &iscsi_flash_tgt_max_xmit_ds_len.attr,
+       &iscsi_flash_tgt_first_burst_len.attr,
+       &iscsi_flash_tgt_def_time2wait.attr,
+       &iscsi_flash_tgt_def_time2retain.attr,
+       &iscsi_flash_tgt_max_outstanding_r2t.attr,
+       &iscsi_flash_tgt_noop_out_interval.attr,
+       &iscsi_flash_tgt_isid.attr,
+       &iscsi_flash_tgt_tsid.attr,
+       &iscsi_flash_tgt_max_burst_len.attr,
+       &iscsi_flash_tgt_fw_cmd_timeout.attr,
+       &iscsi_flash_tgt_iscsi_alias.attr,
+       &iscsi_flash_tgt_address.attr,
+       &iscsi_flash_tgt_tpgt.attr,
+       &iscsi_flash_tgt_chap_tbl_idx.attr,
+       &iscsi_flash_tgt_is_persistent.attr,
+       &iscsi_flash_tgt_login.attr,
+       &iscsi_flash_tgt_logout.attr,
+       &iscsi_flash_tgt_apply.attr,
+       NULL,
+};
+
+static umode_t iscsi_flash_tgt_attr_is_visible(struct kobject *kobj,
+                                            struct attribute *attr, int i)
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj =
+                       container_of(kobj, struct iscsi_flash_tgt_kobj, kobj);
+
+       if (attr == &iscsi_flash_tgt_ip.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_IP_ADDR);
+       else if (attr == &iscsi_flash_tgt_port.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data, FLASH_TGT_PORT);
+       else if (attr ==  &iscsi_flash_tgt_name.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_NAME);
+       else if (attr == &iscsi_flash_tgt_options.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_OPTIONS);
+       else if (attr == &iscsi_flash_tgt_iscsi_options.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_ISCSI_OPTIONS);
+       else if (attr == &iscsi_flash_tgt_tcp_options.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_TCP_OPTIONS);
+       else if (attr == &iscsi_flash_tgt_ip_options.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_IP_OPTIONS);
+       else if (attr == &iscsi_flash_tgt_max_recv_ds_len.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_MAX_RECV_DS_LEN);
+       else if (attr == &iscsi_flash_tgt_max_xmit_ds_len.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_MAX_XMIT_DS_LEN);
+       else if (attr == &iscsi_flash_tgt_first_burst_len.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_FIRST_BURST_LEN);
+       else if (attr == &iscsi_flash_tgt_def_time2wait.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_DEF_TIME2WAIT);
+       else if (attr == &iscsi_flash_tgt_def_time2retain.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_DEF_TIME2RETAIN);
+       else if (attr == &iscsi_flash_tgt_max_outstanding_r2t.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_MAX_OUTSTANDING_R2T);
+       else if (attr == &iscsi_flash_tgt_noop_out_interval.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_NOOP_OUT_INTERVAL);
+       else if (attr == &iscsi_flash_tgt_isid.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data, FLASH_TGT_ISID);
+       else if (attr == &iscsi_flash_tgt_tsid.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data, FLASH_TGT_TSID);
+       else if (attr == &iscsi_flash_tgt_max_burst_len.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_MAX_BURST_LEN);
+       else if (attr ==  &iscsi_flash_tgt_fw_cmd_timeout.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_FW_CMD_TIMEOUT);
+       else if (attr ==  &iscsi_flash_tgt_iscsi_alias.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_ISCSI_ALIAS);
+       else if (attr ==  &iscsi_flash_tgt_address.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_ADDRESS);
+       else if (attr ==  &iscsi_flash_tgt_tpgt.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_TPGT);
+       else if (attr == &iscsi_flash_tgt_chap_tbl_idx.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_CHAP_TBL_IDX);
+       else if (attr == &iscsi_flash_tgt_is_persistent.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_IS_PERSISTENT);
+       else if (attr == &iscsi_flash_tgt_login.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_LOGIN);
+       else if (attr == &iscsi_flash_tgt_logout.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_LOGOUT);
+       else if (attr == &iscsi_flash_tgt_apply.attr)
+               return tgt_kobj->is_visible(tgt_kobj->data,
+                                           FLASH_TGT_APPLY);
+       return 0;
+}
+
+static struct attribute_group iscsi_flash_tgt_attr_group = {
+       .attrs = target_attrs,
+       .is_visible = iscsi_flash_tgt_attr_is_visible,
+};
+
+static struct iscsi_flash_tgt_kobj *
+__iscsi_flash_tgt_kobj_create(struct iscsi_host_kobj *host_kobj,
+                             struct attribute_group *attr_group,
+                             const char *name, int index, void *data,
+                             ssize_t (*show) (void *data, int type, char *buf),
+                             ssize_t (*store) (void *data, int type,
+                                               const char *buf, size_t size),
+                             umode_t (*is_visible) (void *data, int type),
+                             void (*release) (void *data))
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj = NULL;
+
+       tgt_kobj = kzalloc(sizeof(*tgt_kobj), GFP_KERNEL);
+       if (!tgt_kobj)
+               goto exit_kobj_create;
+
+       INIT_LIST_HEAD(&tgt_kobj->list);
+       if (kobject_init_and_add(&tgt_kobj->kobj, &iscsi_flash_tgt_ktype,
+                                &host_kobj->kobj, name, index)) {
+               kfree(tgt_kobj);
+               tgt_kobj = NULL;
+               goto exit_kobj_create;
+       }
+       tgt_kobj->data = data;
+       tgt_kobj->show = show;
+       tgt_kobj->store = store;
+       tgt_kobj->is_visible = is_visible;
+       tgt_kobj->release = release;
+
+       if (sysfs_create_group(&tgt_kobj->kobj, attr_group)) {
+               /*
+                * We do not want to free this because the caller
+                * will assume that since the creation call failed
+                * the flash tgt kobj was not setup and the normal release
+                * path is not being run.
+                */
+               tgt_kobj->release = NULL;
+               kobject_put(&tgt_kobj->kobj);
+               return NULL;
+       }
+       tgt_kobj->attr_group = attr_group;
+
+       kobject_uevent(&tgt_kobj->kobj, KOBJ_ADD);
+       list_add_tail(&tgt_kobj->list, &host_kobj->tgt_list);
+
+exit_kobj_create:
+       return tgt_kobj;
+}
+
+/**
+ * iscsi_flash_tgt_kobj_create() - create flash target sysfs dir
+ * @host_kobj: kobject of host
+ * @index: the target id
+ * @data: driver specific data for target
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ * @release: release function
+ */
+struct iscsi_flash_tgt_kobj *
+iscsi_flash_tgt_kobj_create(struct iscsi_host_kobj *host_kobj, int index,
+                           void *data,
+                           ssize_t (*show) (void *data, int type, char *buf),
+                           ssize_t (*store) (void *data, int type,
+                                             const char *buf, size_t size),
+                           umode_t (*is_visible) (void *data, int type),
+                           void (*release) (void *data))
+{
+       return __iscsi_flash_tgt_kobj_create(host_kobj,
+                                            &iscsi_flash_tgt_attr_group,
+                                            "tgt%d", index, data, show, store,
+                                            is_visible, release);
+}
+EXPORT_SYMBOL_GPL(iscsi_flash_tgt_kobj_create);
+
+static void iscsi_flash_tgt_kobj_delete(struct iscsi_flash_tgt_kobj *tgt_kobj)
+{
+       list_del(&tgt_kobj->list);
+       sysfs_remove_group(&tgt_kobj->kobj, tgt_kobj->attr_group);
+       kobject_put(&tgt_kobj->kobj);
+}
+
+static ssize_t iscsi_flash_new_tgt_store(struct iscsi_host_kobj *host_kobj,
+                                        struct iscsi_host_attribute *attr,
+                                        const char *buf, size_t len)
+{
+       if (!host_kobj->add)
+               return -EIO;
+
+       return host_kobj->add(host_kobj->data, buf, len);
+}
+
+/**
+ * iscsi_flash_find_tgt_kobj_by_index() - find tgt kobj in the list
+ * @tgt_kobj_list: head of the list to search
+ * @tgt_kobj: pointer to the kobj to iterate
+ * @index: index of the target to search
+ *
+ * Returns:
+ * On success: 1
+ * On failure: 0
+ *
+ * This will find the tgt kobj in the given list with the help of index
+ */
+int iscsi_flash_find_tgt_kobj_by_index(struct list_head *tgt_kobj_list,
+                                      struct iscsi_flash_tgt_kobj **tgt_kobj,
+                                      int index)
+{
+       char *get_name = NULL;
+       int found = 0;
+
+       get_name = kasprintf(GFP_KERNEL, "tgt%d", index);
+       if (!get_name)
+               return found;
+
+       list_for_each_entry((*tgt_kobj), tgt_kobj_list, list) {
+               if ((*tgt_kobj)->kobj.name &&
+                   !strcmp((*tgt_kobj)->kobj.name, get_name)) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       kfree(get_name);
+       return found;
+}
+EXPORT_SYMBOL_GPL(iscsi_flash_find_tgt_kobj_by_index);
+
+static ssize_t iscsi_flash_del_tgt_store(struct iscsi_host_kobj *host_kobj,
+                                        struct iscsi_host_attribute *attr,
+                                        const char *buf, size_t len)
+{
+       int index;
+       struct iscsi_flash_tgt_kobj *tgt_kobj = NULL;
+       int found = 0;
+
+       if (kstrtoint(buf, 10, &index))
+               return -EINVAL;
+
+       found = iscsi_flash_find_tgt_kobj_by_index(&host_kobj->tgt_list,
+                                                  &tgt_kobj, index);
+       if (!found)
+               return -EINVAL;
+
+       iscsi_flash_tgt_kobj_delete(tgt_kobj);
+       return len;
+}
+
+static void iscsi_host_kobj_release(struct kobject *kobj)
+{
+       struct iscsi_host_kobj *host_kobj =
+                       container_of(kobj, struct iscsi_host_kobj, kobj);
+
+       kfree(host_kobj);
+}
+
+static ssize_t iscsi_host_attr_store(struct kobject *kobj,
+                                    struct attribute *attr,
+                                    const char *buf, size_t size)
+{
+       struct iscsi_host_kobj *host_kobj =
+                       container_of(kobj, struct iscsi_host_kobj, kobj);
+       struct iscsi_host_attribute *host_tgt_attr =
+                       container_of(attr, struct iscsi_host_attribute, attr);
+
+       if (!host_tgt_attr->store)
+               return -EIO;
+
+       return host_tgt_attr->store(host_kobj, host_tgt_attr, buf, size);
+}
+
+static const struct sysfs_ops iscsi_host_attr_ops = {
+       .show = NULL,
+       .store = iscsi_host_attr_store,
+};
+
+static struct kobj_type iscsi_host_ktype = {
+       .release = iscsi_host_kobj_release,
+       .sysfs_ops = &iscsi_host_attr_ops,
+};
+
+#define iscsi_host_rw_attr(fnname, sysfs_name, _mode, _show, _store, _type)  \
+static struct iscsi_host_attribute iscsi_host_flash_tgt_##fnname = {         \
+       .attr = { .name = __stringify(sysfs_name), .mode = _mode },          \
+       .store = _store,                                                     \
+       .type = _type,                                                       \
+}
+
+/* Host attributes */
+iscsi_host_rw_attr(new, new, 0200, NULL, iscsi_flash_new_tgt_store,
+                  HOST_FLASH_TGT_NEW);
+iscsi_host_rw_attr(del, delete, 0200, NULL, iscsi_flash_del_tgt_store,
+                  HOST_FLASH_TGT_DEL);
+
+static struct attribute *host_attrs[] = {
+       &iscsi_host_flash_tgt_del.attr,
+       &iscsi_host_flash_tgt_new.attr,
+       NULL,
+};
+
+static struct attribute_group iscsi_host_attr_group = {
+       .attrs = host_attrs,
+};
+
+/**
+ * __iscsi_host_kobj_create() - creates host kobject
+ * @set_name: name of the kobject to create
+ * @data: pointer to host specific data
+ * @add: function to add new target for this host
+ *
+ * This creates the host kobject for the given name
+ */
+static struct iscsi_host_kobj *
+__iscsi_host_kobj_create(const char *set_name, void *data,
+                        ssize_t (*add) (void *data, const char *buf,
+                                       size_t len))
+{
+       struct iscsi_host_kobj *host_kobj = NULL;
+
+       host_kobj = kzalloc(sizeof(*host_kobj), GFP_KERNEL);
+       if (!host_kobj)
+               return NULL;
+
+       if (kobject_init_and_add(&host_kobj->kobj, &iscsi_host_ktype,
+                                iscsi_offload_kobj, "%s", set_name))
+               goto error;
+
+       host_kobj->data = data;
+       host_kobj->add = add;
+
+       if (sysfs_create_group(&host_kobj->kobj,
+                              &iscsi_host_attr_group)) {
+               kobject_put(&host_kobj->kobj);
+               goto error;
+       }
+
+       kobject_uevent(&host_kobj->kobj, KOBJ_ADD);
+       INIT_LIST_HEAD(&host_kobj->tgt_list);
+
+       return host_kobj;
+
+error:
+       kfree(host_kobj);
+       return NULL;
+}
+
+/**
+ * iscsi_host_kobj_create() - creates kobject for a scsi host
+ * @hostno: host number of scsi host
+ * @data: pointer to host specific data
+ * @add: function to add target for this host
+ *
+ * This will create host kobject for the given hostno.
+ */
+struct iscsi_host_kobj *
+iscsi_host_kobj_create(unsigned int hostno, void *data,
+                      ssize_t (*add) (void *data, const char *buf, size_t len))
+{
+       struct iscsi_host_kobj *host_kobj;
+       char *set_name;
+
+       set_name = kasprintf(GFP_KERNEL, "host%u", hostno);
+       if (!set_name)
+               return NULL;
+
+       host_kobj = __iscsi_host_kobj_create(set_name, data, add);
+       kfree(set_name);
+       return host_kobj;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_kobj_create);
+
+/**
+ * iscsi_host_kobj_delete() - destroy host kobject and tgt kobjects under it
+ * @host_kobj: host kobject
+ *
+ * This will remove the host kobject and all target kobjects and attrs under 
it.
+ */
+void iscsi_host_kobj_delete(struct iscsi_host_kobj *host_kobj)
+{
+       struct iscsi_flash_tgt_kobj *tgt_kobj = NULL, *tmp_kobj;
+
+       if (!host_kobj)
+               return;
+
+       sysfs_remove_group(&host_kobj->kobj, &iscsi_host_attr_group);
+
+       list_for_each_entry_safe(tgt_kobj, tmp_kobj,
+                                &host_kobj->tgt_list, list)
+               iscsi_flash_tgt_kobj_delete(tgt_kobj);
+
+       kobject_put(&host_kobj->kobj);
+}
+EXPORT_SYMBOL_GPL(iscsi_host_kobj_delete);
+
+/**
+ * iscsi_offload_kobj_create() - creates kobject for iscsi_offload
+ * @name: name of kobject to create
+ */
+static struct kobject *iscsi_offload_kobj_create(const char *name)
+{
+       struct kobject *fw_iscsi_offload = NULL;
+
+       fw_iscsi_offload = kobject_create_and_add(name, firmware_kobj);
+       if (!fw_iscsi_offload)
+               return NULL;
+
+       return fw_iscsi_offload;
+}
+
+/**
+ * iscsi_offload_kobj_remove() - removes iscsi_offload kobject
+ */
+static void iscsi_offload_kobj_remove(struct kobject *kobj)
+{
+       if (kobj) {
+               kobject_del(kobj);
+               kobject_put(kobj);
+       }
+}
+
+static int __init iscsi_offload_module_init(void)
+{
+       iscsi_offload_kobj = iscsi_offload_kobj_create(ISCSI_OFFLOAD_NAME);
+       if (!iscsi_offload_kobj) {
+               pr_err("%s: Unable to create sysfs interface\n",
+                      ISCSI_OFFLOAD_NAME);
+               return -EIO;
+       }
+       return 0;
+}
+
+static void __exit iscsi_offload_module_exit(void)
+{
+       iscsi_offload_kobj_remove(iscsi_offload_kobj);
+}
+
+module_init(iscsi_offload_module_init);
+module_exit(iscsi_offload_module_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI flash target 
information");
+MODULE_LICENSE("GPL");
diff --git a/include/scsi/iscsi_flash_sysfs.h b/include/scsi/iscsi_flash_sysfs.h
new file mode 100644
index 0000000..3a47c57
--- /dev/null
+++ b/include/scsi/iscsi_flash_sysfs.h
@@ -0,0 +1,152 @@
+/*
+ * Export the iSCSI flash target info to userland through sysfs.
+ *
+ * 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.
+ */
+#ifndef ISCSI_FLASH_SYSFS_H
+#define ISCSI_FLASH_SYSFS_H
+
+#define ISCSI_OFFLOAD_NAME "iscsi_offload"
+
+/*
+ * The kobject and attribute structures for Flash Targets
+ */
+
+struct iscsi_flash_tgt_attr {
+       struct attribute attr;
+       int type;
+};
+
+/*
+ * The text attributes names for each of the kobjects.
+ */
+
+enum iscsi_host_flash_tgt_properties_enum {
+       HOST_FLASH_TGT_NEW,
+       HOST_FLASH_TGT_DEL,
+};
+
+enum iscsi_flash_tgt_properties_enum {
+       FLASH_TGT_IP_ADDR,
+       FLASH_TGT_PORT,
+       FLASH_TGT_OPTIONS,
+       FLASH_TGT_ISCSI_OPTIONS,
+       FLASH_TGT_TCP_OPTIONS,
+       FLASH_TGT_IP_OPTIONS,
+       FLASH_TGT_MAX_RECV_DS_LEN,
+       FLASH_TGT_MAX_XMIT_DS_LEN,
+       FLASH_TGT_FIRST_BURST_LEN,
+       FLASH_TGT_DEF_TIME2WAIT,
+       FLASH_TGT_DEF_TIME2RETAIN,
+       FLASH_TGT_MAX_OUTSTANDING_R2T,
+       FLASH_TGT_NOOP_OUT_INTERVAL,
+       FLASH_TGT_ISID,
+       FLASH_TGT_TSID,
+       FLASH_TGT_MAX_BURST_LEN,
+       FLASH_TGT_FW_CMD_TIMEOUT,
+       FLASH_TGT_ISCSI_ALIAS,
+       FLASH_TGT_ADDRESS,
+       FLASH_TGT_NAME,
+       FLASH_TGT_TPGT,
+       FLASH_TGT_CHAP_TBL_IDX,
+       FLASH_TGT_IS_PERSISTENT,
+       FLASH_TGT_LOGIN,
+       FLASH_TGT_LOGOUT,
+       FLASH_TGT_APPLY,
+       FLASH_TGT_END_MARKER,
+};
+
+struct iscsi_flash_tgt_kobj {
+       struct kobject kobj;
+       struct attribute_group *attr_group;
+       struct list_head list;
+
+       /*
+        * Pointer to store driver specific info. If set this will
+        * be freed for the LLD when the kobj release function is called.
+        */
+       void *data;
+       /*
+        * Driver specific show function.
+        *
+        * The enum of the type. This can be any value of the above
+        * properties.
+        */
+       ssize_t (*show) (void *data, int type, char *buf);
+
+       /*
+        * Driver specific store function.
+        *
+        * The enum of the type. This can be any value of the above
+        * properties.
+        */
+       ssize_t (*store) (void *data, int type, const char *buf, size_t size);
+
+       /*
+        * Drivers specific visibility function.
+        * The function should return if they the attr should be readable
+        * writable or should not be shown.
+        *
+        * The enum of the type. This can be any value of the above
+        * properties.
+        */
+       umode_t (*is_visible) (void *data, int type);
+
+       /*
+        * Driver specific release function.
+        *
+        * The function should free the data passed in.
+        */
+       void (*release) (void *data);
+};
+
+struct iscsi_host_kobj {
+       struct kobject kobj;
+       struct list_head tgt_list;
+
+       /*
+        * Pointer to store driver specific info.
+        */
+       void *data;
+
+       /*
+        * Driver specific add function
+        * The function should add new target
+        */
+       ssize_t (*add) (void *data, const char *buf, size_t len);
+};
+
+struct iscsi_host_attribute {
+       struct attribute attr;
+       int type;
+       ssize_t (*store) (struct iscsi_host_kobj *host_kobj,
+                         struct iscsi_host_attribute *attr,
+                         const char *buf, size_t size);
+};
+
+extern struct iscsi_flash_tgt_kobj *
+iscsi_flash_tgt_kobj_create(struct iscsi_host_kobj *host_kobj,
+                           int index, void *data,
+                           ssize_t (*show) (void *data, int type, char *buf),
+                           ssize_t (*store) (void *data, int type,
+                                             const char *buf, size_t size),
+                           umode_t (*is_visible) (void *data, int type),
+                           void (*release) (void *data));
+
+extern struct iscsi_host_kobj *
+iscsi_host_kobj_create(unsigned int hostno, void *data,
+                      ssize_t (*add) (void *data, const char *buf,
+                                      size_t len));
+extern void iscsi_host_kobj_delete(struct iscsi_host_kobj *host_kobj);
+extern int iscsi_flash_find_tgt_kobj_by_index(struct list_head *tgt_kobj_list,
+                                       struct iscsi_flash_tgt_kobj **tgt_kobj,
+                                       int index);
+
+#endif
-- 
1.7.1

-- 
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to open-iscsi@googlegroups.com.
To unsubscribe from this group, send email to 
open-iscsi+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/open-iscsi?hl=en.

Reply via email to