Blame 0014-From-Adheer-Chandravanshi-adheer.chandravanshi-qlogi.patch

c2d5d21
From ade9aafd7cbbd3d1543ff005290e2571f56dd964 Mon Sep 17 00:00:00 2001
c2d5d21
From: Mike Christie <michaelc@cs.wisc.edu>
c2d5d21
Date: Mon, 13 May 2013 03:15:34 -0500
c2d5d21
Subject: From: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
c2d5d21
c2d5d21
This support lets the user manage the target entries in adapter flash
c2d5d21
and
c2d5d21
perform various operations like add, delete, login, logout,
c2d5d21
and update the target information.
c2d5d21
c2d5d21
The sysfs entries will look as cited below:
c2d5d21
        /sys/bus/iscsi_flashnode/devices/flashnode_sess-<host_no>:<flashnode_id>/
c2d5d21
attrs>
c2d5d21
        /sys/bus/iscsi_flashnode/devices/flashnode_conn-<host_no>:<flashnode_id>:<conn_id>/
c2d5d21
attrs>
c2d5d21
c2d5d21
Operations using iscsiadm:
c2d5d21
=========================
c2d5d21
c2d5d21
List all target nodes stored in the FLASH of the adapter
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -o show
c2d5d21
c2d5d21
View all parameters of one particular flash node
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx> -o show
c2d5d21
c2d5d21
Update an entry and commit to adapter FLASH
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx> -n <name>
c2d5d21
-v <value> -o update
c2d5d21
c2d5d21
Multiple name, value pairs can be specified in a single command for
c2d5d21
update operation
c2d5d21
c2d5d21
Delete an entry
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx>  -o delete
c2d5d21
c2d5d21
Create a new entry
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -o new -A <ipv4/ipv6>
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx> -n <name>
c2d5d21
-v <value> -o update
c2d5d21
c2d5d21
Example, create new entry:
c2d5d21
\#iscsiadm -m host -H 7 -C flashnode -o new -A ipv4
c2d5d21
Flashnode index: 2
c2d5d21
c2d5d21
New flashnode for host7 added
c2d5d21
c2d5d21
\#iscsiadm -m host -H 7 -C flashnode -o show
c2d5d21
qla4xxx: [0] 192.168.1.12:3260,2
c2d5d21
iqn.2002-03.com.compellent:5000d310004b0716
c2d5d21
qla4xxx: [1] 192.168.1.12:3260,2
c2d5d21
qla4xxx: [2]
c2d5d21
c2d5d21
Here - The newly created entry is at flashnode_idx 2, use it to update
c2d5d21
the entry
c2d5d21
c2d5d21
\# iscsiadm -m host -H 7 -C flashnode -x 2 -o update
c2d5d21
flashnode.conn[0].ipaddress -v 192.168.1.13
c2d5d21
\#iscsiadm -m host -H 7 -C flashnode -o show
c2d5d21
qla4xxx: [0] 192.168.1.12:3260,2
c2d5d21
iqn.2002-03.com.compellent:5000d310004b0716
c2d5d21
qla4xxx: [1] 192.168.1.12:3260,2
c2d5d21
qla4xxx: [2] 192.168.1.13:3260,0
c2d5d21
c2d5d21
Login
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx>  -o login
c2d5d21
c2d5d21
Logout
c2d5d21
\# iscsiadm -m host -H hostno -C flashnode -x <flashnode_idx>  -o logout
c2d5d21
\# iscsiadm -m session -r sid -u
c2d5d21
c2d5d21
Signed-off-by: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
c2d5d21
Signed-off-by: Manish Rangankar <manish.rangankar@qlogic.com>
c2d5d21
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
c2d5d21
---
c2d5d21
 include/iscsi_if.h | 190 ++++++++++++++++-
c2d5d21
 usr/Makefile       |   2 +-
c2d5d21
 usr/flashnode.c    | 609 +++++++++++++++++++++++++++++++++++++++++++++++++++++
c2d5d21
 usr/flashnode.h    | 127 +++++++++++
c2d5d21
 usr/idbm.c         | 179 ++++++++++++++++
c2d5d21
 usr/idbm.h         |   7 +
c2d5d21
 usr/idbm_fields.h  |  63 ++++++
c2d5d21
 usr/iscsi_ipc.h    |  13 ++
c2d5d21
 usr/iscsi_sysfs.c  | 234 ++++++++++++++++++++
c2d5d21
 usr/iscsi_sysfs.h  |  17 ++
c2d5d21
 usr/iscsiadm.c     | 429 ++++++++++++++++++++++++++++++++++++-
c2d5d21
 usr/netlink.c      | 171 ++++++++++++++-
c2d5d21
 12 files changed, 2031 insertions(+), 10 deletions(-)
c2d5d21
 create mode 100644 usr/flashnode.c
c2d5d21
 create mode 100644 usr/flashnode.h
c2d5d21
c2d5d21
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
c2d5d21
index dad9fd8..20f2bc2 100644
c2d5d21
--- a/include/iscsi_if.h
c2d5d21
+++ b/include/iscsi_if.h
c2d5d21
@@ -68,8 +68,14 @@ enum iscsi_uevent_e {
c2d5d21
 	ISCSI_UEVENT_PING		= UEVENT_BASE + 22,
c2d5d21
 	ISCSI_UEVENT_GET_CHAP		= UEVENT_BASE + 23,
c2d5d21
 	ISCSI_UEVENT_DELETE_CHAP	= UEVENT_BASE + 24,
c2d5d21
+	ISCSI_UEVENT_SET_FLASHNODE_PARAMS	= UEVENT_BASE + 25,
c2d5d21
+	ISCSI_UEVENT_NEW_FLASHNODE	= UEVENT_BASE + 26,
c2d5d21
+	ISCSI_UEVENT_DEL_FLASHNODE	= UEVENT_BASE + 27,
c2d5d21
+	ISCSI_UEVENT_LOGIN_FLASHNODE	= UEVENT_BASE + 28,
c2d5d21
+	ISCSI_UEVENT_LOGOUT_FLASHNODE	= UEVENT_BASE + 29,
c2d5d21
+	ISCSI_UEVENT_LOGOUT_FLASHNODE_SID	= UEVENT_BASE + 30,
c2d5d21
 
c2d5d21
-	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_DELETE_CHAP,
c2d5d21
+	ISCSI_UEVENT_MAX		= ISCSI_UEVENT_LOGOUT_FLASHNODE_SID,
c2d5d21
 
c2d5d21
 	/* up events */
c2d5d21
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
c2d5d21
@@ -219,6 +225,31 @@ struct iscsi_uevent {
c2d5d21
 			uint32_t	host_no;
c2d5d21
 			uint16_t	chap_tbl_idx;
c2d5d21
 		} delete_chap;
c2d5d21
+		struct msg_set_flashnode_param {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	flashnode_idx;
c2d5d21
+			uint32_t	count;
c2d5d21
+		} set_flashnode;
c2d5d21
+		struct msg_new_flashnode {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	len;
c2d5d21
+		} new_flashnode;
c2d5d21
+		struct msg_del_flashnode {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	flashnode_idx;
c2d5d21
+		} del_flashnode;
c2d5d21
+		struct msg_login_flashnode {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	flashnode_idx;
c2d5d21
+		} login_flashnode;
c2d5d21
+		struct msg_logout_flashnode {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	flashnode_idx;
c2d5d21
+		} logout_flashnode;
c2d5d21
+		struct msg_logout_flashnode_sid {
c2d5d21
+			uint32_t	host_no;
c2d5d21
+			uint32_t	sid;
c2d5d21
+		} logout_flashnode_sid;
c2d5d21
 	} u;
c2d5d21
 	union {
c2d5d21
 		/* messages k -> u */
c2d5d21
@@ -276,6 +307,9 @@ struct iscsi_uevent {
c2d5d21
 						   with each ping request */
c2d5d21
 			uint32_t	data_size;
c2d5d21
 		} ping_comp;
c2d5d21
+		struct msg_new_flashnode_ret {
c2d5d21
+			uint32_t	flashnode_idx;
c2d5d21
+		} new_flashnode_ret;
c2d5d21
 	} r;
c2d5d21
 } __attribute__ ((aligned (sizeof(uint64_t))));
c2d5d21
 
c2d5d21
@@ -283,6 +317,7 @@ enum iscsi_param_type {
c2d5d21
 	ISCSI_PARAM,		/* iscsi_param (session, conn, target, LU) */
c2d5d21
 	ISCSI_HOST_PARAM,	/* iscsi_host_param */
c2d5d21
 	ISCSI_NET_PARAM,	/* iscsi_net_param */
c2d5d21
+	ISCSI_FLASHNODE_PARAM,	/* iscsi_flashnode_param */
c2d5d21
 };
c2d5d21
 
