From: Adheer Chandravanshi <[email protected]>

This support lets the user manage the target entries in adapter flash and
perform various operations like add, delete, login, logout,
and update the target information.

Example:

The target information from flash would appear in sysfs as:

/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_address
/sys/firmware/iscsi_offload/host1/tgt0/default_time2retain
/sys/firmware/iscsi_offload/host1/tgt0/default_time2wait
/sys/firmware/iscsi_offload/host1/tgt0/firmware_cmd_timeout
/sys/firmware/iscsi_offload/host1/tgt0/first_burst_length
/sys/firmware/iscsi_offload/host1/tgt0/ipaddress
/sys/firmware/iscsi_offload/host1/tgt0/ip_options
/sys/firmware/iscsi_offload/host1/tgt0/iscsi_alias
/sys/firmware/iscsi_offload/host1/tgt0/iscsi_options
/sys/firmware/iscsi_offload/host1/tgt0/isid
/sys/firmware/iscsi_offload/host1/tgt0/is_persistent
/sys/firmware/iscsi_offload/host1/tgt0/max_burst_length
/sys/firmware/iscsi_offload/host1/tgt0/max_outstanding_r2t
/sys/firmware/iscsi_offload/host1/tgt0/max_recv_data_segment_length
/sys/firmware/iscsi_offload/host1/tgt0/max_xmit_data_segment_length
/sys/firmware/iscsi_offload/host1/tgt0/name
/sys/firmware/iscsi_offload/host1/tgt0/noop_out_interval
/sys/firmware/iscsi_offload/host1/tgt0/port
/sys/firmware/iscsi_offload/host1/tgt0/target_options
/sys/firmware/iscsi_offload/host1/tgt0/tcp_options
/sys/firmware/iscsi_offload/host1/tgt0/tpgt
/sys/firmware/iscsi_offload/host1/tgt0/tsid

Operations using iscsiadm:
=========================

List all targets stored in the FLASH of the adapter

\# iscsiadm -m host -H hostno -C flash_target -o show
 qla4xxx: [0] 192.168.1.12:3260,2 iqn.1992-04.com.emc:cx.ckm00101200392.b2
 qla4xxx: [1] 192.168.1.12:3260,2  << Send target entry.

\# iscsiadm -m host -H hostno -C flash_target -x <target_idx> -o show
\# BEGIN RECORD 2.0-873
ipaddress = 192.168.1.11
name = iqn.1992-04.com.emc:cx.ckm00101200392.b3
port = 3260
options = 0
iscsi_options = 2848
tcp_options = 2087
ip_options = 32768
max_rcv_data_seg_len = 128
max_snd_data_seg_len = 128
first_burst_len = 256
def_time2wait = 2
time2retain = 20
max_outstanding_r2t = 1
max_noop_out_interval = 30
isid = <empty>
tsid = 65535
max_burst_len = 512
fw_cmd_timeout = 10
iscsi_alias = <empty>
target_address = 0.0.0.0
tpgt = 0
chap_tbl_idx = 0
is_persistent = 1
\# END RECORD

Update an entry and commit to adapter FLASH
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx> -n <name> -v 
<value> -o update
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx>  -o apply

Delete an entry
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx>  -o delete

Create a new entry
\# iscsiadm -m host -H hostno -C flash_target -o new -type <ipv4/ipv6>
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx> -n <name> -v 
<value> -o update
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx>  -o apply

Example, create new entry:
\#iscsiadm -m host -H 7 -C flash_target -o new -type ipv4
\#iscsiadm -m host -H 7 -C flash_target -o show
qla4xxx: [0] 192.168.1.12:3260,2 iqn.1992-04.com.emc:cx.ckm00101200392.b2
 qla4xxx: [1] 192.168.1.12:3260,2
qla4xxx: [2]

Here - The newly created entry is at target_idx 2, use it to update the entry

\# iscsiadm -m host -H 7 -C flash_target -x 2 -n address -v 192.168.1.13 -o 
update
\# iscsiadm -m host -H 7  -C flash_target -x 2  -o apply
\#iscsiadm -m host -H 7 -C flash_target -o show
qla4xxx: [0] 192.168.1.12:3260,2 iqn.1992-04.com.emc:cx.ckm00101200392.b2
qla4xxx: [1] 192.168.1.12:3260,2
qla4xxx: [2] 192.168.1.13:3260,0

Login & Logout
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx>  -o login
\# iscsiadm -m host -H hostno -C flash_target -x <target_idx>  -o logout

