From: Adheer Chandravanshi <[email protected]> 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 <[email protected]> Signed-off-by: Vikas Chaudhary <[email protected]> --- drivers/scsi/Kconfig | 8 + drivers/scsi/Makefile | 1 + drivers/scsi/iscsi_flash_sysfs.c | 717 ++++++++++++++++++++++++++++++++++++++ include/scsi/iscsi_flash_sysfs.h | 174 +++++++++ 4 files changed, 900 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..2c62e7f --- /dev/null +++ b/drivers/scsi/iscsi_flash_sysfs.c @@ -0,0 +1,717 @@ +/* + * 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, ISCSI_FLASH_TGT_IP_ADDR); +iscsi_flash_tgt_rw_attr(port, port, ISCSI_FLASH_TGT_PORT); +iscsi_flash_tgt_rw_attr(opt_auto_send_tgt_disable, opt_auto_send_tgt_disable, + ISCSI_FLASH_TGT_OPT_AUTO_SND_TGT_DISABLE); +iscsi_flash_tgt_rw_attr(opt_discovery_sess, opt_discovery_session, + ISCSI_FLASH_TGT_OPT_DISCOVERY_SESS); +iscsi_flash_tgt_rw_attr(opt_entry_enable, opt_entry_enable, + ISCSI_FLASH_TGT_OPT_ENTRY_ENABLE); +iscsi_flash_tgt_rw_attr(iscsiopt_enable_hdr_digest, + iscsiopt_enable_hdr_digest, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_HDR_DIGEST); +iscsi_flash_tgt_rw_attr(iscsiopt_enable_data_digest, + iscsiopt_enable_data_digest, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_DATA_DIGEST); +iscsi_flash_tgt_rw_attr(iscsiopt_enable_immediate_data, + iscsiopt_enable_immediate_data, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_IMMEDIATE_DATA); +iscsi_flash_tgt_rw_attr(iscsiopt_enable_initial_r2t, + iscsiopt_enable_initial_r2t, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_INITIAL_R2T); +iscsi_flash_tgt_rw_attr(iscsiopt_data_seq_in_order, iscsiopt_data_seq_in_order, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_SEQ_IN_ORDER); +iscsi_flash_tgt_rw_attr(iscsiopt_data_pdu_in_order, iscsiopt_data_pdu_in_order, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_PDU_IN_ORDER); +iscsi_flash_tgt_rw_attr(iscsiopt_chap_auth_enable, iscsiopt_chap_auth_enable, + ISCSI_FLASH_TGT_ISCSIOPT_CHAP_AUTH_ENABLE); +iscsi_flash_tgt_rw_attr(iscsiopt_snack_req_enable, iscsiopt_snack_req_enable, + ISCSI_FLASH_TGT_ISCSIOPT_SNACK_REQ_ENABLE); +iscsi_flash_tgt_rw_attr(iscsiopt_discovery_logout_enable, + iscsiopt_discovery_logout_enable, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_LOGOUT_ENABLE); +iscsi_flash_tgt_rw_attr(iscsiopt_bi_chap_challenge_enable, + iscsiopt_bi_chap_challenge_enable, + ISCSI_FLASH_TGT_ISCSIOPT_BI_CHAP_CHALLENGE_ENABLE); +iscsi_flash_tgt_rw_attr(iscsiopt_discovery_auth_opt, + iscsiopt_discovery_auth_opt, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_AUTH_OPT); +iscsi_flash_tgt_rw_attr(tcpopt_nagle_disable, tcpopt_nagle_disable, + ISCSI_FLASH_TGT_TCPOPT_NAGLE_DISABLE); +iscsi_flash_tgt_rw_attr(tcpopt_timer_scale, tcpopt_timer_scale, + ISCSI_FLASH_TGT_TCPOPT_TIMER_SCALE); +iscsi_flash_tgt_rw_attr(tcpopt_timestamp_enable, tcpopt_timestamp_enable, + ISCSI_FLASH_TGT_TCPOPT_TIMESTAMP_ENABLE); +iscsi_flash_tgt_rw_attr(ipopt_frag_disable, ipopt_frag_disable, + ISCSI_FLASH_TGT_IPOPT_FRAG_DISABLE); +iscsi_flash_tgt_rw_attr(max_recv_ds_len, max_recv_data_segment_length, + ISCSI_FLASH_TGT_MAX_RECV_DS_LEN); +iscsi_flash_tgt_rw_attr(max_xmit_ds_len, max_xmit_data_segment_length, + ISCSI_FLASH_TGT_MAX_XMIT_DS_LEN); +iscsi_flash_tgt_rw_attr(first_burst_len, first_burst_length, + ISCSI_FLASH_TGT_FIRST_BURST_LEN); +iscsi_flash_tgt_rw_attr(def_time2wait, default_time2wait, + ISCSI_FLASH_TGT_DEF_TIME2WAIT); +iscsi_flash_tgt_rw_attr(def_time2retain, default_time2retain, + ISCSI_FLASH_TGT_DEF_TIME2RETAIN); +iscsi_flash_tgt_rw_attr(max_outstanding_r2t, max_outstanding_r2t, + ISCSI_FLASH_TGT_MAX_OUTSTANDING_R2T); +iscsi_flash_tgt_rw_attr(noop_out_interval, noop_out_interval, + ISCSI_FLASH_TGT_NOOP_OUT_INTERVAL); +iscsi_flash_tgt_rw_attr(isid, isid, ISCSI_FLASH_TGT_ISID); +iscsi_flash_tgt_rw_attr(tsid, tsid, ISCSI_FLASH_TGT_TSID); +iscsi_flash_tgt_rw_attr(max_burst_len, max_burst_length, + ISCSI_FLASH_TGT_MAX_BURST_LEN); +iscsi_flash_tgt_rw_attr(fw_cmd_timeout, firmware_cmd_timeout, + ISCSI_FLASH_TGT_FW_CMD_TIMEOUT); +iscsi_flash_tgt_rw_attr(iscsi_alias, iscsi_alias, + ISCSI_FLASH_TGT_ISCSI_ALIAS); +iscsi_flash_tgt_rw_attr(address, target_address, ISCSI_FLASH_TGT_ADDRESS); +iscsi_flash_tgt_rw_attr(name, name, ISCSI_FLASH_TGT_NAME); +iscsi_flash_tgt_rw_attr(tpgt, tpgt, ISCSI_FLASH_TGT_TPGT); +iscsi_flash_tgt_rw_attr(chap_tbl_idx, chap_tbl_idx, + ISCSI_FLASH_TGT_CHAP_TBL_IDX); +iscsi_flash_tgt_rw_attr(is_persistent, is_persistent, + ISCSI_FLASH_TGT_IS_PERSISTENT); +iscsi_flash_tgt_rw_attr(is_dirty, is_dirty, ISCSI_FLASH_TGT_IS_DIRTY); +iscsi_flash_tgt_rw_attr(login, login, ISCSI_FLASH_TGT_LOGIN); +iscsi_flash_tgt_rw_attr(logout, logout, ISCSI_FLASH_TGT_LOGOUT); +iscsi_flash_tgt_rw_attr(apply, apply, ISCSI_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_opt_auto_send_tgt_disable.attr, + &iscsi_flash_tgt_opt_discovery_sess.attr, + &iscsi_flash_tgt_opt_entry_enable.attr, + &iscsi_flash_tgt_iscsiopt_enable_hdr_digest.attr, + &iscsi_flash_tgt_iscsiopt_enable_data_digest.attr, + &iscsi_flash_tgt_iscsiopt_enable_immediate_data.attr, + &iscsi_flash_tgt_iscsiopt_enable_initial_r2t.attr, + &iscsi_flash_tgt_iscsiopt_data_seq_in_order.attr, + &iscsi_flash_tgt_iscsiopt_data_pdu_in_order.attr, + &iscsi_flash_tgt_iscsiopt_chap_auth_enable.attr, + &iscsi_flash_tgt_iscsiopt_snack_req_enable.attr, + &iscsi_flash_tgt_iscsiopt_discovery_logout_enable.attr, + &iscsi_flash_tgt_iscsiopt_bi_chap_challenge_enable.attr, + &iscsi_flash_tgt_iscsiopt_discovery_auth_opt.attr, + &iscsi_flash_tgt_tcpopt_nagle_disable.attr, + &iscsi_flash_tgt_tcpopt_timer_scale.attr, + &iscsi_flash_tgt_tcpopt_timestamp_enable.attr, + &iscsi_flash_tgt_ipopt_frag_disable.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_is_dirty.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, + ISCSI_FLASH_TGT_IP_ADDR); + else if (attr == &iscsi_flash_tgt_port.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_PORT); + else if (attr == &iscsi_flash_tgt_name.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_NAME); + else if (attr == &iscsi_flash_tgt_opt_auto_send_tgt_disable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_OPT_AUTO_SND_TGT_DISABLE); + else if (attr == &iscsi_flash_tgt_opt_discovery_sess.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_OPT_DISCOVERY_SESS); + else if (attr == &iscsi_flash_tgt_opt_entry_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_OPT_ENTRY_ENABLE); + else if (attr == &iscsi_flash_tgt_iscsiopt_enable_hdr_digest.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_HDR_DIGEST); + else if (attr == &iscsi_flash_tgt_iscsiopt_enable_data_digest.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_DATA_DIGEST); + else if (attr == &iscsi_flash_tgt_iscsiopt_enable_immediate_data.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_IMMEDIATE_DATA); + else if (attr == &iscsi_flash_tgt_iscsiopt_enable_initial_r2t.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_INITIAL_R2T); + else if (attr == &iscsi_flash_tgt_iscsiopt_data_seq_in_order.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_SEQ_IN_ORDER); + else if (attr == &iscsi_flash_tgt_iscsiopt_data_pdu_in_order.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_PDU_IN_ORDER); + else if (attr == &iscsi_flash_tgt_iscsiopt_chap_auth_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_CHAP_AUTH_ENABLE); + else if (attr == &iscsi_flash_tgt_iscsiopt_snack_req_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_SNACK_REQ_ENABLE); + else if (attr == + &iscsi_flash_tgt_iscsiopt_discovery_logout_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_LOGOUT_ENABLE); + else if (attr == + &iscsi_flash_tgt_iscsiopt_bi_chap_challenge_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_BI_CHAP_CHALLENGE_ENABLE); + else if (attr == &iscsi_flash_tgt_iscsiopt_discovery_auth_opt.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_AUTH_OPT); + else if (attr == &iscsi_flash_tgt_tcpopt_nagle_disable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_TCPOPT_NAGLE_DISABLE); + else if (attr == &iscsi_flash_tgt_tcpopt_timer_scale.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_TCPOPT_TIMER_SCALE); + else if (attr == &iscsi_flash_tgt_tcpopt_timestamp_enable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_TCPOPT_TIMESTAMP_ENABLE); + else if (attr == &iscsi_flash_tgt_ipopt_frag_disable.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_IPOPT_FRAG_DISABLE); + else if (attr == &iscsi_flash_tgt_max_recv_ds_len.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_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, + ISCSI_FLASH_TGT_MAX_XMIT_DS_LEN); + else if (attr == &iscsi_flash_tgt_first_burst_len.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_FIRST_BURST_LEN); + else if (attr == &iscsi_flash_tgt_def_time2wait.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_DEF_TIME2WAIT); + else if (attr == &iscsi_flash_tgt_def_time2retain.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_DEF_TIME2RETAIN); + else if (attr == &iscsi_flash_tgt_max_outstanding_r2t.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_MAX_OUTSTANDING_R2T); + else if (attr == &iscsi_flash_tgt_noop_out_interval.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_NOOP_OUT_INTERVAL); + else if (attr == &iscsi_flash_tgt_isid.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISID); + else if (attr == &iscsi_flash_tgt_tsid.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_TSID); + else if (attr == &iscsi_flash_tgt_max_burst_len.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_MAX_BURST_LEN); + else if (attr == &iscsi_flash_tgt_fw_cmd_timeout.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_FW_CMD_TIMEOUT); + else if (attr == &iscsi_flash_tgt_iscsi_alias.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ISCSI_ALIAS); + else if (attr == &iscsi_flash_tgt_address.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_ADDRESS); + else if (attr == &iscsi_flash_tgt_tpgt.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_TPGT); + else if (attr == &iscsi_flash_tgt_chap_tbl_idx.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_CHAP_TBL_IDX); + else if (attr == &iscsi_flash_tgt_is_persistent.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_IS_PERSISTENT); + else if (attr == &iscsi_flash_tgt_is_dirty.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_IS_DIRTY); + else if (attr == &iscsi_flash_tgt_login.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_LOGIN); + else if (attr == &iscsi_flash_tgt_logout.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_FLASH_TGT_LOGOUT); + else if (attr == &iscsi_flash_tgt_apply.attr) + return tgt_kobj->is_visible(tgt_kobj->data, + ISCSI_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)) { + tgt_kobj->release = NULL; + kobject_put(&tgt_kobj->kobj); + kfree(tgt_kobj); + tgt_kobj = NULL; + goto exit_kobj_create; + } + 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; + int ret = len; + + if (kstrtoint(buf, 10, &index)) { + ret = -EINVAL; + goto exit_del_tgt_store; + } + + found = iscsi_flash_find_tgt_kobj_by_index(&host_kobj->tgt_list, + &tgt_kobj, index); + if (!found) { + ret = -EINVAL; + goto exit_del_tgt_store; + } + + if (!host_kobj->del) { + ret = -EIO; + goto exit_del_tgt_store; + } + + host_kobj->del(tgt_kobj->data); + iscsi_flash_tgt_kobj_delete(tgt_kobj); + +exit_del_tgt_store: + return ret; +} + +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), + void (*del) (void *data)) +{ + 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; + host_kobj->del = del; + + 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), + void (*del) (void *data)) +{ + 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, del); + 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..8e2c950 --- /dev/null +++ b/include/scsi/iscsi_flash_sysfs.h @@ -0,0 +1,174 @@ +/* + * 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 { + ISCSI_FLASH_TGT_IP_ADDR, + ISCSI_FLASH_TGT_PORT, + ISCSI_FLASH_TGT_OPT_AUTO_SND_TGT_DISABLE, + ISCSI_FLASH_TGT_OPT_DISCOVERY_SESS, + ISCSI_FLASH_TGT_OPT_ENTRY_ENABLE, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_HDR_DIGEST, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_DATA_DIGEST, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_IMMEDIATE_DATA, + ISCSI_FLASH_TGT_ISCSIOPT_ENABLE_INITIAL_R2T, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_SEQ_IN_ORDER, + ISCSI_FLASH_TGT_ISCSIOPT_DATA_PDU_IN_ORDER, + ISCSI_FLASH_TGT_ISCSIOPT_CHAP_AUTH_ENABLE, + ISCSI_FLASH_TGT_ISCSIOPT_SNACK_REQ_ENABLE, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_LOGOUT_ENABLE, + ISCSI_FLASH_TGT_ISCSIOPT_BI_CHAP_CHALLENGE_ENABLE, + ISCSI_FLASH_TGT_ISCSIOPT_DISCOVERY_AUTH_OPT, + ISCSI_FLASH_TGT_TCPOPT_NAGLE_DISABLE, + ISCSI_FLASH_TGT_TCPOPT_TIMER_SCALE, + ISCSI_FLASH_TGT_TCPOPT_TIMESTAMP_ENABLE, + ISCSI_FLASH_TGT_IPOPT_FRAG_DISABLE, + ISCSI_FLASH_TGT_MAX_RECV_DS_LEN, + ISCSI_FLASH_TGT_MAX_XMIT_DS_LEN, + ISCSI_FLASH_TGT_FIRST_BURST_LEN, + ISCSI_FLASH_TGT_DEF_TIME2WAIT, + ISCSI_FLASH_TGT_DEF_TIME2RETAIN, + ISCSI_FLASH_TGT_MAX_OUTSTANDING_R2T, + ISCSI_FLASH_TGT_NOOP_OUT_INTERVAL, + ISCSI_FLASH_TGT_ISID, + ISCSI_FLASH_TGT_TSID, + ISCSI_FLASH_TGT_MAX_BURST_LEN, + ISCSI_FLASH_TGT_FW_CMD_TIMEOUT, + ISCSI_FLASH_TGT_ISCSI_ALIAS, + ISCSI_FLASH_TGT_ADDRESS, + ISCSI_FLASH_TGT_NAME, + ISCSI_FLASH_TGT_TPGT, + ISCSI_FLASH_TGT_CHAP_TBL_IDX, + ISCSI_FLASH_TGT_IS_PERSISTENT, + ISCSI_FLASH_TGT_IS_DIRTY, + ISCSI_FLASH_TGT_LOGIN, + ISCSI_FLASH_TGT_LOGOUT, + ISCSI_FLASH_TGT_APPLY, + ISCSI_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); + + /* + * Driver specific delete function + * The function should delete target + */ + void (*del) (void *data); +}; + +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), + void (*del) (void *data)); +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 [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/open-iscsi?hl=en.