c2d5d21
 struct iscsi_iface_param_info {
c2d5d21
@@ -502,6 +537,159 @@ enum iscsi_param {
c2d5d21
 #define ISCSI_TGT_RESET_TMO		(1ULL << ISCSI_PARAM_TGT_RESET_TMO)
c2d5d21
 #define ISCSI_TARGET_ALIAS		(1ULL << ISCSI_PARAM_TARGET_ALIAS)
c2d5d21
 
c2d5d21
+/* iSCSI Flash Target params */
c2d5d21
+enum iscsi_flashnode_param {
c2d5d21
+	ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
c2d5d21
+	ISCSI_FLASHNODE_PORTAL_TYPE,
c2d5d21
+	ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
c2d5d21
+	ISCSI_FLASHNODE_DISCOVERY_SESS,
c2d5d21
+	ISCSI_FLASHNODE_ENTRY_EN,
c2d5d21
+	ISCSI_FLASHNODE_HDR_DGST_EN,
c2d5d21
+	ISCSI_FLASHNODE_DATA_DGST_EN,
c2d5d21
+	ISCSI_FLASHNODE_IMM_DATA_EN,
c2d5d21
+	ISCSI_FLASHNODE_INITIAL_R2T_EN,
c2d5d21
+	ISCSI_FLASHNODE_DATASEQ_INORDER,
c2d5d21
+	ISCSI_FLASHNODE_PDU_INORDER,
c2d5d21
+	ISCSI_FLASHNODE_CHAP_AUTH_EN,
c2d5d21
+	ISCSI_FLASHNODE_SNACK_REQ_EN,
c2d5d21
+	ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
c2d5d21
+	ISCSI_FLASHNODE_BIDI_CHAP_EN,
c2d5d21
+	/* make authentication for discovery sessions optional */
c2d5d21
+	ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
c2d5d21
+	ISCSI_FLASHNODE_ERL,
c2d5d21
+	ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
c2d5d21
+	ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
c2d5d21
+	ISCSI_FLASHNODE_TCP_WSF_DISABLE,
c2d5d21
+	ISCSI_FLASHNODE_TCP_TIMER_SCALE,
c2d5d21
+	ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
c2d5d21
+	ISCSI_FLASHNODE_IP_FRAG_DISABLE,
c2d5d21
+	ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
c2d5d21
+	ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
c2d5d21
+	ISCSI_FLASHNODE_FIRST_BURST,
c2d5d21
+	ISCSI_FLASHNODE_DEF_TIME2WAIT,
c2d5d21
+	ISCSI_FLASHNODE_DEF_TIME2RETAIN,
c2d5d21
+	ISCSI_FLASHNODE_MAX_R2T,
c2d5d21
+	ISCSI_FLASHNODE_KEEPALIVE_TMO,
c2d5d21
+	ISCSI_FLASHNODE_ISID,
c2d5d21
+	ISCSI_FLASHNODE_TSID,
c2d5d21
+	ISCSI_FLASHNODE_PORT,
c2d5d21
+	ISCSI_FLASHNODE_MAX_BURST,
c2d5d21
+	ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
c2d5d21
+	ISCSI_FLASHNODE_IPADDR,
c2d5d21
+	ISCSI_FLASHNODE_ALIAS,
c2d5d21
+	ISCSI_FLASHNODE_REDIRECT_IPADDR,
c2d5d21
+	ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
c2d5d21
+	ISCSI_FLASHNODE_LOCAL_PORT,
c2d5d21
+	ISCSI_FLASHNODE_IPV4_TOS,
c2d5d21
+	ISCSI_FLASHNODE_IPV6_TC,
c2d5d21
+	ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
c2d5d21
+	ISCSI_FLASHNODE_NAME,
c2d5d21
+	ISCSI_FLASHNODE_TPGT,
c2d5d21
+	ISCSI_FLASHNODE_LINK_LOCAL_IPV6,
c2d5d21
+	ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
c2d5d21
+	ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
c2d5d21
+	ISCSI_FLASHNODE_TCP_XMIT_WSF,
c2d5d21
+	ISCSI_FLASHNODE_TCP_RECV_WSF,
c2d5d21
+	ISCSI_FLASHNODE_CHAP_IN_IDX,
c2d5d21
+	ISCSI_FLASHNODE_CHAP_OUT_IDX,
c2d5d21
+	ISCSI_FLASHNODE_USERNAME,
c2d5d21
+	ISCSI_FLASHNODE_USERNAME_IN,
c2d5d21
+	ISCSI_FLASHNODE_PASSWORD,
c2d5d21
+	ISCSI_FLASHNODE_PASSWORD_IN,
c2d5d21
+	ISCSI_FLASHNODE_STATSN,
c2d5d21
+	ISCSI_FLASHNODE_EXP_STATSN,
c2d5d21
+	ISCSI_FLASHNODE_IS_BOOT_TGT,
c2d5d21
+
c2d5d21
+	ISCSI_FLASHNODE_MAX,
c2d5d21
+};
c2d5d21
+
c2d5d21
+#define ISCSI_FNODE_IS_FW_ASSIGNED_IPV6				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6)
c2d5d21
+#define ISCSI_FNODE_PORTAL_TYPE		(1ULL << ISCSI_FLASHNODE_PORTAL_TYPE)
c2d5d21
+#define ISCSI_FNODE_AUTO_SND_TGT_DISABLE			\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_OPT_AUTO_SND_TGT_DISABLE)
c2d5d21
+#define ISCSI_FNODE_DISCOVERY_SESS				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_OPT_DISCOVERY_SESS)
c2d5d21
+#define ISCSI_FNODE_ENTRY_EN		(1ULL << ISCSI_FLASHNODE_ENTRY_EN)
c2d5d21
+#define ISCSI_FNODE_HDR_DGST_EN		(1ULL << ISCSI_FLASHNODE_HDR_DGST_EN)
c2d5d21
+#define ISCSI_FNODE_DATA_DGST_EN	(1ULL << ISCSI_FLASHNODE_DATA_DGST_EN)
c2d5d21
+#define ISCSI_FNODE_IMM_DATA_EN		(1ULL << ISCSI_FLASHNODE_IMM_DATA_EN)
c2d5d21
+#define ISCSI_FNODE_INITIAL_R2T_EN	(1ULL << ISCSI_FLASHNODE_INITIAL_R2T_EN)
c2d5d21
+#define ISCSI_FNODE_DATASEQ_INORDER				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DATASEQ_INORDER)
c2d5d21
+#define ISCSI_FNODE_PDU_INORDER		(1ULL << ISCSI_FLASHNODE_PDU_INORDER)
c2d5d21
+#define ISCSI_FNODE_CHAP_AUTH_EN	(1ULL << ISCSI_FLASHNODE_CHAP_AUTH_EN)
c2d5d21
+#define ISCSI_FNODE_SNACK_REQ_EN	(1ULL << ISCSI_FLASHNODE_SNACK_REQ_EN)
c2d5d21
+#define ISCSI_FNODE_DISCOVERY_LOGOUT_EN				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN)
c2d5d21
+#define ISCSI_FNODE_BIDI_CHAP_EN	(1ULL << ISCSI_FLASHNODE_BIDI_CHAP_EN)
c2d5d21
+#define ISCSI_FNODE_DISCOVERY_AUTH_OPTIONAL			\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL)
c2d5d21
+#define ISCSI_FNODE_ERL			(1ULL << ISCSI_FLASHNODE_ERL)
c2d5d21
+#define ISCSI_FNODE_TCP_TIMESTAMP_STAT				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT)
c2d5d21
+#define ISCSI_FNODE_TCP_NAGLE_DISABLE				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_TCP_NAGLE_DISABLE)
c2d5d21
+#define ISCSI_FNODE_TCP_WSF_DISABLE				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_TCP_WSF_DISABLE)
c2d5d21
+#define ISCSI_FNODE_TCP_TIMER_SCALE				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_TCP_TIMER_SCALE)
c2d5d21
+#define ISCSI_FNODE_TCP_TIMESTAMP_ENABLE			\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_TCP_TIMESTAMP_ENABLE)
c2d5d21
+#define ISCSI_FNODE_IP_FRAG_DISABLE				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_IP_FRAG_DISABLE)
c2d5d21
+#define ISCSI_FNODE_MAX_RECV_DLENGTH				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_MAX_RECV_DLENGTH)
c2d5d21
+#define ISCSI_FNODE_MAX_XMIT_DLENGTH				\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_MAX_XMIT_DLENGTH)
c2d5d21
+#define ISCSI_FNODE_FIRST_BURST		(1ULL << ISCSI_FLASHNODE_FIRST_BURST)
c2d5d21
+#define ISCSI_FNODE_DEF_TIME2WAIT	(1ULL << ISCSI_FLASHNODE_DEF_TIME2WAIT)
c2d5d21
+#define ISCSI_FNODE_DEF_TIME2RETAIN	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DEF_TIME2RETAIN)
c2d5d21
+#define ISCSI_FNODE_MAX_R2T		(1ULL << ISCSI_FLASHNODE_MAX_R2T)
c2d5d21
+#define ISCSI_FNODE_KEEPALIVE_TMO	(1ULL << ISCSI_FLASHNODE_KEEPALIVE_TMO)
c2d5d21
+#define ISCSI_FNODE_ISID		(1ULL << ISCSI_FLASHNODE_ISID)
c2d5d21
+#define ISCSI_FNODE_TSID		(1ULL << ISCSI_FLASHNODE_TSID)
c2d5d21
+#define ISCSI_FNODE_PORT		(1ULL << ISCSI_FLASHNODE_PORT)
c2d5d21
+#define ISCSI_FNODE_MAX_BURST		(1ULL << ISCSI_FLASHNODE_MAX_BURST)
c2d5d21
+#define ISCSI_FNODE_DEF_TMF_TMO		(1ULL << ISCSI_FLASHNODE_DEF_TMF_TMO)
c2d5d21
+#define ISCSI_FNODE_IPADDR		(1ULL << ISCSI_FLASHNODE_IPADDR)
c2d5d21
+#define ISCSI_FNODE_ALIAS		(1ULL << ISCSI_FLASHNODE_ALIAS)
c2d5d21
+#define ISCSI_FNODE_REDIRECT_IPADDR	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_REDIRECT_IPADDR)
c2d5d21
+#define ISCSI_FNODE_MAX_SEGMENT_SIZE	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_MAX_SEGMENT_SIZE)
c2d5d21
+#define ISCSI_FNODE_LOCAL_PORT		(1ULL << ISCSI_FLASHNODE_LOCAL_PORT)
c2d5d21
+#define ISCSI_FNODE_IPV4_TOS		(1ULL << ISCSI_FLASHNODE_IPV4_TOS)
c2d5d21
+#define ISCSI_FNODE_IPV6_TC		(1ULL << ISCSI_FLASHNODE_IPV6_TC)
c2d5d21
+#define ISCSI_FNODE_IPV6_FLOW_LABEL	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_IPV6_FLOW_LABEL)
c2d5d21
+#define ISCSI_FNODE_NAME		(1ULL << ISCSI_FLASHNODE_NAME)
c2d5d21
+#define ISCSI_FNODE_TPGT		(1ULL << ISCSI_FLASHNODE_TPGT)
c2d5d21
+#define ISCSI_FNODE_LINK_LOCAL_IPV6	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_LINK_LOCAL_IPV6)
c2d5d21
+#define ISCSI_FNODE_DISCOVERY_PARENT_IDX	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX)
c2d5d21
+#define ISCSI_FNODE_DISCOVERY_PARENT_TYPE	\
c2d5d21
+	(1ULL << ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE)
c2d5d21
+#define ISCSI_FNODE_TCP_XMIT_WSF	(1ULL << ISCSI_FLASHNODE_TCP_XMIT_WSF)
c2d5d21
+#define ISCSI_FNODE_TCP_RECV_WSF	(1ULL << ISCSI_FLASHNODE_TCP_RECV_WSF)
c2d5d21
+#define ISCSI_FNODE_CHAP_IN_IDX		(1ULL << ISCSI_FLASHNODE_CHAP_IN_IDX)
c2d5d21
+#define ISCSI_FNODE_CHAP_OUT_IDX	(1ULL << ISCSI_FLASHNODE_CHAP_OUT_IDX)
c2d5d21
+#define ISCSI_FNODE_USERNAME		(1ULL << ISCSI_FLASHNODE_USERNAME)
c2d5d21
+#define ISCSI_FNODE_USERNAME_IN		(1ULL << ISCSI_FLASHNODE_USERNAME_IN)
c2d5d21
+#define ISCSI_FNODE_PASSWORD		(1ULL << ISCSI_FLASHNODE_PASSWORD)
c2d5d21
+#define ISCSI_FNODE_PASSWORD_IN		(1ULL << ISCSI_FLASHNODE_PASSWORD_IN)
c2d5d21
+#define ISCSI_FNODE_STATSN		(1ULL << ISCSI_FLASHNODE_STATSN)
c2d5d21
+#define ISCSI_FNODE_EXP_STATSN		(1ULL << ISCSI_FLASHNODE_EXP_STATSN)
c2d5d21
+#define ISCSI_FNODE_IS_BOOT_TGT		(1ULL << ISCSI_FLASHNODE_IS_BOOT_TGT)
c2d5d21
+
c2d5d21
+struct iscsi_flashnode_param_info {
c2d5d21
+	uint32_t len;		/* Actual length of the param */
c2d5d21
+	uint16_t param;		/* iscsi param value */
c2d5d21
+	uint8_t value[0];	/* length sized value follows */
c2d5d21
+} __attribute__((__packed__));
c2d5d21
+
c2d5d21
 /* iSCSI HBA params */
c2d5d21
 enum iscsi_host_param {
c2d5d21
 	ISCSI_HOST_PARAM_HWADDRESS,
c2d5d21
diff --git a/usr/Makefile b/usr/Makefile
c2d5d21
index 33b517c..3d8ee22 100644
c2d5d21
--- a/usr/Makefile
c2d5d21
+++ b/usr/Makefile
c2d5d21
@@ -40,7 +40,7 @@ SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o)
c2d5d21
 ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \
c2d5d21
 	sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \
c2d5d21
 	iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \
c2d5d21
-	initiator_common.o iscsi_err.o uip_mgmt_ipc.o \
c2d5d21
+	initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \
c2d5d21
 	$(IPC_OBJ)  $(SYSDEPS_SRCS)
c2d5d21
 # core initiator files
c2d5d21
 INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o
c2d5d21
diff --git a/usr/flashnode.c b/usr/flashnode.c
c2d5d21
new file mode 100644
c2d5d21
index 0000000..da1392a
c2d5d21
--- /dev/null
c2d5d21
+++ b/usr/flashnode.c
c2d5d21
@@ -0,0 +1,609 @@
c2d5d21
+/*
c2d5d21
+ * iSCSI flashnode helpers
c2d5d21
+ *
c2d5d21
+ * Copyright (C) 2013 QLogic Corporation.
c2d5d21
+ * Maintained by open-iscsi@googlegroups.com
c2d5d21
+ *
c2d5d21
+ * This program is free software; you can redistribute it and/or modify
c2d5d21
+ * it under the terms of the GNU General Public License as published
c2d5d21
+ * by the Free Software Foundation; either version 2 of the License, or
c2d5d21
+ * (at your option) any later version.
c2d5d21
+ *
c2d5d21
+ * This program is distributed in the hope that it will be useful, but
c2d5d21
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
c2d5d21
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c2d5d21
+ * General Public License for more details.
c2d5d21
+ *
c2d5d21
+ * See the file COPYING included with this distribution for more details.
c2d5d21
+ */
c2d5d21
+#include <errno.h>
c2d5d21
+#include <stdlib.h>
c2d5d21
+#include <stdio.h>
c2d5d21
+#include <unistd.h>
c2d5d21
+#include <string.h>
c2d5d21
+#include <sys/stat.h>
c2d5d21
+#include <arpa/inet.h>
c2d5d21
+
c2d5d21
+#include "log.h"
c2d5d21
+#include "idbm.h"
c2d5d21
+#include "iscsi_util.h"
c2d5d21
+#include "transport.h"
c2d5d21
+#include "iscsi_sysfs.h"
c2d5d21
+#include "list.h"
c2d5d21
+#include "sysdeps.h"
c2d5d21
+#include "idbm_fields.h"
c2d5d21
+#include "iscsi_err.h"
c2d5d21
+#include "iscsi_ipc.h"
c2d5d21
+#include "iscsi_netlink.h"
c2d5d21
+#include "flashnode.h"
c2d5d21
+#include "iscsi_settings.h"
c2d5d21
+
c2d5d21
+char key[NAME_MAXVAL];
c2d5d21
+
c2d5d21
+char *to_key(const char *fmt)
c2d5d21
+{
c2d5d21
+	int i = 0;
c2d5d21
+	memset(key, 0, sizeof(key));
c2d5d21
+	sprintf(key, fmt, i);
c2d5d21
+	return key;
c2d5d21
+}
c2d5d21
+
c2d5d21
+int flashnode_info_print_flat(void *data, struct flashnode_rec *fnode,
c2d5d21
+			      uint32_t host_no, uint32_t flashnode_idx)
c2d5d21
+{
c2d5d21
+	printf("%s: [%d] ", fnode->transport_name, flashnode_idx);
c2d5d21
+	if (!strlen((char *)fnode->conn[0].ipaddress))
c2d5d21
+		printf("%s:", UNKNOWN_VALUE);
c2d5d21
+	else if (strchr((char *)fnode->conn[0].ipaddress, '.'))
c2d5d21
+		printf("%s:", fnode->conn[0].ipaddress);
c2d5d21
+	else
c2d5d21
+		printf("[%s]:", fnode->conn[0].ipaddress);
c2d5d21
+
c2d5d21
+	if (!fnode->conn[0].port)
c2d5d21
+		printf("%s,", UNKNOWN_VALUE);
c2d5d21
+	else
c2d5d21
+		printf("%u,", fnode->conn[0].port);
c2d5d21
+
c2d5d21
+	printf("%u ", fnode->sess.tpgt);
c2d5d21
+
c2d5d21
+	if (!strlen(fnode->sess.targetname))
c2d5d21
+		printf("%s\n", UNKNOWN_VALUE);
c2d5d21
+	else
c2d5d21
+		printf("%s\n", fnode->sess.targetname);
c2d5d21
+
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_isid(struct flashnode_rec *fnode, struct iovec *iov)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+	uint8_t isid[6];
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 6;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(ISCSI_FLASHNODE_ISID, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = ISCSI_FLASHNODE_ISID;
c2d5d21
+	fnode_param->len = 6;
c2d5d21
+
c2d5d21
+	sscanf(fnode->sess.isid, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
c2d5d21
+	       &isid[0], &isid[1], &isid[2], &isid[3], &isid[4], &isid[5]);
c2d5d21
+
c2d5d21
+	memcpy(fnode_param->value, isid, fnode_param->len);
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_ipv4_addr(struct flashnode_rec *fnode,
c2d5d21
+				    struct iovec *iov, int param_type)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+	int rc;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 4;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = 4;
c2d5d21
+
c2d5d21
+	switch (param_type) {
c2d5d21
+	case ISCSI_FLASHNODE_IPADDR:
c2d5d21
+		rc = inet_pton(AF_INET, (char *)fnode->conn[0].ipaddress,
c2d5d21
+			       fnode_param->value);
c2d5d21
+		break;
c2d5d21
+	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
c2d5d21
+		rc = inet_pton(AF_INET, (char *)fnode->conn[0].redirect_ipaddr,
c2d5d21
+			       fnode_param->value);
c2d5d21
+		break;
c2d5d21
+	default:
c2d5d21
+		goto free;
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	if (rc <= 0)
c2d5d21
+		goto free;
c2d5d21
+
c2d5d21
+	return 0;
c2d5d21
+
c2d5d21
+free:
c2d5d21
+	free(iov->iov_base);
c2d5d21
+	iov->iov_base = NULL;
c2d5d21
+	iov->iov_len = 0;
c2d5d21
+	return 1;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_ipv6_addr(struct flashnode_rec *fnode,
c2d5d21
+				    struct iovec *iov, int param_type)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+	int rc;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 16;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = 16;
c2d5d21
+
c2d5d21
+	switch (param_type) {
c2d5d21
+	case ISCSI_FLASHNODE_IPADDR:
c2d5d21
+		rc = inet_pton(AF_INET6, (char *)fnode->conn[0].ipaddress,
c2d5d21
+			       fnode_param->value);
c2d5d21
+		break;
c2d5d21
+	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
c2d5d21
+		rc = inet_pton(AF_INET6, (char *)fnode->conn[0].redirect_ipaddr,
c2d5d21
+			       fnode_param->value);
c2d5d21
+		break;
c2d5d21
+	case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
c2d5d21
+		rc = inet_pton(AF_INET6, (char *)fnode->conn[0].link_local_ipv6,
c2d5d21
+			       fnode_param->value);
c2d5d21
+		break;
c2d5d21
+	default:
c2d5d21
+		goto free;
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	if (rc <= 0)
c2d5d21
+		goto free;
c2d5d21
+
c2d5d21
+	return 0;
c2d5d21
+
c2d5d21
+free:
c2d5d21
+	free(iov->iov_base);
c2d5d21
+	iov->iov_base = NULL;
c2d5d21
+	iov->iov_len = 0;
c2d5d21
+	return 1;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_ipaddr(struct flashnode_rec *fnode, struct iovec *iov,
c2d5d21
+				 int param_type)
c2d5d21
+{
c2d5d21
+	int rc = 0;
c2d5d21
+
c2d5d21
+	if (!strncmp(fnode->sess.portal_type, "ipv4", 4))
c2d5d21
+		rc = flashnode_fill_ipv4_addr(fnode, iov, param_type);
c2d5d21
+	else
c2d5d21
+		rc = flashnode_fill_ipv6_addr(fnode, iov, param_type);
c2d5d21
+
c2d5d21
+	return rc;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_uint8(struct flashnode_rec *fnode, struct iovec *iov,
c2d5d21
+				int param_type, uint8_t val)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 1;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = 1;
c2d5d21
+	fnode_param->value[0] = val;
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_uint16(struct flashnode_rec *fnode, struct iovec *iov,
c2d5d21
+				 int param_type, uint16_t val)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 2;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = 2;
c2d5d21
+	memcpy(fnode_param->value, &val, fnode_param->len);
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_uint32(struct flashnode_rec *fnode, struct iovec *iov,
c2d5d21
+				 int param_type, uint32_t val)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + 4;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = 4;
c2d5d21
+	memcpy(fnode_param->value, &val, fnode_param->len);
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int flashnode_fill_str(struct flashnode_rec *fnode, struct iovec *iov,
c2d5d21
+			      int param_type, char *buf, int buflen)
c2d5d21
+{
c2d5d21
+	struct iscsi_flashnode_param_info *fnode_param;
c2d5d21
+	struct nlattr *attr;
c2d5d21
+	int len;
c2d5d21
+
c2d5d21
+	len = sizeof(struct iscsi_flashnode_param_info) + buflen;
c2d5d21
+	iov->iov_base = iscsi_nla_alloc(param_type, len);
c2d5d21
+	if (!iov->iov_base)
c2d5d21
+		return 1;
c2d5d21
+
c2d5d21
+	attr = iov->iov_base;
c2d5d21
+	iov->iov_len = NLA_ALIGN(attr->nla_len);
c2d5d21
+
c2d5d21
+	fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
c2d5d21
+	fnode_param->param = param_type;
c2d5d21
+	fnode_param->len = buflen;
c2d5d21
+	memcpy(fnode_param->value, buf, fnode_param->len);
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
+int flashnode_build_config(struct list_head *params,
c2d5d21
+			   struct flashnode_rec *fnode, struct iovec *iovs)
c2d5d21
+{
c2d5d21
+	struct user_param *param;
c2d5d21
+	struct iovec *iov = NULL;
c2d5d21
+	int count = 0;
c2d5d21
+	int port = 3260;
c2d5d21
+
c2d5d21
+	/* start at 2, because 0 is for nlmsghdr and 1 for event */
c2d5d21
+	iov = iovs + 2;
c2d5d21
+
c2d5d21
+	list_for_each_entry(param, params, list) {
c2d5d21
+		if (!strcmp(param->name, FLASHNODE_SESS_AUTO_SND_TGT_DISABLE)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
c2d5d21
+			    fnode->sess.auto_snd_tgt_disable))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				   FLASHNODE_SESS_DISCOVERY_SESS)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DISCOVERY_SESS,
c2d5d21
+			    fnode->sess.discovery_session))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_ENTRY_EN)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_ENTRY_EN,
c2d5d21
+			    fnode->sess.entry_enable))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_IMM_DATA_EN)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IMM_DATA_EN,
c2d5d21
+			    fnode->sess.immediate_data))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				   FLASHNODE_SESS_INITIAL_R2T_EN)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_INITIAL_R2T_EN,
c2d5d21
+			    fnode->sess.initial_r2t))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DATASEQ_INORDER)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DATASEQ_INORDER,
c2d5d21
+			    fnode->sess.data_seq_in_order))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_PDU_INORDER)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_PDU_INORDER,
c2d5d21
+			    fnode->sess.data_pdu_in_order))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_CHAP_AUTH_EN)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_CHAP_AUTH_EN,
c2d5d21
+			    fnode->sess.chap_auth_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DISCOVERY_LOGOUT_EN)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
c2d5d21
+			    fnode->sess.discovery_logout_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_BIDI_CHAP_EN )) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_BIDI_CHAP_EN,
c2d5d21
+			    fnode->sess.bidi_chap_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
c2d5d21
+			    fnode->sess.discovery_auth_optional))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_ERL)) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_ERL,
c2d5d21
+			    fnode->sess.erl))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DEF_TIME2WAIT)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DEF_TIME2WAIT,
c2d5d21
+			    fnode->sess.def_time2wait))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DEF_TIME2RETAIN)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DEF_TIME2RETAIN,
c2d5d21
+			    fnode->sess.def_time2retain))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_MAX_R2T)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_MAX_R2T,
c2d5d21
+			    fnode->sess.max_outstanding_r2t))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_TSID)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TSID,
c2d5d21
+			    fnode->sess.tsid))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_MAX_BURST)) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_MAX_BURST,
c2d5d21
+			    fnode->sess.max_burst_len))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+				  FLASHNODE_SESS_DEF_TASKMGMT_TMO)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
c2d5d21
+			    fnode->sess.def_taskmgmt_tmo))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_NAME)) {
c2d5d21
+			if (!flashnode_fill_str(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_NAME,
c2d5d21
+			    fnode->sess.targetname,
c2d5d21
+			    sizeof(fnode->sess.targetname)))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_FIRST_BURST)) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_FIRST_BURST,
c2d5d21
+			    fnode->sess.first_burst_len))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_ISID)) {
c2d5d21
+			if (!flashnode_fill_isid(fnode, &iov[count]))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_ALIAS)) {
c2d5d21
+			if (!flashnode_fill_str(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_ALIAS,
c2d5d21
+			    fnode->sess.targetalias,
c2d5d21
+			    sizeof(fnode->sess.targetalias)))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_TPGT)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TPGT,
c2d5d21
+			    fnode->sess.tpgt))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  FLASHNODE_SESS_DISCOVERY_PARENT_IDX)) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
c2d5d21
+			    fnode->sess.discovery_parent_idx))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  FLASHNODE_SESS_DISCOVERY_PARENT_TYPE)) {
c2d5d21
+			if (!flashnode_fill_str(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
c2d5d21
+			    fnode->sess.discovery_parent_type,
c2d5d21
+			    sizeof(fnode->sess.discovery_parent_type)))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, FLASHNODE_SESS_PORTAL_TYPE)) {
c2d5d21
+			if (!flashnode_fill_str(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_PORTAL_TYPE,
c2d5d21
+			    fnode->sess.portal_type,
c2d5d21
+			    sizeof(fnode->sess.portal_type)))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name, to_key(FLASHNODE_CONN_PORT))) {
c2d5d21
+			if (fnode->conn[0].port)
c2d5d21
+				port = fnode->conn[0].port;
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_PORT, port))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IPADDR))) {
c2d5d21
+			if (!flashnode_fill_ipaddr(fnode, &iov[count],
c2d5d21
+						   ISCSI_FLASHNODE_IPADDR))
c2d5d21
+					count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_MAX_RECV_DLENGTH))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
c2d5d21
+			    fnode->conn[0].max_recv_dlength))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
c2d5d21
+			    fnode->conn[0].is_fw_assigned_ipv6))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_HDR_DGST_EN))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_HDR_DGST_EN,
c2d5d21
+			    fnode->conn[0].header_digest_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_DATA_DGST_EN))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_DATA_DGST_EN,
c2d5d21
+			    fnode->conn[0].data_digest_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_SNACK_REQ_EN))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_SNACK_REQ_EN,
c2d5d21
+			    fnode->conn[0].snack_req_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_TIMESTAMP_STAT))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
c2d5d21
+			    fnode->conn[0].tcp_timestamp_stat))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_NAGLE_DISABLE))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
c2d5d21
+			    fnode->conn[0].tcp_nagle_disable))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_WSF_DISABLE))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_WSF_DISABLE,
c2d5d21
+			    fnode->conn[0].tcp_wsf_disable))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_TIMER_SCALE))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_TIMER_SCALE,
c2d5d21
+			    fnode->conn[0].tcp_timer_scale))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_TIMESTAMP_EN))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
c2d5d21
+			    fnode->conn[0].tcp_timestamp_en))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IP_FRAG_DISABLE))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IP_FRAG_DISABLE,
c2d5d21
+			    fnode->conn[0].fragment_disable))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_MAX_XMIT_DLENGTH))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
c2d5d21
+			    fnode->conn[0].max_xmit_dlength))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_KEEPALIVE_TMO))) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_KEEPALIVE_TMO,
c2d5d21
+			    fnode->conn[0].keepalive_tmo))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_REDIRECT_IPADDR))) {
c2d5d21
+			if (!flashnode_fill_ipaddr(fnode, &iov[count],
c2d5d21
+					ISCSI_FLASHNODE_REDIRECT_IPADDR))
c2d5d21
+					count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_MAX_SEGMENT_SIZE))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
c2d5d21
+			    fnode->conn[0].max_segment_size))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_LOCAL_PORT))) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_LOCAL_PORT,
c2d5d21
+			    fnode->conn[0].local_port))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IPV4_TOS))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IPV4_TOS,
c2d5d21
+			    fnode->conn[0].ipv4_tos))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IPV6_TC))) {
c2d5d21
+			if (!flashnode_fill_uint8(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IPV6_TC,
c2d5d21
+			    fnode->conn[0].ipv6_traffic_class))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_IPV6_FLOW_LABEL))) {
c2d5d21
+			if (!flashnode_fill_uint16(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
c2d5d21
+			    fnode->conn[0].ipv6_flow_lbl))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_LINK_LOCAL_IPV6))) {
c2d5d21
+			if (!flashnode_fill_ipv6_addr(fnode, &iov[count],
c2d5d21
+					ISCSI_FLASHNODE_LINK_LOCAL_IPV6))
c2d5d21
+					count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_XMIT_WSF))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_XMIT_WSF,
c2d5d21
+			    fnode->conn[0].tcp_xmit_wsf))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_TCP_RECV_WSF))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_TCP_RECV_WSF,
c2d5d21
+			    fnode->conn[0].tcp_recv_wsf))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_STATSN))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_STATSN,
c2d5d21
+			    fnode->conn[0].stat_sn))
c2d5d21
+				count++;
c2d5d21
+		} else if (!strcmp(param->name,
c2d5d21
+			  to_key(FLASHNODE_CONN_EXP_STATSN))) {
c2d5d21
+			if (!flashnode_fill_uint32(fnode, &iov[count],
c2d5d21
+			    ISCSI_FLASHNODE_EXP_STATSN,
c2d5d21
+			    fnode->conn[0].exp_stat_sn))
c2d5d21
+				count++;
c2d5d21
+		}
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	return count;
c2d5d21
+}
c2d5d21
diff --git a/usr/flashnode.h b/usr/flashnode.h
c2d5d21
new file mode 100644
c2d5d21
index 0000000..c1de9cc
c2d5d21
--- /dev/null
c2d5d21
+++ b/usr/flashnode.h
c2d5d21
@@ -0,0 +1,127 @@
c2d5d21
+/*
c2d5d21
+ * iSCSI flashnode helpers
c2d5d21
+ *
c2d5d21
+ * Copyright (C) 2013 QLogic Corporation.
c2d5d21
+ * Maintained by open-iscsi@googlegroups.com
c2d5d21
+ *
c2d5d21
+ * This program is free software; you can redistribute it and/or modify
c2d5d21
+ * it under the terms of the GNU General Public License as published
c2d5d21
+ * by the Free Software Foundation; either version 2 of the License, or
c2d5d21
+ * (at your option) any later version.
c2d5d21
+ *
c2d5d21
+ * This program is distributed in the hope that it will be useful, but
c2d5d21
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
c2d5d21
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c2d5d21
+ * General Public License for more details.
c2d5d21
+ *
c2d5d21
+ * See the file COPYING included with this distribution for more details.
c2d5d21
+ */
c2d5d21
+#ifndef FLASHNODE_H
c2d5d21
+#define FLASHNODE_H
c2d5d21
+#include <sys/types.h>
c2d5d21
+#include <netdb.h>
c2d5d21
+#include <net/if.h>
c2d5d21
+
c2d5d21
+#include "types.h"
c2d5d21
+#include "config.h"
c2d5d21
+#include "auth.h"
c2d5d21
+
c2d5d21
+typedef enum portal_type {
c2d5d21
+	IPV4,
c2d5d21
+	IPV6,
c2d5d21
+} portal_type_e;
c2d5d21
+
c2d5d21
+typedef struct flashnode_sess_rec {
c2d5d21
+	char			targetname[TARGET_NAME_MAXLEN];
c2d5d21
+	char			targetalias[TARGET_NAME_MAXLEN];
c2d5d21
+	char			username[AUTH_STR_MAX_LEN];
c2d5d21
+	char			username_in[AUTH_STR_MAX_LEN];
c2d5d21
+	char			password[AUTH_STR_MAX_LEN];
c2d5d21
+	char			password_in[AUTH_STR_MAX_LEN];
c2d5d21
+	/* indicates if discovery was done through iSNS discovery service
c2d5d21
+	 * or through sendTarget */
c2d5d21
+	char			discovery_parent_type[ISCSI_MAX_STR_LEN];
c2d5d21
+	char			isid[16];
c2d5d21
+	char			portal_type[5]; /* ipv4 or ipv6 */
c2d5d21
+	unsigned		first_burst_len;
c2d5d21
+	unsigned		max_burst_len;
c2d5d21
+	uint16_t		def_time2wait;
c2d5d21
+	uint16_t		def_time2retain;
c2d5d21
+	uint16_t		max_outstanding_r2t;
c2d5d21
+	uint16_t		tsid;
c2d5d21
+	uint16_t		def_taskmgmt_tmo;
c2d5d21
+	uint16_t		tpgt;
c2d5d21
+	uint16_t		chap_out_idx;
c2d5d21
+	uint16_t		chap_in_idx;
c2d5d21
+	/* index of iSCSI discovery session if the entry is
c2d5d21
+	 * discovered by iSCSI discovery session
c2d5d21
+	 */
c2d5d21
+	uint16_t		discovery_parent_idx;
c2d5d21
+	/* Firmware auto sendtarget discovery disable */
c2d5d21
+	uint8_t			auto_snd_tgt_disable;
c2d5d21
+	uint8_t			discovery_session;
c2d5d21
+	/* indicates if this flashnode entry is enabled or disabled */
c2d5d21
+	uint8_t			entry_enable;
c2d5d21
+	uint8_t			immediate_data;
c2d5d21
+	uint8_t			initial_r2t;
c2d5d21
+	uint8_t			data_seq_in_order;
c2d5d21
+	uint8_t			data_pdu_in_order;
c2d5d21
+	uint8_t			chap_auth_en;
c2d5d21
+	/* enables firmware to auto logout the discovery session on discovery
c2d5d21
+	 * completion
c2d5d21
+	 */
c2d5d21
+	uint8_t			discovery_logout_en;
c2d5d21
+	uint8_t			bidi_chap_en;
c2d5d21
+	/* makes authentication for discovery session optional */
c2d5d21
+	uint8_t			discovery_auth_optional;
c2d5d21
+	uint8_t			erl;
c2d5d21
+	uint8_t			is_boot_target;
c2d5d21
+} flashnode_sess_rec_t;
c2d5d21
+
c2d5d21
+typedef struct flashnode_conn_rec {
c2d5d21
+	char			ipaddress[NI_MAXHOST];
c2d5d21
+	char			redirect_ipaddr[NI_MAXHOST];
c2d5d21
+	char			link_local_ipv6[NI_MAXHOST];
c2d5d21
+	unsigned		max_recv_dlength;
c2d5d21
+	unsigned		max_xmit_dlength;
c2d5d21
+	unsigned		max_segment_size;
c2d5d21
+	unsigned		tcp_xmit_wsf;
c2d5d21
+	unsigned		tcp_recv_wsf;
c2d5d21
+	uint32_t		stat_sn;
c2d5d21
+	uint32_t		exp_stat_sn;
c2d5d21
+	uint16_t		keepalive_tmo;
c2d5d21
+	uint16_t		port;
c2d5d21
+	uint16_t		local_port;
c2d5d21
+	uint16_t		ipv6_flow_lbl;
c2d5d21
+	/* Link local IPv6 address is assigned by firmware or driver */
c2d5d21
+	uint8_t			is_fw_assigned_ipv6;
c2d5d21
+	uint8_t			header_digest_en;
c2d5d21
+	uint8_t			data_digest_en;
c2d5d21
+	uint8_t			snack_req_en;
c2d5d21
+	/* tcp timestamp negotiation status */
c2d5d21
+	uint8_t			tcp_timestamp_stat;
c2d5d21
+	uint8_t			tcp_nagle_disable;
c2d5d21
+	/* tcp window scale factor */
c2d5d21
+	uint8_t			tcp_wsf_disable;
c2d5d21
+	uint8_t			tcp_timer_scale;
c2d5d21
+	uint8_t			tcp_timestamp_en;
c2d5d21
+	uint8_t			fragment_disable;
c2d5d21
+	uint8_t			ipv4_tos;
c2d5d21
+	uint8_t			ipv6_traffic_class;
c2d5d21
+} flashnode_conn_rec_t;
c2d5d21
+
c2d5d21
+struct flashnode_rec {
c2d5d21
+	struct list_head	list;
c2d5d21
+	char			transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
c2d5d21
+	flashnode_sess_rec_t	sess;
c2d5d21
+	flashnode_conn_rec_t	conn[ISCSI_CONN_MAX];
c2d5d21
+};
c2d5d21
+
c2d5d21
+extern int flashnode_info_print_flat(void *data, struct flashnode_rec *tgt,
c2d5d21
+				     uint32_t host_no, uint32_t flashnode_idx);
c2d5d21
+extern int iscsi_logout_flashnode_sid(struct iscsi_transport *t,
c2d5d21
+				      uint32_t host_no, uint32_t sid);
c2d5d21
+extern int flashnode_build_config(struct list_head *params,
c2d5d21
+				  struct flashnode_rec *flashnode,
c2d5d21
+				  struct iovec *iovs);
c2d5d21
+#endif
c2d5d21
diff --git a/usr/idbm.c b/usr/idbm.c
c2d5d21
index 4d30aa9..bc06058 100644
c2d5d21
--- a/usr/idbm.c
c2d5d21
+++ b/usr/idbm.c
c2d5d21
@@ -94,6 +94,17 @@ static struct idbm *db;
c2d5d21
 	_n++; \