Signed-off-by: Adheer Chandravanshi <[email protected]>
Signed-off-by: Vikas Chaudhary <[email protected]>
---
 usr/flash_tgt.h   |   45 +++++++++
 usr/host.c        |   27 ++++++
 usr/idbm.c        |   54 +++++++++++
 usr/idbm.h        |    4 +
 usr/idbm_fields.h |   25 +++++
 usr/iscsi_sysfs.c |  258 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 usr/iscsi_sysfs.h |   16 ++++
 usr/iscsiadm.c    |  148 +++++++++++++++++++++++++++++--
 8 files changed, 571 insertions(+), 6 deletions(-)
 create mode 100644 usr/flash_tgt.h

diff --git a/usr/flash_tgt.h b/usr/flash_tgt.h
new file mode 100644
index 0000000..44b639a
--- /dev/null
+++ b/usr/flash_tgt.h
@@ -0,0 +1,45 @@
+#ifndef ISCSI_TARGET_H
+#define ISCSI_TARGET_H
+#include <sys/types.h>
+
+#include "types.h"
+#include "config.h"
+
+typedef enum ip_type {
+       IPV4,
+       IPV6,
+} ip_type_e;
+
+struct flash_tgt_rec {
+       struct list_head        list;
+       char                    transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
+       char                    ipaddress[NI_MAXHOST];
+       char                    name[TARGET_NAME_MAXLEN];
+       uint16_t                port;
+       uint16_t                options;
+       uint16_t                iscsi_options;
+       uint16_t                tcp_options;
+       uint16_t                ip_options;
+       uint16_t                iscsi_max_rcv_data_seg_len;
+       uint16_t                iscsi_max_snd_data_seg_len;
+       uint16_t                iscsi_first_burst_len;
+       uint16_t                iscsi_def_time2wait;
+       uint16_t                iscsi_def_time2retain;
+       uint16_t                iscsi_max_outsnd_r2t;
+       uint16_t                ka_timeout;
+       uint8_t                 isid[6];
+       uint16_t                tsid;
+       uint16_t                iscsi_max_burst_len;
+       uint16_t                def_timeout;
+       uint8_t                 iscsi_alias[0x20];
+       uint8_t                 tgt_addr[0x20];
+       uint8_t                 iscsi_name[0xE0];
+       uint16_t                tgt_portal_grp;
+       uint16_t                chap_tbl_idx;
+       uint16_t                cookie;
+};
+
+extern int flash_tgt_info_print_flat(void *data, struct flash_tgt_rec *tgt,
+                                    uint32_t host_no, uint32_t target_idx);
+
+#endif
diff --git a/usr/host.c b/usr/host.c
index b03e50f..47e3467 100644
--- a/usr/host.c
+++ b/usr/host.c
@@ -34,6 +34,7 @@
 #include "initiator.h"
 #include "iface.h"
 #include "iscsi_err.h"
+#include "flash_tgt.h"
 
 static int match_host_to_session(void *data, struct session_info *info)
 {
@@ -118,6 +119,32 @@ static int host_info_print_flat(void *data, struct 
host_info *hinfo)
        return 0;
 }
 
+int flash_tgt_info_print_flat(void *data, struct flash_tgt_rec *tgt,
+                             uint32_t host_no, uint32_t target_idx)
+{
+       printf("%s: [%d] ", tgt->transport_name, target_idx);
+       if (!strlen(tgt->ipaddress))
+               printf("%s:", UNKNOWN_VALUE);
+       else if (strchr(tgt->ipaddress, '.'))
+               printf("%s:", tgt->ipaddress);
+       else
+               printf("[%s]:", tgt->ipaddress);
+
+       if (!tgt->port)
+               printf("%s,", UNKNOWN_VALUE);
+       else
+               printf("%u,", tgt->port);
+
+       printf("%u ", tgt->tgt_portal_grp);
+
+       if (!strlen(tgt->name))
+               printf("%s\n", UNKNOWN_VALUE);
+       else
+               printf("%s\n", tgt->name);
+
+       return 0;
+}
+
 static int print_host_iface(void *data, struct iface_rec *iface)
 {
        char *prefix = data;
diff --git a/usr/idbm.c b/usr/idbm.c
index 4d30aa9..6d8d19f 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -469,6 +469,51 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec 
*r, recinfo_t *ri)
        }
 }
 
