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.