c2d5d21
 } while (0)
c2d5d21
 
c2d5d21
+#define __recinfo_uint32(_key, _info, _rec, _name, _show, _n, _mod) do { \
c2d5d21
+	_info[_n].type = TYPE_UINT32; \
c2d5d21
+	strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
c2d5d21
+	snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \
c2d5d21
+	_info[_n].data = &_rec->_name; \
c2d5d21
+	_info[_n].data_len = sizeof(_rec->_name); \
c2d5d21
+	_info[_n].visible = _show; \
c2d5d21
+	_info[_n].can_modify = _mod; \
c2d5d21
+	_n++; \
c2d5d21
+} while (0)
c2d5d21
+
c2d5d21
 #define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \
c2d5d21
 	_info[_n].type = TYPE_INT_O; \
c2d5d21
 	strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
c2d5d21
@@ -469,6 +480,158 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
c2d5d21
 	}
c2d5d21
 }
c2d5d21
 
c2d5d21
+void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri)
c2d5d21
+{
c2d5d21
+	int num = 0;
c2d5d21
+	int i;
c2d5d21
+
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_AUTO_SND_TGT_DISABLE, ri, r,
c2d5d21
+			sess.auto_snd_tgt_disable, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_DISCOVERY_SESS, ri, r,
c2d5d21
+			sess.discovery_session, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_PORTAL_TYPE, ri, r, sess.portal_type,
c2d5d21
+		      IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_ENTRY_EN, ri, r,
c2d5d21
+			sess.entry_enable, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_IMM_DATA_EN, ri, r, sess.immediate_data,
c2d5d21
+			IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_INITIAL_R2T_EN, ri, r, sess.initial_r2t,
c2d5d21
+			IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_DATASEQ_INORDER, ri, r,
c2d5d21
+			sess.data_seq_in_order, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_PDU_INORDER, ri, r,
c2d5d21
+			sess.data_pdu_in_order, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_CHAP_AUTH_EN, ri, r, sess.chap_auth_en,
c2d5d21
+			IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_DISCOVERY_LOGOUT_EN, ri, r,
c2d5d21
+			sess.discovery_logout_en, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_BIDI_CHAP_EN, ri, r, sess.bidi_chap_en,
c2d5d21
+			IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL, ri, r,
c2d5d21
+			sess.discovery_auth_optional, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_ERL, ri, r, sess.erl, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint32(FLASHNODE_SESS_FIRST_BURST, ri, r,
c2d5d21
+			 sess.first_burst_len, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_DEF_TIME2WAIT, ri, r,
c2d5d21
+			 sess.def_time2wait, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_DEF_TIME2RETAIN, ri, r,
c2d5d21
+			 sess.def_time2retain, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_MAX_R2T, ri, r,
c2d5d21
+			 sess.max_outstanding_r2t, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_ISID, ri, r, sess.isid, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_TSID, ri, r, sess.tsid, IDBM_SHOW,
c2d5d21
+			 num, 1);
c2d5d21
+	__recinfo_uint32(FLASHNODE_SESS_MAX_BURST, ri, r, sess.max_burst_len,
c2d5d21
+			 IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_DEF_TASKMGMT_TMO, ri, r,
c2d5d21
+			 sess.def_taskmgmt_tmo, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_ALIAS, ri, r, sess.targetalias, IDBM_SHOW,
c2d5d21
+		      num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_NAME, ri, r, sess.targetname, IDBM_SHOW,
c2d5d21
+		      num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_DISCOVERY_PARENT_IDX, ri, r,
c2d5d21
+			 sess.discovery_parent_idx, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_DISCOVERY_PARENT_TYPE, ri, r,
c2d5d21
+		      sess.discovery_parent_type, IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_TPGT, ri, r, sess.tpgt, IDBM_SHOW,
c2d5d21
+			 num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_CHAP_OUT_IDX, ri, r, sess.chap_out_idx,
c2d5d21
+			 IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint16(FLASHNODE_SESS_CHAP_IN_IDX, ri, r, sess.chap_in_idx,
c2d5d21
+			 IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_USERNAME, ri, r, sess.username, IDBM_SHOW,
c2d5d21
+		      num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_USERNAME_IN, ri, r, sess.username_in,
c2d5d21
+		      IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_PASSWORD, ri, r, sess.password, IDBM_SHOW,
c2d5d21
+		      num, 1);
c2d5d21
+	__recinfo_str(FLASHNODE_SESS_PASSWORD_IN, ri, r, sess.password_in,
c2d5d21
+		      IDBM_SHOW, num, 1);
c2d5d21
+	__recinfo_uint8(FLASHNODE_SESS_IS_BOOT_TGT, ri, r, sess.is_boot_target,
c2d5d21
+			IDBM_SHOW, num, 1);
c2d5d21
+
c2d5d21
+	for (i = 0; i < ISCSI_CONN_MAX; i++) {
c2d5d21
+		char key[NAME_MAXVAL];
c2d5d21
+
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].is_fw_assigned_ipv6,
c2d5d21
+				IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_HDR_DGST_EN, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].header_digest_en, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_DATA_DGST_EN, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].data_digest_en, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_SNACK_REQ_EN, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].snack_req_en, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_STAT, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_stat,
c2d5d21
+				IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_NAGLE_DISABLE, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].tcp_nagle_disable,
c2d5d21
+				IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_WSF_DISABLE, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].tcp_wsf_disable, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_TIMER_SCALE, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].tcp_timer_scale, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_EN, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_en,
c2d5d21
+				IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IP_FRAG_DISABLE, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].fragment_disable, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_MAX_XMIT_DLENGTH, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].max_xmit_dlength,
c2d5d21
+				 IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_MAX_RECV_DLENGTH, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].max_recv_dlength,
c2d5d21
+				 IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_KEEPALIVE_TMO, i);
c2d5d21
+		__recinfo_uint16(key, ri, r, conn[i].keepalive_tmo, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_PORT, i);
c2d5d21
+		__recinfo_uint16(key, ri, r, conn[i].port, IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IPADDR, i);
c2d5d21
+		__recinfo_str(key, ri, r, conn[i].ipaddress, IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_REDIRECT_IPADDR, i);
c2d5d21
+		__recinfo_str(key, ri, r, conn[i].redirect_ipaddr, IDBM_SHOW,
c2d5d21
+			      num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_MAX_SEGMENT_SIZE, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].max_segment_size,
c2d5d21
+				 IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_LOCAL_PORT, i);
c2d5d21
+		__recinfo_uint16(key, ri, r, conn[i].local_port, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IPV4_TOS, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].ipv4_tos, IDBM_SHOW,
c2d5d21
+				num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IPV6_TC, i);
c2d5d21
+		__recinfo_uint8(key, ri, r, conn[i].ipv6_traffic_class,
c2d5d21
+				IDBM_SHOW, num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_IPV6_FLOW_LABEL, i);
c2d5d21
+		__recinfo_uint16(key, ri, r, conn[i].ipv6_flow_lbl, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_LINK_LOCAL_IPV6, i);
c2d5d21
+		__recinfo_str(key, ri, r, conn[i].link_local_ipv6, IDBM_SHOW,
c2d5d21
+			      num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_XMIT_WSF, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].tcp_xmit_wsf, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_TCP_RECV_WSF, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].tcp_recv_wsf, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_STATSN, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].stat_sn, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+		sprintf(key, FLASHNODE_CONN_EXP_STATSN, i);
c2d5d21
+		__recinfo_uint32(key, ri, r, conn[i].exp_stat_sn, IDBM_SHOW,
c2d5d21
+				 num, 1);
c2d5d21
+	}
c2d5d21
+}
c2d5d21
+
c2d5d21
 recinfo_t *idbm_recinfo_alloc(int max_keys)