+static void idbm_recinfo_flash_tgt(struct flash_tgt_rec *r, recinfo_t *ri)
+{
+       int num = 0;
+
+       __recinfo_str(TARGET_IPADDR, ri, r, ipaddress, IDBM_SHOW, num, 1);
+       __recinfo_str(TARGET_NAME, ri, r, name, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_PORT, ri, r, port, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_OPTIONS, ri, r, options, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_ISCSI_OPTIONS, ri, r, iscsi_options, IDBM_SHOW,
+                        num, 1);
+       __recinfo_uint16(TARGET_TCP_OPTIONS, ri, r, tcp_options, IDBM_SHOW,
+                        num, 1);
+       __recinfo_uint16(TARGET_IP_OPTIONS, ri, r, ip_options, IDBM_SHOW,
+                        num, 1);
+       __recinfo_uint16(TARGET_MAX_RCV_DS_LEN, ri, r,
+                        iscsi_max_rcv_data_seg_len, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_MAX_SND_DS_LEN, ri, r,
+                        iscsi_max_rcv_data_seg_len, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_FIRST_BURST_LEN, ri, r,
+                        iscsi_first_burst_len, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_DEF_TIME2WAIT, ri, r,
+                        iscsi_def_time2wait, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_DEF_TIME2RETAIN, ri, r,
+                        iscsi_def_time2retain, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_MAX_OUTSTANDING_R2T, ri, r,
+                        iscsi_max_outsnd_r2t, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_NOOP_OUT_INTERVAL, ri, r,
+                        ka_timeout, IDBM_SHOW, num, 1);
+       __recinfo_str(TARGET_ISID, ri, r, isid, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_TSID, ri, r, tsid, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_MAX_BURST_LEN, ri, r, iscsi_max_burst_len,
+                        IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_FW_CMD_TIMEOUT, ri, r, def_timeout,
+                        IDBM_SHOW, num, 1);
+       __recinfo_str(TARGET_ISCSI_ALIAS, ri, r, iscsi_alias, IDBM_SHOW,
+                     num, 1);
+       __recinfo_str(TARGET_ADDRESS, ri, r, tgt_addr, IDBM_SHOW, num, 1);
+       __recinfo_uint16(TARGET_TPGT, ri, r, tgt_portal_grp, IDBM_SHOW,
+                        num, 1);
+       __recinfo_uint16(TARGET_CHAP_TBL_IDX, ri, r, chap_tbl_idx, IDBM_SHOW,
+                        num, 1);
+       __recinfo_uint16(TARGET_IS_PERSISTENT, ri, r, cookie, IDBM_SHOW,
+                        num, 1);
+}
+
 recinfo_t *idbm_recinfo_alloc(int max_keys)
 {
        recinfo_t *info;
@@ -502,6 +547,9 @@ void idbm_print(int type, void *rec, int show, FILE *f)
        case IDBM_PRINT_TYPE_HOST_CHAP:
                idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
                break;
+       case IDBM_PRINT_TYPE_FLASH_TGT:
+               idbm_recinfo_flash_tgt((struct flash_tgt_rec *)rec, info);
+               break;
        }
 
        fprintf(f, "%s\n", ISCSI_BEGIN_REC);
@@ -880,6 +928,12 @@ int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
        return 0;
 }
 