c2d5d21
 {
c2d5d21
 	recinfo_t *info;
c2d5d21
@@ -502,6 +665,9 @@ void idbm_print(int type, void *rec, int show, FILE *f)
c2d5d21
 	case IDBM_PRINT_TYPE_HOST_CHAP:
c2d5d21
 		idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
c2d5d21
 		break;
c2d5d21
+	case IDBM_PRINT_TYPE_FLASHNODE:
c2d5d21
+		idbm_recinfo_flashnode((struct flashnode_rec *)rec, info);
c2d5d21
+		break;
c2d5d21
 	}
c2d5d21
 
c2d5d21
 	fprintf(f, "%s\n", ISCSI_BEGIN_REC);
c2d5d21
@@ -629,6 +795,13 @@ setup_passwd_len:
c2d5d21
 				*(uint16_t *)info[i].data =
c2d5d21
 					strtoul(value, NULL, 10);
c2d5d21
 				goto updated;
c2d5d21
+			} else if (info[i].type == TYPE_UINT32) {
c2d5d21
+				if (!info[i].data)
c2d5d21
+					continue;
c2d5d21
+
c2d5d21
+				*(uint32_t *)info[i].data =
c2d5d21
+					strtoul(value, NULL, 10);
c2d5d21
+				goto updated;
c2d5d21
 			} else if (info[i].type == TYPE_STR) {
c2d5d21
 				if (!info[i].data)
c2d5d21
 					continue;
c2d5d21
@@ -880,6 +1053,12 @@ int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
c2d5d21
 	return 0;
c2d5d21
 }