+int idbm_print_flash_tgt_info(struct flash_tgt_rec *target)
+{
+       idbm_print(IDBM_PRINT_TYPE_FLASH_TGT, target, 1, stdout);
+       return 0;
+}
+
 int idbm_print_node_flat(void *data, node_rec_t *rec)
 {
        if (strchr(rec->conn[0].address, '.'))
diff --git a/usr/idbm.h b/usr/idbm.h
index 245f046..6de0b76 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -27,6 +27,7 @@
 #include "initiator.h"
 #include "config.h"
 #include "list.h"
+#include "flash_tgt.h"
 
 #define NODE_CONFIG_DIR                ISCSI_CONFIG_ROOT"nodes"
 #define SLP_CONFIG_DIR         ISCSI_CONFIG_ROOT"slp"
@@ -168,6 +169,7 @@ enum {
        IDBM_PRINT_TYPE_NODE,
        IDBM_PRINT_TYPE_IFACE,
        IDBM_PRINT_TYPE_HOST_CHAP,
+       IDBM_PRINT_TYPE_FLASH_TGT
 };
 
 extern void idbm_print(int type, void *rec, int show, FILE *f);
@@ -182,4 +184,6 @@ idbm_create_rec_from_boot_context(struct boot_context 
*context);
 
 extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
 
+extern int idbm_print_flash_tgt_info(struct flash_tgt_rec *target);
+
 #endif /* IDBM_H */
diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h
index 358d014..de3e91c 100644
--- a/usr/idbm_fields.h
+++ b/usr/idbm_fields.h
@@ -126,4 +126,29 @@
 #define HOST_AUTH_PASSWORD_IN          "host.auth.password_in"
 #define HOST_AUTH_PASSWORD_IN_LEN      "host.auth.password_in_length"
 
+/* flash target fields */
+#define TARGET_NAME                    "name"
+#define TARGET_PORT                    "port"
+#define TARGET_IPADDR                  "ipaddress"
+#define TARGET_OPTIONS                 "options"
+#define TARGET_ISCSI_OPTIONS           "iscsi_options"
+#define TARGET_TCP_OPTIONS             "tcp_options"
+#define TARGET_IP_OPTIONS              "ip_options"
+#define TARGET_MAX_RCV_DS_LEN          "max_rcv_data_seg_len"
+#define TARGET_MAX_SND_DS_LEN          "max_snd_data_seg_len"
+#define TARGET_FIRST_BURST_LEN         "first_burst_len"
+#define TARGET_DEF_TIME2WAIT           "def_time2wait"
+#define TARGET_DEF_TIME2RETAIN         "time2retain"
+#define TARGET_MAX_OUTSTANDING_R2T     "max_outstanding_r2t"
+#define TARGET_NOOP_OUT_INTERVAL       "max_noop_out_interval"
+#define TARGET_ISID                    "isid"
+#define TARGET_TSID                    "tsid"
+#define TARGET_MAX_BURST_LEN           "max_burst_len"
+#define TARGET_FW_CMD_TIMEOUT          "fw_cmd_timeout"
+#define TARGET_ISCSI_ALIAS             "iscsi_alias"
+#define TARGET_ADDRESS                 "target_address"
+#define TARGET_TPGT                    "tpgt"
+#define TARGET_CHAP_TBL_IDX            "chap_tbl_idx"
+#define TARGET_IS_PERSISTENT           "is_persistent"
+
 #endif
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
index 123dde3..1e1a959 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -37,6 +37,7 @@
 #include "session_info.h"
 #include "host.h"
 #include "iscsi_err.h"
+#include "flash_tgt.h"
 
 /*
  * TODO: remove the _DIR defines and search for subsys dirs like
@@ -45,18 +46,21 @@
 #define ISCSI_TRANSPORT_DIR    "/sys/class/iscsi_transport"
 #define ISCSI_SESSION_DIR      "/sys/class/iscsi_session"
 #define ISCSI_HOST_DIR         "/sys/class/iscsi_host"
+#define ISCSI_OFFLOAD_DIR      "/sys/firmware/iscsi_offload"
 
 #define ISCSI_SESSION_SUBSYS           "iscsi_session"
 #define ISCSI_CONN_SUBSYS              "iscsi_connection"
 #define ISCSI_HOST_SUBSYS              "iscsi_host"
 #define ISCSI_TRANSPORT_SUBSYS         "iscsi_transport"
 #define ISCSI_IFACE_SUBSYS             "iscsi_iface"
+#define ISCSI_OFFLOAD_SUBSYS           "iscsi_offload"
 #define SCSI_HOST_SUBSYS               "scsi_host"
 #define SCSI_SUBSYS                    "scsi"
 
 #define ISCSI_SESSION_ID               "session%d"
 #define ISCSI_CONN_ID                  "connection%d:0"
 #define ISCSI_HOST_ID                  "host%d"
+#define ISCSI_TARGET_ID                        "tgt%d"
 
 /*
  * TODO: make this into a real API and check inputs better and add doc.
@@ -440,6 +444,260 @@ uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct 
iface_rec *iface, int *rc)
 }
 
 /*
+ * Read the flash target attributes based on host and target index.
+ */
+int iscsi_sysfs_get_flash_tgt_info(struct flash_tgt_rec *tgt, uint32_t host_no,
+                                  uint32_t target_idx)
+{
+       char id[NAME_SIZE] = {'\0'};
+       struct iscsi_transport *t;
+       int ret = 0;
+
+       t = iscsi_sysfs_get_transport_by_hba(host_no);
+       if (!t)
+               log_debug(7, "could not get transport name for host%d",
+                         host_no);
+       else
+               strncpy(tgt->transport_name, t->name,
+                       ISCSI_TRANSPORT_NAME_MAXLEN);
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID"/"ISCSI_TARGET_ID,
+                host_no, target_idx);
+
+       sysfs_get_str(id, ISCSI_OFFLOAD_SUBSYS, "ipaddress",
+                     tgt->ipaddress, sizeof(tgt->ipaddress));
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "port", &tgt->port);
+       sysfs_get_str(id, ISCSI_OFFLOAD_SUBSYS, "name",
+                     tgt->name, sizeof(tgt->name));
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "target_options",
+                        &tgt->options);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "iscsi_options",
+                        &tgt->iscsi_options);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "tcp_options",
+                        &tgt->tcp_options);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "ip_options",
+                        &tgt->ip_options);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS,
+                        "max_recv_data_segment_length",
+                        &tgt->iscsi_max_rcv_data_seg_len);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS,
+                        "max_xmit_data_segment_length",
+                        &tgt->iscsi_max_snd_data_seg_len);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "first_burst_length",
+                        &tgt->iscsi_first_burst_len);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "default_time2wait",
+                        &tgt->iscsi_def_time2wait);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "default_time2retain",
+                        &tgt->iscsi_def_time2retain);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "max_outstanding_r2t",
+                        &tgt->iscsi_max_outsnd_r2t);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "noop_out_interval",
+                        &tgt->ka_timeout);
+       sysfs_get_str(id, ISCSI_OFFLOAD_SUBSYS, "isid",
+                     (char *)&tgt->isid, sizeof(tgt->isid));
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "tsid", &tgt->tsid);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "max_burst_length",
+                        &tgt->iscsi_max_burst_len);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "firmware_cmd_timeout",
+                        &tgt->def_timeout);
+       sysfs_get_str(id, ISCSI_OFFLOAD_SUBSYS, "iscsi_alias",
+                     (char *)&tgt->iscsi_alias, sizeof(tgt->iscsi_alias));
+       sysfs_get_str(id, ISCSI_OFFLOAD_SUBSYS, "target_address",
+                     (char *)&tgt->tgt_addr, sizeof(tgt->tgt_addr));
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "tpgt",
+                        &tgt->tgt_portal_grp);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "chap_tbl_idx",
+                        &tgt->chap_tbl_idx);
+       sysfs_get_uint16(id, ISCSI_OFFLOAD_SUBSYS, "is_persistent",
+                        &tgt->cookie);
+       return ret;
+}
+
+/*
+ * Add new flash target entry for the specified host.
+ */
+int iscsi_sysfs_create_flash_tgt(uint32_t host_no, char *ip_type)
+{
+       char id[PATH_SIZE] = {'\0'};
+       char *write_buf = ip_type;
+       int ret = 0;
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
+
+       log_debug(4, "Add new target for host%d", host_no);
+
+       ret = sysfs_set_param(id, ISCSI_OFFLOAD_SUBSYS, "new", write_buf,
+                             strlen(write_buf));
+       if (ret)
+               log_error("Could not create target for host%d", host_no);
+
+       return ret;
+}
+
+/*
+ * Delete the specified flash target entry for the specified host.
+ */
+int iscsi_sysfs_del_flash_tgt(uint32_t host_no, uint32_t target_idx)
+{
+       char id[NAME_SIZE] = {'\0'};
+       char target[NAME_SIZE] = {'\0'};
+       int ret = 0;
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID, host_no);
+
+       snprintf(target, sizeof(target), "%d", target_idx);
+
+       log_debug(4, "Delete target tgt%d for host%d", target_idx, host_no);
+
+       ret = sysfs_set_param(id, ISCSI_OFFLOAD_SUBSYS, "delete", target,
+                             strlen(target));
+       if (ret == EINVAL)
+               log_error("Invalid target idx %d or hostno %d",
+                         target_idx, host_no);
+       else if (ret)
+               log_error("Could not delete target tgt%d of host%d",
+                         target_idx, host_no);
+
+       return ret;
+}
+
+/*
+ * Login to given flash target of the specified host.
+ */
+int iscsi_sysfs_login_flash_tgt(uint32_t host_no, uint32_t target_idx)
+{
+       char id[PATH_SIZE] = {'\0'};
+       char *write_buf = "1";
+       int ret = 0;
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID"/"ISCSI_TARGET_ID,
+                host_no, target_idx);
+
+       log_debug(4, "Login to target tgt%d for host%d", target_idx, host_no);
+
+       ret = sysfs_set_param(id, ISCSI_OFFLOAD_SUBSYS, "login", write_buf,
+                             strlen(write_buf));
+       if (ret == EINVAL)
+               log_error("Invalid target idx %d or hostno %d",
+                         target_idx, host_no);
+       else if (ret)
+               log_error("Could not login to target tgt%d of host%d",
+                         target_idx, host_no);
+
+       return ret;
+}
+
+/*
+ * Logout of given flash target for the specified host.
+ */
+int iscsi_sysfs_logout_flash_tgt(uint32_t host_no, uint32_t target_idx)
+{
+       char id[PATH_SIZE] = {'\0'};
+       char *write_buf = "1";
+       int ret = 0;
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID"/"ISCSI_TARGET_ID,
+                host_no, target_idx);
+
+       log_debug(4, "Logout of target tgt%d of host%d", target_idx, host_no);
+
+       ret = sysfs_set_param(id, ISCSI_OFFLOAD_SUBSYS, "logout", write_buf,
+                             strlen(write_buf));
+       if (ret == EINVAL)
+               log_error("Invalid target idx %d or hostno %d",
+                         target_idx, host_no);
+       else if (ret)
+               log_error("Could not logout of target tgt%d of host%d",
+                         target_idx, host_no);
+
+       return ret;
+}
+
+/*
+ * Update the parameter of given flash target for the specified host.
+ */
+int iscsi_sysfs_update_flash_tgt_param(uint32_t host_no, uint32_t target_idx,
+                                      char *name, char *val)
+{
+       char id[PATH_SIZE] = {'\0'};
+       char *write_buf = val;
+       int ret = 0;
+
+       snprintf(id, sizeof(id), ISCSI_HOST_ID"/"ISCSI_TARGET_ID,
+                host_no, target_idx);
+
+       log_debug(4, "Update param %s of target tgt%d of host%d with val %s",
+                 name, target_idx, host_no, val);
+
+       ret = sysfs_set_param(id, ISCSI_OFFLOAD_SUBSYS, name, write_buf,
+                             strlen(write_buf));
+       if (ret == EINVAL)
+               log_error("Invalid target idx %d or hostno %d",
+                         target_idx, host_no);
+       else if (ret)
+               log_error("Could not update param %s of target tgt%d of host%d",
+                         name, target_idx, host_no);
+
+       return ret;
+}
+
+/*
+ * For each target of the given host, perform operation specified in fn.
+ */
+int iscsi_sysfs_for_each_flash_tgt(void *data, uint32_t host_no,
+                                  int *nr_found, iscsi_sysfs_tgt_op_fn *fn)
+{
+       struct dirent **namelist;
+       int rc = 0, i, n;
+       struct flash_tgt_rec *tgt;
+       char host_dir[PATH_SIZE] = {'\0'};
+       uint32_t target_idx;
+
+       tgt = malloc(sizeof(*tgt));
+       if (!tgt)
+               return ISCSI_ERR_NOMEM;
+
+       snprintf(host_dir, sizeof(host_dir), ISCSI_OFFLOAD_DIR"/"ISCSI_HOST_ID,
+                host_no);
+
+       n = scandir(host_dir, &namelist, trans_filter, alphasort);
+       if (n <= 0)
+               goto free_tgt;
+
+       for (i = 0; i < n; i++) {
+               memset(tgt, 0, sizeof(*tgt));
+               if (!strcmp(namelist[i]->d_name, "new") ||
+                   !strcmp(namelist[i]->d_name, "delete")) {
+                       continue;
+               }
+
+               if (sscanf(namelist[i]->d_name, ISCSI_TARGET_ID,
+                          &target_idx) != 1) {
+                       log_error("Invalid iscsi target dir: %s",
+                                 namelist[i]->d_name);
+                       break;
+               }
+
+               rc = iscsi_sysfs_get_flash_tgt_info(tgt, host_no, target_idx);
+               if (rc)
+                       break;
+
+               rc = fn(data, tgt, host_no, target_idx);
+               if (rc != 0)
+                       break;
+               (*nr_found)++;
+       }
+
+       for (i = 0; i < n; i++)
+               free(namelist[i]);
+       free(namelist);
+
+free_tgt:
+       free(tgt);
+       return rc;
+}
+
+/*
  * Read in iface settings based on host and session values. If
  * session is not passed in, then the ifacename will not be set. And
  * if the session is not passed in then iname will only be set for
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
index 2b15d78..9f4d554 100644
--- a/usr/iscsi_sysfs.h
+++ b/usr/iscsi_sysfs.h
@@ -31,6 +31,7 @@ struct iscsi_conn;
 struct iscsi_session_operational_config;
 struct iscsi_conn_operational_config;
 struct iscsi_auth_config;
+struct flash_tgt_rec;
 
 #define SCSI_MAX_STATE_VALUE 32
 
@@ -42,6 +43,8 @@ extern int iscsi_sysfs_session_has_leadconn(uint32_t sid);
 
 typedef int (iscsi_sysfs_session_op_fn)(void *, struct session_info *);
 typedef int (iscsi_sysfs_host_op_fn)(void *, struct host_info *);
+typedef int (iscsi_sysfs_tgt_op_fn)(void *, struct flash_tgt_rec *, uint32_t,
+                                   uint32_t);
 typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *);
 
 extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
@@ -56,6 +59,19 @@ extern uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct 
iface_rec *iface,
                                                    int *rc);
 extern uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int 
*rc);
 extern int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo);
+extern int iscsi_sysfs_for_each_flash_tgt(void *data, uint32_t host_no,
+                                         int *nr_found,
+                                         iscsi_sysfs_tgt_op_fn *fn);
+extern int iscsi_sysfs_get_flash_tgt_info(struct flash_tgt_rec *tgt,
+                                         uint32_t host_no,
+                                         uint32_t target_idx);
+extern int iscsi_sysfs_update_flash_tgt_param(uint32_t host_no,
+                                             uint32_t target_idx,
+                                             char *name, char *val);
+extern int iscsi_sysfs_create_flash_tgt(uint32_t host_no, char *ipver);
+extern int iscsi_sysfs_del_flash_tgt(uint32_t host_no, uint32_t target_idx);
+extern int iscsi_sysfs_login_flash_tgt(uint32_t host_no, uint32_t target_idx);
+extern int iscsi_sysfs_logout_flash_tgt(uint32_t host_no, uint32_t target_idx);
 extern int iscsi_sysfs_get_sid_from_path(char *session);
 extern char *iscsi_sysfs_get_blockdev_from_lun(int hostno, int target, int 
sid);
 
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 8f9de05..2f0bbb4 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -53,6 +53,7 @@
 #include "iscsi_err.h"
 #include "iscsi_ipc.h"
 #include "iscsi_timer.h"
+#include "flash_tgt.h"
 
 static char program_name[] = "iscsiadm";
 static char config_file[TARGET_NAME_MAXLEN];
@@ -67,7 +68,8 @@ enum iscsiadm_mode {
        MODE_IFACE,
        MODE_FW,
        MODE_PING,
-       MODE_CHAP
+       MODE_CHAP,
+       MODE_FLASH_TARGET
 };
 
 enum iscsiadm_op {
@@ -78,7 +80,9 @@ enum iscsiadm_op {
        OP_SHOW                 = 0x8,
        OP_NONPERSISTENT        = 0x10,
        OP_APPLY                = 0x20,
-       OP_APPLY_ALL            = 0x40
+       OP_APPLY_ALL            = 0x40,
+       OP_LOGIN                = 0x80,
+       OP_LOGOUT               = 0x100
 };
 
 static struct option const long_options[] =
@@ -111,9 +115,10 @@ static struct option const long_options[] =
        {"packetsize", required_argument, NULL, 'b'},
        {"count", required_argument, NULL, 'c'},
        {"interval", required_argument, NULL, 'i'},
+       {"target_idx", optional_argument, NULL, 'x'},
        {NULL, 0, NULL, 0},
 };
-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";
+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:";
 
 static void usage(int status)
 {
@@ -130,7 +135,7 @@ iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel 
] [ -L all,manual,au
 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P  printlevel] [ -r 
sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] 
]\n\
 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\
 iscsiadm -m fw [ -l ]\n\
-iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ -C chap [ -o operation 
] [ -v chap_tbl_idx ] ]\n\
+iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ -C chap | -C 
flash_target [ -o operation ] [ -v chap_tbl_idx ] [ [ -t type ] [ -x target_idx 
] [ -n name ] [ -v value ] ] ]\n\
 iscsiadm -k priority\n");
        }
        exit(status);
@@ -155,6 +160,10 @@ str_to_op(char *str)
                op = OP_APPLY;
        else if (!strcmp("applyall", str))
                op = OP_APPLY_ALL;
+       else if (!strcmp("login", str))
+               op = OP_LOGIN;
+       else if (!strcmp("logout", str))
+               op = OP_LOGOUT;
        else
                op = OP_NOOP;
 
@@ -195,6 +204,8 @@ str_to_submode(char *str)
                sub_mode = MODE_PING;
        else if (!strcmp("chap", str))
                sub_mode = MODE_CHAP;
+       else if (!strcmp("flash_target", str))
+               sub_mode = MODE_FLASH_TARGET;
        else
                sub_mode = -1;
 
@@ -215,6 +226,10 @@ str_to_type(char *str)
                type = DISCOVERY_TYPE_ISNS;
        else if (!strcmp("fw", str))
                type = DISCOVERY_TYPE_FW;
+       else if (!strcmp("ipv4", str))
+               type = IPV4;
+       else if (!strcmp("ipv6", str))
+               type = IPV6;
        else
                type = -1;
 
@@ -1438,6 +1453,112 @@ static int exec_host_chap_op(int op, int info_level, 
uint32_t host_no,
        return rc;
 }
 
+static int get_flash_tgt_info(uint32_t host_no, uint32_t target_idx)
+{
+       struct flash_tgt_rec tgt;
+       int rc = 0;
+
+       memset(&tgt, 0, sizeof(tgt));
+       rc = iscsi_sysfs_get_flash_tgt_info(&tgt, host_no, target_idx);
+       if (rc) {
+               log_error("Could not read target info for target %d of host %d",
+                         target_idx, host_no);
+               return rc;
+       }
+
+       idbm_print_flash_tgt_info(&tgt);
+       return rc;
+}
+
+static int list_flash_tgts(int info_level, uint32_t host_no)
+{
+       int rc = 0;
+       int num_found = 0;
+
+       rc = iscsi_sysfs_for_each_flash_tgt(NULL, host_no, &num_found,
+                                           flash_tgt_info_print_flat);
+
+       if (!num_found)
+               log_error("No targets attached to host%d", host_no);
+
+       return rc;
+}
+
+static int exec_flash_tgt_op(int op, int info_level, uint32_t host_no,
+                            uint32_t target_idx, int type, char *name,
+                            char *val)
+{
+       int rc = ISCSI_ERR_INVAL;
+       char *ip_type;
+
+       switch (op) {
+       case OP_NOOP:
+       case OP_SHOW:
+               if (target_idx == 0xffffffff)
+                       rc = list_flash_tgts(info_level, host_no);
+               else
+                       rc = get_flash_tgt_info(host_no, target_idx);
+               break;
+       case OP_DELETE:
+               rc = iscsi_sysfs_del_flash_tgt(host_no, target_idx);
+               if (!rc)
+                       printf("Target tgt%d of host%d deleted\n",
+                              target_idx, host_no);
+               break;
+       case OP_NEW:
+               if (type == IPV4) {
+                       ip_type = "IPv4";
+               } else if (type == IPV6) {
+                       ip_type = "IPv6";
+               } else {
+                       log_error("Invalid type mentioned for target");
+                       return rc;
+               }
+               rc = iscsi_sysfs_create_flash_tgt(host_no, ip_type);
+               if (!rc)
+                       printf("New target for host%d added\n", host_no);
+               break;
+       case OP_LOGIN:
+               rc = iscsi_sysfs_update_flash_tgt_param(host_no, target_idx,
+                                                       "login", "1");
+               if (!rc)
+                       printf("Login to target tgt%d of host%d done\n",
+                              target_idx, host_no);
+               break;
+       case OP_LOGOUT:
+               rc = iscsi_sysfs_update_flash_tgt_param(host_no, target_idx,
+                                                       "logout", "1");
+               if (!rc)
+                       printf("Logout from target tgt%d of host%d done\n",
+                              target_idx, host_no);
+               break;
+       case OP_UPDATE:
+               if (!name || !val) {
+                       log_error("Cannot update parameter as "
+                                 "either name or value is not passed");
+                       return ISCSI_ERR_INVAL;
+               }
+               rc = iscsi_sysfs_update_flash_tgt_param(host_no, target_idx,
+                                                       name, val);
+               if (!rc)
+                       printf("Param %s for target tgt%d of host%d updated\n",
+                              name, target_idx, host_no);
+               break;
+       case OP_APPLY:
+               rc = iscsi_sysfs_update_flash_tgt_param(host_no, target_idx,
+                                                       "apply", "1");
+               if (!rc)
+                       printf("Target tgt%d of host%d applied\n",
+                              target_idx, host_no);
+               break;
+       default:
+               log_error("Invalid operation");
+               break;
+       }
+
+       return rc;
+}
+
 static int verify_iface_params(struct list_head *params, struct node_rec *rec)
 {
        struct user_param *param;
@@ -2403,6 +2524,7 @@ main(int argc, char **argv)
        int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
        int packet_size=32, ping_count=1, ping_interval=0;
        int do_discover = 0, sub_mode = -1;
+       int target_idx = -1;
        struct sigaction sa_old;
        struct sigaction sa_new;
        struct list_head ifaces;
@@ -2551,11 +2673,14 @@ main(int argc, char **argv)
                        printf("%s version %s\n", program_name,
                                ISCSI_VERSION_STR);
                        return 0;
+               case 'x':
+                       target_idx = atoi(optarg);
+                       break;
                case 'h':
                        usage(0);
                }
 
-               if (name && value) {
+               if (mode == MODE_IFACE && name && value) {
                        param = idbm_alloc_user_param(name, value);
                        if (!param) {
                                log_error("Cannot allocate memory for params.");
@@ -2603,7 +2728,7 @@ main(int argc, char **argv)
 
        switch (mode) {
        case MODE_HOST:
-               if ((rc = verify_mode_params(argc, argv, "CHdmPov", 0))) {
+               if ((rc = verify_mode_params(argc, argv, "CHdmPotnvx", 0))) {
                        log_error("host mode: option '-%c' is not "
                                  "allowed/supported", rc);
                        rc = ISCSI_ERR_INVAL;
@@ -2621,6 +2746,17 @@ main(int argc, char **argv)
                                rc = exec_host_chap_op(op, info_level, host_no,
                                                       value);
                                break;
+                       case MODE_FLASH_TARGET:
+                               if (!host_no) {
+                                       log_error("FLASH_TARGET mode requires 
host no");
+                                       rc = ISCSI_ERR_INVAL;
+                                       break;
+                               }
+
+                               rc = exec_flash_tgt_op(op, info_level, host_no,
+                                                      target_idx, type, name,
+                                                      value);
+                               break;
                        default:
                                log_error("Invalid Sub Mode");
                                break;
-- 
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.

Reply via email to