c2d5d21
 
c2d5d21
+int idbm_print_flashnode_info(struct flashnode_rec *fnode)
c2d5d21
+{
c2d5d21
+	idbm_print(IDBM_PRINT_TYPE_FLASHNODE, fnode, 1, stdout);
c2d5d21
+	return 0;
c2d5d21
+}
c2d5d21
+
c2d5d21
 int idbm_print_node_flat(void *data, node_rec_t *rec)
c2d5d21
 {
c2d5d21
 	if (strchr(rec->conn[0].address, '.'))
c2d5d21
diff --git a/usr/idbm.h b/usr/idbm.h
c2d5d21
index 245f046..5e4038d 100644
c2d5d21
--- a/usr/idbm.h
c2d5d21
+++ b/usr/idbm.h
c2d5d21
@@ -27,6 +27,7 @@
c2d5d21
 #include "initiator.h"
c2d5d21
 #include "config.h"
c2d5d21
 #include "list.h"
c2d5d21
+#include "flashnode.h"
c2d5d21
 
c2d5d21
 #define NODE_CONFIG_DIR		ISCSI_CONFIG_ROOT"nodes"
c2d5d21
 #define SLP_CONFIG_DIR		ISCSI_CONFIG_ROOT"slp"
c2d5d21
@@ -42,6 +43,7 @@
c2d5d21
 #define TYPE_STR	2
c2d5d21
 #define TYPE_UINT8	3
c2d5d21
 #define TYPE_UINT16	4
c2d5d21
+#define TYPE_UINT32	5
c2d5d21
 #define MAX_KEYS	256   /* number of keys total(including CNX_MAX) */
c2d5d21
 #define NAME_MAXVAL	128   /* the maximum length of key name */
c2d5d21
 #define VALUE_MAXVAL	256   /* the maximum length of 223 bytes in the RFC. */
c2d5d21
@@ -85,6 +87,7 @@ struct user_param {
c2d5d21
 	struct list_head list;
c2d5d21
 	char *name;
c2d5d21
 	char *value;
c2d5d21
+	int param;
c2d5d21
 };
c2d5d21
 
c2d5d21
 typedef int (idbm_iface_op_fn)(void *data, node_rec_t *rec);
c2d5d21
@@ -168,6 +171,7 @@ enum {
c2d5d21
 	IDBM_PRINT_TYPE_NODE,
c2d5d21
 	IDBM_PRINT_TYPE_IFACE,
c2d5d21
 	IDBM_PRINT_TYPE_HOST_CHAP,
c2d5d21
+	IDBM_PRINT_TYPE_FLASHNODE
c2d5d21
 };
c2d5d21
 
c2d5d21
 extern void idbm_print(int type, void *rec, int show, FILE *f);
c2d5d21
@@ -182,4 +186,7 @@ idbm_create_rec_from_boot_context(struct boot_context *context);
c2d5d21
 
c2d5d21
 extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
c2d5d21
 
c2d5d21
+extern int idbm_print_flashnode_info(struct flashnode_rec *target);
c2d5d21
+extern void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri);
c2d5d21
+
c2d5d21
 #endif /* IDBM_H */
c2d5d21
diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h
c2d5d21
index 358d014..179dda8 100644
c2d5d21
--- a/usr/idbm_fields.h
c2d5d21
+++ b/usr/idbm_fields.h
c2d5d21
@@ -126,4 +126,67 @@
c2d5d21
 #define HOST_AUTH_PASSWORD_IN		"host.auth.password_in"
c2d5d21
 #define HOST_AUTH_PASSWORD_IN_LEN	"host.auth.password_in_length"
c2d5d21
 
c2d5d21
+/* flash target session fields */
c2d5d21
+#define FLASHNODE_SESS_AUTO_SND_TGT_DISABLE	"flashnode.session.auto_snd_tgt_disable"
c2d5d21
+#define FLASHNODE_SESS_DISCOVERY_SESS	"flashnode.session.discovery_session"
c2d5d21
+#define FLASHNODE_SESS_PORTAL_TYPE	"flashnode.session.portal_type"
c2d5d21
+#define FLASHNODE_SESS_ENTRY_EN		"flashnode.session.entry_enable"
c2d5d21
+#define FLASHNODE_SESS_IMM_DATA_EN	"flashnode.session.immediate_data"
c2d5d21
+#define FLASHNODE_SESS_INITIAL_R2T_EN	"flashnode.session.initial_r2t"
c2d5d21
+#define FLASHNODE_SESS_DATASEQ_INORDER	"flashnode.session.data_seq_in_order"
c2d5d21
+#define FLASHNODE_SESS_PDU_INORDER	"flashnode.session.data_pdu_in_order"
c2d5d21
+#define FLASHNODE_SESS_CHAP_AUTH_EN	"flashnode.session.chap_auth_en"
c2d5d21
+#define FLASHNODE_SESS_DISCOVERY_LOGOUT_EN	"flashnode.session.discovery_logout_en"
c2d5d21
+#define FLASHNODE_SESS_BIDI_CHAP_EN	"flashnode.session.bidi_chap_en"
c2d5d21
+#define FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL	"flashnode.session.discovery_auth_optional"
c2d5d21
+#define FLASHNODE_SESS_ERL 		"flashnode.session.erl"
c2d5d21
+#define FLASHNODE_SESS_FIRST_BURST	"flashnode.session.first_burst_len"
c2d5d21
+#define FLASHNODE_SESS_DEF_TIME2WAIT	"flashnode.session.def_time2wait"
c2d5d21
+#define FLASHNODE_SESS_DEF_TIME2RETAIN	"flashnode.session.def_time2retain"
c2d5d21
+#define FLASHNODE_SESS_MAX_R2T		"flashnode.session.max_outstanding_r2t"
c2d5d21
+#define FLASHNODE_SESS_ISID		"flashnode.session.isid"
c2d5d21
+#define FLASHNODE_SESS_TSID		"flashnode.session.tsid"
c2d5d21
+#define FLASHNODE_SESS_MAX_BURST	"flashnode.session.max_burst_len"
c2d5d21
+#define FLASHNODE_SESS_DEF_TASKMGMT_TMO	"flashnode.session.def_taskmgmt_tmo"
c2d5d21
+#define FLASHNODE_SESS_ALIAS		"flashnode.session.targetalias"
c2d5d21
+#define FLASHNODE_SESS_NAME		"flashnode.session.targetname"
c2d5d21
+#define FLASHNODE_SESS_TPGT		"flashnode.session.tpgt"
c2d5d21
+#define FLASHNODE_SESS_DISCOVERY_PARENT_IDX	"flashnode.session.discovery_parent_idx"
c2d5d21
+#define FLASHNODE_SESS_DISCOVERY_PARENT_TYPE	"flashnode.session.discovery_parent_type"
c2d5d21
+#define FLASHNODE_SESS_CHAP_OUT_IDX	"flashnode.session.chap_out_idx"
c2d5d21
+#define FLASHNODE_SESS_CHAP_IN_IDX	"flashnode.session.chap_in_idx"
c2d5d21
+#define FLASHNODE_SESS_USERNAME		"flashnode.session.username"
c2d5d21
+#define FLASHNODE_SESS_USERNAME_IN	"flashnode.session.username_in"
c2d5d21
+#define FLASHNODE_SESS_PASSWORD		"flashnode.session.password"
c2d5d21
+#define FLASHNODE_SESS_PASSWORD_IN	"flashnode.session.password_in"
c2d5d21
+#define FLASHNODE_SESS_IS_BOOT_TGT	"flashnode.session.is_boot_target"
c2d5d21
+
c2d5d21
+/* flash target connection fields */
c2d5d21
+#define FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6	"flashnode.conn[%d].is_fw_assigned_ipv6"
c2d5d21
+#define FLASHNODE_CONN_HDR_DGST_EN	"flashnode.conn[%d].header_digest_en"
c2d5d21
+#define FLASHNODE_CONN_DATA_DGST_EN	"flashnode.conn[%d].data_digest_en"
c2d5d21
+#define FLASHNODE_CONN_SNACK_REQ_EN	"flashnode.conn[%d].snack_req_en"
c2d5d21
+#define FLASHNODE_CONN_TCP_TIMESTAMP_STAT	"flashnode.conn[%d].tcp_timestamp_stat"
c2d5d21
+#define FLASHNODE_CONN_TCP_NAGLE_DISABLE	"flashnode.conn[%d].tcp_nagle_disable"
c2d5d21
+#define FLASHNODE_CONN_TCP_WSF_DISABLE	"flashnode.conn[%d].tcp_wsf_disable"
c2d5d21
+#define FLASHNODE_CONN_TCP_TIMER_SCALE	"flashnode.conn[%d].tcp_timer_scale"
c2d5d21
+#define FLASHNODE_CONN_TCP_TIMESTAMP_EN	"flashnode.conn[%d].tcp_timestamp_en"
c2d5d21
+#define FLASHNODE_CONN_IP_FRAG_DISABLE	"flashnode.conn[%d].fragment_disable"
c2d5d21
+#define FLASHNODE_CONN_MAX_RECV_DLENGTH	"flashnode.conn[%d].max_recv_dlength"
c2d5d21
+#define FLASHNODE_CONN_MAX_XMIT_DLENGTH	"flashnode.conn[%d].max_xmit_dlength"
c2d5d21
+#define FLASHNODE_CONN_KEEPALIVE_TMO	"flashnode.conn[%d].keepalive_tmo"
c2d5d21
+#define FLASHNODE_CONN_PORT		"flashnode.conn[%d].port"
c2d5d21
+#define FLASHNODE_CONN_IPADDR		"flashnode.conn[%d].ipaddress"
c2d5d21
+#define FLASHNODE_CONN_REDIRECT_IPADDR	"flashnode.conn[%d].redirect_ipaddr"
c2d5d21
+#define FLASHNODE_CONN_MAX_SEGMENT_SIZE	"flashnode.conn[%d].max_segment_size"
c2d5d21
+#define FLASHNODE_CONN_LOCAL_PORT	"flashnode.conn[%d].local_port"
c2d5d21
+#define FLASHNODE_CONN_IPV4_TOS		"flashnode.conn[%d].ipv4_tos"
c2d5d21
+#define FLASHNODE_CONN_IPV6_TC		"flashnode.conn[%d].ipv6_traffic_class"
c2d5d21
+#define FLASHNODE_CONN_IPV6_FLOW_LABEL	"flashnode.conn[%d].ipv6_flow_label"
c2d5d21
+#define FLASHNODE_CONN_LINK_LOCAL_IPV6	"flashnode.conn[%d].link_local_ipv6"
c2d5d21
+#define FLASHNODE_CONN_TCP_XMIT_WSF	"flashnode.conn[%d].tcp_xmit_wsf"
c2d5d21
+#define FLASHNODE_CONN_TCP_RECV_WSF	"flashnode.conn[%d].tcp_recv_wsf"
c2d5d21
+#define FLASHNODE_CONN_STATSN		"flashnode.conn[%d].statsn"
c2d5d21
+#define FLASHNODE_CONN_EXP_STATSN	"flashnode.conn[%d].exp_statsn"
c2d5d21
+
c2d5d21
 #endif
c2d5d21
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
c2d5d21
index db5f1f0..b6665cb 100644
c2d5d21
--- a/usr/iscsi_ipc.h
c2d5d21
+++ b/usr/iscsi_ipc.h
c2d5d21
@@ -145,6 +145,19 @@ struct iscsi_ipc {
c2d5d21
 
c2d5d21
 	int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
c2d5d21
 			    uint16_t chap_tbl_idx);
c2d5d21
+	int (*set_flash_node_params) (uint64_t transport_handle,
c2d5d21
+				      uint32_t host_no, uint32_t flashnode_idx,
c2d5d21
+				      struct iovec *iovs, uint32_t param_count);
c2d5d21
+	int (*new_flash_node) (uint64_t transport_handle, uint32_t host_no,
c2d5d21
+			       void *value, uint32_t *flashnode_idx);
c2d5d21
+	int (*del_flash_node) (uint64_t transport_handle, uint32_t host_no,
c2d5d21
+			       uint32_t flashnode_idx);
c2d5d21
+	int (*login_flash_node) (uint64_t transport_handle, uint32_t host_no,
c2d5d21
+				uint32_t flashnode_idx);
c2d5d21
+	int (*logout_flash_node) (uint64_t transport_handle, uint32_t host_no,
c2d5d21
+				  uint32_t flashnode_idx);
c2d5d21
+	int (*logout_flash_node_sid) (uint64_t transport_handle,
c2d5d21
+				      uint32_t host_no, uint32_t sid);
c2d5d21
 };
c2d5d21
 
c2d5d21
 #endif /* ISCSI_IPC_H */
c2d5d21
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
c2d5d21
index 4015b35..64a4ce7 100644
c2d5d21
--- a/usr/iscsi_sysfs.c
c2d5d21
+++ b/usr/iscsi_sysfs.c
c2d5d21
@@ -29,6 +29,7 @@
c2d5d21
 #include "initiator.h"
c2d5d21
 #include "transport.h"
c2d5d21
 #include "idbm.h"
c2d5d21
+#include "idbm_fields.h"
c2d5d21
 #include "version.h"
c2d5d21
 #include "iscsi_sysfs.h"
c2d5d21
 #include "sysdeps.h"
c2d5d21
@@ -37,6 +38,7 @@
c2d5d21
 #include "session_info.h"
c2d5d21
 #include "host.h"
c2d5d21
 #include "iscsi_err.h"
c2d5d21
+#include "flashnode.h"
c2d5d21
 
c2d5d21
 /*
c2d5d21
  * TODO: remove the _DIR defines and search for subsys dirs like
c2d5d21
@@ -45,18 +47,22 @@
c2d5d21
 #define ISCSI_TRANSPORT_DIR	"/sys/class/iscsi_transport"
c2d5d21
 #define ISCSI_SESSION_DIR	"/sys/class/iscsi_session"
c2d5d21
 #define ISCSI_HOST_DIR		"/sys/class/iscsi_host"
c2d5d21
+#define ISCSI_FLASHNODE_DIR	"/sys/bus/iscsi_flashnode/devices"
c2d5d21
 
c2d5d21
 #define ISCSI_SESSION_SUBSYS		"iscsi_session"
c2d5d21
 #define ISCSI_CONN_SUBSYS		"iscsi_connection"
c2d5d21
 #define ISCSI_HOST_SUBSYS		"iscsi_host"
c2d5d21
 #define ISCSI_TRANSPORT_SUBSYS		"iscsi_transport"
c2d5d21
 #define ISCSI_IFACE_SUBSYS		"iscsi_iface"
c2d5d21
+#define ISCSI_FLASHNODE_SUBSYS		"iscsi_flashnode"
c2d5d21
 #define SCSI_HOST_SUBSYS		"scsi_host"
c2d5d21
 #define SCSI_SUBSYS			"scsi"
c2d5d21
 
c2d5d21
 #define ISCSI_SESSION_ID		"session%d"
c2d5d21
 #define ISCSI_CONN_ID			"connection%d:0"
c2d5d21
 #define ISCSI_HOST_ID			"host%d"
c2d5d21
+#define ISCSI_FLASHNODE_SESS		"flashnode_sess-%d:%d"
c2d5d21
+#define ISCSI_FLASHNODE_CONN		"flashnode_conn-%d:%d:0"
c2d5d21
 
c2d5d21
 /*
c2d5d21
  * TODO: make this into a real API and check inputs better and add doc.
c2d5d21
@@ -440,6 +446,234 @@ uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, int *rc)
c2d5d21
 }
c2d5d21
 
c2d5d21
 /*
c2d5d21
+ * Read the flash node attributes based on host and flash node index.
c2d5d21
+ */
c2d5d21
+int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode,
c2d5d21
+				   uint32_t host_no,
c2d5d21
+				   uint32_t flashnode_idx)
c2d5d21
+{
c2d5d21
+	char sess_id[NAME_SIZE] = {'\0'};
c2d5d21
+	char conn_id[NAME_SIZE] = {'\0'};
c2d5d21
+	char fnode_path[PATH_SIZE] = {'\0'};
c2d5d21
+	struct iscsi_transport *t;
c2d5d21
+	int ret = 0;
c2d5d21
+
c2d5d21
+	t = iscsi_sysfs_get_transport_by_hba(host_no);
c2d5d21
+	if (!t)
c2d5d21
+		log_debug(7, "could not get transport name for host%d",
c2d5d21
+			  host_no);
c2d5d21
+	else
c2d5d21
+		strncpy(fnode->transport_name, t->name,
c2d5d21
+			ISCSI_TRANSPORT_NAME_MAXLEN);
c2d5d21
+
c2d5d21
+	snprintf(sess_id, sizeof(sess_id), ISCSI_FLASHNODE_SESS, host_no,
c2d5d21
+		 flashnode_idx);
c2d5d21
+
c2d5d21
+	snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
c2d5d21
+		 sess_id);
c2d5d21
+	if (access(fnode_path, F_OK) != 0)
c2d5d21
+		return errno;
c2d5d21
+
c2d5d21
+	snprintf(conn_id, sizeof(conn_id), ISCSI_FLASHNODE_CONN, host_no,
c2d5d21
+		 flashnode_idx);
c2d5d21
+
c2d5d21
+	snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
c2d5d21
+		 conn_id);
c2d5d21
+	if (access(fnode_path, F_OK) != 0)
c2d5d21
+		return errno;
c2d5d21
+
c2d5d21
+
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "is_fw_assigned_ipv6",
c2d5d21
+			&((fnode->conn[0]).is_fw_assigned_ipv6));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "portal_type",
c2d5d21
+		      (fnode->sess).portal_type,
c2d5d21
+		      sizeof((fnode->sess).portal_type));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "auto_snd_tgt_disable",
c2d5d21
+			&((fnode->sess).auto_snd_tgt_disable));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_session",
c2d5d21
+			&((fnode->sess).discovery_session));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "entry_enable",
c2d5d21
+			&((fnode->sess).entry_enable));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "header_digest",
c2d5d21
+			&((fnode->conn[0]).header_digest_en));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "data_digest",
c2d5d21
+			&((fnode->conn[0]).data_digest_en));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "immediate_data",
c2d5d21
+			&((fnode->sess).immediate_data));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "initial_r2t",
c2d5d21
+			&((fnode->sess).initial_r2t));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_seq_in_order",
c2d5d21
+			&((fnode->sess).data_seq_in_order));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_pdu_in_order",
c2d5d21
+			&((fnode->sess).data_pdu_in_order));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_auth",
c2d5d21
+			&((fnode->sess).chap_auth_en));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "snack_req",
c2d5d21
+			&((fnode->conn[0]).snack_req_en));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_logout",
c2d5d21
+			&((fnode->sess).discovery_logout_en));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "bidi_chap",
c2d5d21
+			&((fnode->sess).bidi_chap_en));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS,
c2d5d21
+			"discovery_auth_optional",
c2d5d21
+			&((fnode->sess).discovery_auth_optional));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "erl",
c2d5d21
+			&((fnode->sess).erl));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_stat",
c2d5d21
+			&((fnode->conn[0]).tcp_timestamp_stat));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_nagle_disable",
c2d5d21
+			&((fnode->conn[0]).tcp_nagle_disable));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_wsf_disable",
c2d5d21
+			&((fnode->conn[0]).tcp_wsf_disable));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timer_scale",
c2d5d21
+			&((fnode->conn[0]).tcp_timer_scale));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_enable",
c2d5d21
+			&((fnode->conn[0]).tcp_timestamp_en));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "fragment_disable",
c2d5d21
+			&((fnode->conn[0]).fragment_disable));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_recv_dlength",
c2d5d21
+		       &((fnode->conn[0]).max_recv_dlength));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_xmit_dlength",
c2d5d21
+		       &((fnode->conn[0]).max_xmit_dlength));
c2d5d21
+	sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "first_burst_len",
c2d5d21
+		       &((fnode->sess).first_burst_len));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2wait",
c2d5d21
+			 &((fnode->sess).def_time2wait));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2retain",
c2d5d21
+			 &((fnode->sess).def_time2retain));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_outstanding_r2t",
c2d5d21
+			 &((fnode->sess).max_outstanding_r2t));
c2d5d21
+	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "keepalive_tmo",
c2d5d21
+			 &((fnode->conn[0]).keepalive_tmo));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "isid",
c2d5d21
+		      (fnode->sess).isid, sizeof((fnode->sess).isid));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tsid",
c2d5d21
+			 &((fnode->sess).tsid));
c2d5d21
+	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "port",
c2d5d21
+			 &((fnode->conn[0]).port));
c2d5d21
+	sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_burst_len",
c2d5d21
+		       &((fnode->sess).max_burst_len));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_taskmgmt_tmo",
c2d5d21
+			 &((fnode->sess).def_taskmgmt_tmo));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetalias",
c2d5d21
+		      (fnode->sess).targetalias,
c2d5d21
+		      sizeof((fnode->sess).targetalias));
c2d5d21
+	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipaddress",
c2d5d21
+		      (fnode->conn[0]).ipaddress,
c2d5d21
+		      sizeof((fnode->conn[0]).ipaddress));
c2d5d21
+	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "redirect_ipaddr",
c2d5d21
+		      (fnode->conn[0]).redirect_ipaddr,
c2d5d21
+		      sizeof((fnode->conn[0]).redirect_ipaddr));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_segment_size",
c2d5d21
+		       &((fnode->conn[0]).max_segment_size));
c2d5d21
+	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "local_port",
c2d5d21
+			 &((fnode->conn[0]).local_port));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv4_tos",
c2d5d21
+			&((fnode->conn[0]).ipv4_tos));
c2d5d21
+	sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_traffic_class",
c2d5d21
+			&((fnode->conn[0]).ipv6_traffic_class));
c2d5d21
+	sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_flow_label",
c2d5d21
+			 &((fnode->conn[0]).ipv6_flow_lbl));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetname",
c2d5d21
+		      (fnode->sess).targetname,
c2d5d21
+		      sizeof((fnode->sess).targetname));
c2d5d21
+	sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "link_local_ipv6",
c2d5d21
+		      (fnode->conn[0]).link_local_ipv6,
c2d5d21
+		      sizeof((fnode->conn[0]).link_local_ipv6));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS,
c2d5d21
+			 "discovery_parent_idx",
c2d5d21
+			 &((fnode->sess).discovery_parent_idx));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS,
c2d5d21
+		      "discovery_parent_type",
c2d5d21
+		      (fnode->sess).discovery_parent_type,
c2d5d21
+		      sizeof((fnode->sess).discovery_parent_type));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tpgt",
c2d5d21
+			 &((fnode->sess).tpgt));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_xmit_wsf",
c2d5d21
+		       &((fnode->conn[0]).tcp_xmit_wsf));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_recv_wsf",
c2d5d21
+		       &((fnode->conn[0]).tcp_recv_wsf));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_out_idx",
c2d5d21
+			 &((fnode->sess).chap_out_idx));
c2d5d21
+	sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_in_idx",
c2d5d21
+			 &((fnode->sess).chap_in_idx));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username",
c2d5d21
+		      (fnode->sess).username, sizeof((fnode->sess).username));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username_in",
c2d5d21
+		      (fnode->sess).username,
c2d5d21
+		      sizeof((fnode->sess).username_in));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password",
c2d5d21
+		      (fnode->sess).password, sizeof((fnode->sess).password));
c2d5d21
+	sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password_in",
c2d5d21
+		      (fnode->sess).password,
c2d5d21
+		      sizeof((fnode->sess).password_in));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "statsn",
c2d5d21
+		       &((fnode->conn[0]).stat_sn));
c2d5d21
+	sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "exp_statsn",
c2d5d21
+		       &((fnode->conn[0]).exp_stat_sn));
c2d5d21
+	sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "is_boot_target",
c2d5d21
+			&((fnode->sess).is_boot_target));
c2d5d21
+	return ret;
c2d5d21
+}
c2d5d21
+
c2d5d21
+/*
c2d5d21
+ * For each flash node of the given host, perform operation specified in fn.
c2d5d21
+ */
c2d5d21
+int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no, int *nr_found,
c2d5d21
+				   iscsi_sysfs_flashnode_op_fn *fn)
c2d5d21
+{
c2d5d21
+	struct dirent **namelist;
c2d5d21
+	int rc = 0, i, n;
c2d5d21
+	struct flashnode_rec *fnode;
c2d5d21
+	uint32_t flashnode_idx;
c2d5d21
+	uint32_t hostno;
c2d5d21
+
c2d5d21
+	fnode = malloc(sizeof(*fnode));
c2d5d21
+	if (!fnode)
c2d5d21
+		return ISCSI_ERR_NOMEM;
c2d5d21
+
c2d5d21
+	n = scandir(ISCSI_FLASHNODE_DIR, &namelist, trans_filter, alphasort);
c2d5d21
+	if (n <= 0)
c2d5d21
+		goto free_fnode;
c2d5d21
+
c2d5d21
+	for (i = 0; i < n; i++) {
c2d5d21
+		memset(fnode, 0, sizeof(*fnode));
c2d5d21
+
c2d5d21
+		if (!strncmp(namelist[i]->d_name, "flashnode_conn",
c2d5d21
+			     strlen("flashnode_conn")))
c2d5d21
+			continue;
c2d5d21
+
c2d5d21
+		if (sscanf(namelist[i]->d_name, ISCSI_FLASHNODE_SESS,
c2d5d21
+			   &hostno, &flashnode_idx) != 2) {
c2d5d21
+			log_error("Invalid iscsi target dir: %s",
c2d5d21
+				  namelist[i]->d_name);
c2d5d21
+			break;
c2d5d21
+		}
c2d5d21
+
c2d5d21
+		if (host_no != hostno)
c2d5d21
+			continue;
c2d5d21
+
c2d5d21
+		rc = iscsi_sysfs_get_flashnode_info(fnode, host_no,
c2d5d21
+						    flashnode_idx);
c2d5d21
+		if (rc)
c2d5d21
+			break;
c2d5d21
+
c2d5d21
+		rc = fn(data, fnode, host_no, flashnode_idx);
c2d5d21
+		if (rc != 0)
c2d5d21
+			break;
c2d5d21
+		(*nr_found)++;
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	for (i = 0; i < n; i++)
c2d5d21
+		free(namelist[i]);
c2d5d21
+	free(namelist);
c2d5d21
+
c2d5d21
+free_fnode:
c2d5d21
+	free(fnode);
c2d5d21
+	return rc;
c2d5d21
+}
c2d5d21
+
c2d5d21
+/*
c2d5d21
  * Read in iface settings based on host and session values. If
c2d5d21
  * session is not passed in, then the ifacename will not be set. And
c2d5d21
  * if the session is not passed in then iname will only be set for
c2d5d21
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
c2d5d21
index 2b15d78..d130d36 100644
c2d5d21
--- a/usr/iscsi_sysfs.h
c2d5d21
+++ b/usr/iscsi_sysfs.h
c2d5d21
@@ -31,6 +31,7 @@ struct iscsi_conn;
c2d5d21
 struct iscsi_session_operational_config;
c2d5d21
 struct iscsi_conn_operational_config;
c2d5d21
 struct iscsi_auth_config;
c2d5d21
+struct flashnode_rec;
c2d5d21
 
c2d5d21
 #define SCSI_MAX_STATE_VALUE 32
c2d5d21
 
c2d5d21
@@ -42,6 +43,8 @@ extern int iscsi_sysfs_session_has_leadconn(uint32_t sid);
c2d5d21
 
c2d5d21
 typedef int (iscsi_sysfs_session_op_fn)(void *, struct session_info *);
c2d5d21
 typedef int (iscsi_sysfs_host_op_fn)(void *, struct host_info *);
c2d5d21
+typedef int (iscsi_sysfs_flashnode_op_fn)(void *, struct flashnode_rec *,
c2d5d21
+					  uint32_t, uint32_t);
c2d5d21
 typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *);
c2d5d21
 
c2d5d21
 extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
c2d5d21
@@ -56,6 +59,20 @@ extern uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface,
c2d5d21
 						    int *rc);
c2d5d21
 extern uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int *rc);
c2d5d21
 extern int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo);
c2d5d21
+extern int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no,
c2d5d21
+					  int *nr_found,
c2d5d21
+					  iscsi_sysfs_flashnode_op_fn *fn);
c2d5d21
+extern int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode,
c2d5d21
+					  uint32_t host_no,
c2d5d21
+					  uint32_t flashnode_id);
c2d5d21
+extern int iscsi_sysfs_update_flashnode_param(uint32_t host_no,
c2d5d21
+					      uint32_t flashnode_id,
c2d5d21
+					      char *name, char *val);
c2d5d21
+extern int iscsi_sysfs_create_flashnode(uint32_t host_no, char *ipver);
c2d5d21
+extern int iscsi_sysfs_del_flashnode(uint32_t host_no, uint32_t flashnode_id);
c2d5d21
+extern int iscsi_sysfs_login_flashnode(uint32_t host_no, uint32_t flashnode_id);
c2d5d21
+extern int iscsi_sysfs_logout_flashnode(uint32_t host_no,
c2d5d21
+					uint32_t flashnode_id);
c2d5d21
 extern int iscsi_sysfs_get_sid_from_path(char *session);
c2d5d21
 extern char *iscsi_sysfs_get_blockdev_from_lun(int hostno, int target, int sid);
c2d5d21
 
c2d5d21
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
c2d5d21
index 8f9de05..5a18522 100644
c2d5d21
--- a/usr/iscsiadm.c
c2d5d21
+++ b/usr/iscsiadm.c
c2d5d21
@@ -53,6 +53,7 @@
c2d5d21
 #include "iscsi_err.h"
c2d5d21
 #include "iscsi_ipc.h"
c2d5d21
 #include "iscsi_timer.h"
c2d5d21
+#include "flashnode.h"
c2d5d21
 
c2d5d21
 static char program_name[] = "iscsiadm";
c2d5d21
 static char config_file[TARGET_NAME_MAXLEN];
c2d5d21
@@ -67,7 +68,8 @@ enum iscsiadm_mode {
c2d5d21
 	MODE_IFACE,
c2d5d21
 	MODE_FW,
c2d5d21
 	MODE_PING,
c2d5d21
-	MODE_CHAP
c2d5d21
+	MODE_CHAP,
c2d5d21
+	MODE_FLASHNODE
c2d5d21
 };
c2d5d21
 
c2d5d21
 enum iscsiadm_op {
c2d5d21
@@ -78,7 +80,9 @@ enum iscsiadm_op {
c2d5d21
 	OP_SHOW			= 0x8,
c2d5d21
 	OP_NONPERSISTENT	= 0x10,
c2d5d21
 	OP_APPLY		= 0x20,
c2d5d21
-	OP_APPLY_ALL		= 0x40
c2d5d21
+	OP_APPLY_ALL		= 0x40,
c2d5d21
+	OP_LOGIN		= 0x80,
c2d5d21
+	OP_LOGOUT		= 0x100
c2d5d21
 };
c2d5d21
 
c2d5d21
 static struct option const long_options[] =
c2d5d21
@@ -111,9 +115,11 @@ static struct option const long_options[] =
c2d5d21
 	{"packetsize", required_argument, NULL, 'b'},
c2d5d21
 	{"count", required_argument, NULL, 'c'},
c2d5d21
 	{"interval", required_argument, NULL, 'i'},
c2d5d21
+	{"flashnode_idx", optional_argument, NULL, 'x'},
c2d5d21
+	{"portal_type", optional_argument, NULL, 'A'},
c2d5d21
 	{NULL, 0, NULL, 0},
c2d5d21
 };
c2d5d21
-static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:u";
c2d5d21
+static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:";
c2d5d21
 
c2d5d21
 static void usage(int status)
c2d5d21
 {
c2d5d21
@@ -130,7 +136,7 @@ iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,au
c2d5d21
 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P  printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
c2d5d21
 iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o  operation  ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\
c2d5d21
 iscsiadm -m fw [ -l ]\n\
c2d5d21
-iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ]\n\
c2d5d21
+iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ] | [ -C flashnode [ -o operation ] [ -A portal_type ] [ -x flashnode_idx ] [ -n name ] [ -v value ] ] ]\n\
c2d5d21
 iscsiadm -k priority\n");
c2d5d21
 	}
c2d5d21
 	exit(status);
c2d5d21
@@ -155,6 +161,10 @@ str_to_op(char *str)
c2d5d21
 		op = OP_APPLY;
c2d5d21
 	else if (!strcmp("applyall", str))
c2d5d21
 		op = OP_APPLY_ALL;
c2d5d21
+	else if (!strcmp("login", str))
c2d5d21
+		op = OP_LOGIN;
c2d5d21
+	else if (!strcmp("logout", str))
c2d5d21
+		op = OP_LOGOUT;
c2d5d21
 	else
c2d5d21
 		op = OP_NOOP;
c2d5d21
 
c2d5d21
@@ -195,6 +205,8 @@ str_to_submode(char *str)
c2d5d21
 		sub_mode = MODE_PING;
c2d5d21
 	else if (!strcmp("chap", str))
c2d5d21
 		sub_mode = MODE_CHAP;
c2d5d21
+	else if (!strcmp("flashnode", str))
c2d5d21
+		sub_mode = MODE_FLASHNODE;
c2d5d21
 	else
c2d5d21
 		sub_mode = -1;
c2d5d21
 
c2d5d21
@@ -221,6 +233,21 @@ str_to_type(char *str)
c2d5d21
 	return type;
c2d5d21
 }
c2d5d21
 
c2d5d21
+static int
c2d5d21
+str_to_portal_type(char *str)
c2d5d21
+{
c2d5d21
+	int ptype;
c2d5d21
+
c2d5d21
+	if (!strcmp("ipv4", str))
c2d5d21
+		ptype = IPV4;
c2d5d21
+	else if (!strcmp("ipv6", str))
c2d5d21
+		ptype = IPV6;
c2d5d21
+	else
c2d5d21
+		ptype = -1;
c2d5d21
+
c2d5d21
+	return ptype;
c2d5d21
+}
c2d5d21
+
c2d5d21
 static void kill_iscsid(int priority)
c2d5d21
 {
c2d5d21
 	iscsiadm_req_t req;
c2d5d21
@@ -582,6 +609,8 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list,
c2d5d21
 {
c2d5d21
 	struct node_rec *pattern_rec = data;
c2d5d21
 	struct iscsi_transport *t;
c2d5d21
+	uint32_t host_no;
c2d5d21
+	int rc = 0;
c2d5d21
 
c2d5d21
 	t = iscsi_sysfs_get_transport_by_sid(info->sid);
c2d5d21
 	if (!t)
c2d5d21
@@ -590,7 +619,19 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list,
c2d5d21
 	if (!iscsi_match_session(pattern_rec, info))
c2d5d21
 		return -1;
c2d5d21
 
c2d5d21
-	return iscsi_logout_portal(info, list);
c2d5d21
+	host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &rc);
c2d5d21
+	if (rc) {
c2d5d21
+		log_error("could not get host_no for session%d: %s.",
c2d5d21
+			  info->sid, iscsi_err_to_str(rc));
c2d5d21
+		return -1;
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	if (!iscsi_sysfs_session_user_created(info->sid))
c2d5d21
+		rc = iscsi_logout_flashnode_sid(t, host_no, info->sid);
c2d5d21
+	else
c2d5d21
+		rc = iscsi_logout_portal(info, list);
c2d5d21
+
c2d5d21
+	return rc;
c2d5d21
 }
c2d5d21
 
c2d5d21
 static int rec_match_fn(void *data, node_rec_t *rec)
c2d5d21
@@ -1438,6 +1479,360 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
c2d5d21
 	return rc;
c2d5d21
 }
c2d5d21
 
c2d5d21
+static int get_flashnode_info(uint32_t host_no, uint32_t flashnode_idx)
c2d5d21
+{
c2d5d21
+	struct flashnode_rec fnode;
c2d5d21
+	int rc = 0;
c2d5d21
+
c2d5d21
+	memset(&fnode, 0, sizeof(fnode));
c2d5d21
+	rc = iscsi_sysfs_get_flashnode_info(&fnode, host_no, flashnode_idx);
c2d5d21
+	if (rc) {
c2d5d21
+		log_error("Could not read info for flashnode %u of host %u, %s",
c2d5d21
+			  flashnode_idx, host_no, strerror(rc));
c2d5d21
+		return rc;
c2d5d21
+	}
c2d5d21
+
c2d5d21
+	idbm_print_flashnode_info(&fnode);
c2d5d21
+	return rc;
c2d5d21
+}
c2d5d21
+
c2d5d21
+static int list_flashnodes(int info_level, uint32_t host_no)
c2d5d21
+{
c2d5d21
+	int rc = 0;
c2d5d21
+	int num_found = 0;
c2d5d21
+
c2d5d21
+	rc = iscsi_sysfs_for_each_flashnode(NULL, host_no, &num_found,
c2d5d21
+					    flashnode_info_print_flat);
c2d5d21
+
c2d5d21
+	if (!num_found) {
c2d5d21
+		log_error("No flashnodes attached to host %u.", host_no);