#include #include #include #include #include #include #include "list.h" #include "log.h" #include "iscsi_sysfs.h" #include "version.h" #include "iscsi_settings.h" #include "mgmt_ipc.h" #include "session_info.h" #include "transport.h" #include "initiator.h" #include "iface.h" #include "iscsid_req.h" #include "iscsi_err.h" static int session_info_print_flat(struct iscsi_session *se); int session_info_create_list(void *data, struct session_info *info) { struct session_link_info *link_info = data; struct list_head *list = link_info->list; struct session_info *new, *curr, *match = NULL; if (link_info->match_fn && !link_info->match_fn(link_info->data, info)) return -1; new = calloc(1, sizeof(*new)); if (!new) return ISCSI_ERR_NOMEM; memcpy(new, info, sizeof(*new)); INIT_LIST_HEAD(&new->list); if (list_empty(list)) { list_add_tail(&new->list, list); return 0; } list_for_each_entry(curr, list, list) { if (!strcmp(curr->targetname, info->targetname)) { match = curr; if (!strcmp(curr->address, info->address)) { match = curr; if (curr->port == info->port) { match = curr; break; } } } } list_add_tail(&new->list, match ? match->list.next : list); return 0; } void session_info_free_list(struct list_head *list) { struct session_info *curr, *tmp; list_for_each_entry_safe(curr, tmp, list, list) { list_del(&curr->list); free(curr); } } static char *get_iscsi_node_type(uint32_t sid) { int pid = iscsi_sysfs_session_user_created((int) sid); if (!pid) return "flash"; else return "non-flash"; } static int session_info_print_flat(struct iscsi_session *se) { uint32_t sid = 0; struct iscsi_transport *t = NULL; sid = iscsi_session_sid_get(se); t = iscsi_sysfs_get_transport_by_sid((int) sid); if (strchr(iscsi_session_persistent_address_get(se), '.')) printf("%s: [%" PRIu32 "] %s:%" PRIi32 ",%"PRIi32 " %s (%s)\n", t ? t->name : UNKNOWN_VALUE, sid, iscsi_session_persistent_address_get(se), iscsi_session_persistent_port_get(se), iscsi_session_tpgt_get(se), iscsi_session_target_name_get(se), get_iscsi_node_type(sid)); else printf("%s: [%" PRIu32 "] [%s]:%" PRIi32 ",%" PRIi32 " %s (%s)\n", t ? t->name : UNKNOWN_VALUE, sid, iscsi_session_persistent_address_get(se), iscsi_session_persistent_port_get(se), iscsi_session_tpgt_get(se), iscsi_session_target_name_get(se), get_iscsi_node_type(sid)); return 0; } static int print_iscsi_state(int sid, char *prefix, int tmo) { iscsiadm_req_t req; iscsiadm_rsp_t rsp; int err; char *state = NULL; char state_buff[SCSI_MAX_STATE_VALUE]; static char *conn_state[] = { "FREE", "TRANSPORT WAIT", "IN LOGIN", "LOGGED IN", "IN LOGOUT", "LOGOUT REQUESTED", "CLEANUP WAIT", }; static char *session_state[] = { "NO CHANGE", "CLEANUP", "REOPEN", "REDIRECT", }; memset(&req, 0, sizeof(iscsiadm_req_t)); req.command = MGMT_IPC_SESSION_INFO; req.u.session.sid = sid; err = iscsid_exec_req(&req, &rsp, 1, tmo); /* * for drivers like qla4xxx, iscsid does not display * anything here since it does not know about it. */ if (!err && rsp.u.session_state.conn_state >= 0 && rsp.u.session_state.conn_state <= ISCSI_CONN_STATE_CLEANUP_WAIT) state = conn_state[rsp.u.session_state.conn_state]; printf("%s\t\tiSCSI Connection State: %s\n", prefix, state ? state : "Unknown"); state = NULL; memset(state_buff, 0, SCSI_MAX_STATE_VALUE); if (!iscsi_sysfs_get_session_state(state_buff, sid)) printf("%s\t\tiSCSI Session State: %s\n", prefix, state_buff); else printf("%s\t\tiSCSI Session State: Unknown\n", prefix); if (!err && rsp.u.session_state.session_state >= 0 && rsp.u.session_state.session_state <= R_STAGE_SESSION_REDIRECT) state = session_state[rsp.u.session_state.session_state]; printf("%s\t\tInternal iscsid Session State: %s\n", prefix, state ? state : "Unknown"); return 0; } static void print_iscsi_params(int sid, char *prefix) { struct iscsi_session_operational_config session_conf; struct iscsi_conn_operational_config conn_conf; iscsi_sysfs_get_negotiated_session_conf(sid, &session_conf); iscsi_sysfs_get_negotiated_conn_conf(sid, &conn_conf); printf("%s\t\t************************\n", prefix); printf("%s\t\tNegotiated iSCSI params:\n", prefix); printf("%s\t\t************************\n", prefix); if (is_valid_operational_value(conn_conf.HeaderDigest)) printf("%s\t\tHeaderDigest: %s\n", prefix, conn_conf.HeaderDigest ? "CRC32C" : "None"); if (is_valid_operational_value(conn_conf.DataDigest)) printf("%s\t\tDataDigest: %s\n", prefix, conn_conf.DataDigest ? "CRC32C" : "None"); if (is_valid_operational_value(conn_conf.MaxRecvDataSegmentLength)) printf("%s\t\tMaxRecvDataSegmentLength: %d\n", prefix, conn_conf.MaxRecvDataSegmentLength); if (is_valid_operational_value(conn_conf.MaxXmitDataSegmentLength)) printf("%s\t\tMaxXmitDataSegmentLength: %d\n", prefix, conn_conf.MaxXmitDataSegmentLength); if (is_valid_operational_value(session_conf.FirstBurstLength)) printf("%s\t\tFirstBurstLength: %d\n", prefix, session_conf.FirstBurstLength); if (is_valid_operational_value(session_conf.MaxBurstLength)) printf("%s\t\tMaxBurstLength: %d\n", prefix, session_conf.MaxBurstLength); if (is_valid_operational_value(session_conf.ImmediateData)) printf("%s\t\tImmediateData: %s\n", prefix, session_conf.ImmediateData ? "Yes" : "No"); if (is_valid_operational_value(session_conf.InitialR2T)) printf("%s\t\tInitialR2T: %s\n", prefix, session_conf.InitialR2T ? "Yes" : "No"); if (is_valid_operational_value(session_conf.MaxOutstandingR2T)) printf("%s\t\tMaxOutstandingR2T: %d\n", prefix, session_conf.MaxOutstandingR2T); } static void print_scsi_device_info(void *data, int host_no, int target, int lun) { char *prefix = data; char *blockdev, state[SCSI_MAX_STATE_VALUE]; printf("%s\t\tscsi%d Channel 00 Id %d Lun: %d\n", prefix, host_no, target, lun); blockdev = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); if (blockdev) { printf("%s\t\t\tAttached scsi disk %s\t\t", prefix, blockdev); free(blockdev); if (!iscsi_sysfs_get_device_state(state, host_no, target, lun)) printf("State: %s\n", state); else printf("State: Unknown\n"); } } static int print_scsi_state(int sid, char *prefix, unsigned int flags) { int host_no = -1, err = 0; char state[SCSI_MAX_STATE_VALUE]; printf("%s\t\t************************\n", prefix); printf("%s\t\tAttached SCSI devices:\n", prefix); printf("%s\t\t************************\n", prefix); host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); if (err) { printf("%s\t\tUnavailable\n", prefix); return err; } if (flags & SESSION_INFO_HOST_DEVS) { printf("%s\t\tHost Number: %d\t", prefix, host_no); if (!iscsi_sysfs_get_host_state(state, host_no)) printf("State: %s\n", state); else printf("State: Unknown\n"); } if (flags & SESSION_INFO_SCSI_DEVS) iscsi_sysfs_for_each_device(prefix, host_no, sid, print_scsi_device_info); return 0; } void session_info_print_tree(struct iscsi_session **ses, uint32_t se_count, char *prefix, unsigned int flags, int do_show) { struct iscsi_session *curr = NULL; struct iscsi_session *prev = NULL; const char *curr_targetname = NULL; const char *curr_address = NULL; const char *persistent_address = NULL; const char *prev_targetname = NULL; const char *prev_address = NULL; int32_t curr_port = 0; int32_t prev_port = 0; uint32_t i = 0; uint32_t sid = 0; char *new_prefix = NULL; int32_t tgt_reset_tmo = -1; int32_t lu_reset_tmo = -1; int32_t abort_tmo = -1; const char *pass = NULL; for (i = 0; i < se_count; ++i) { curr = ses[i]; curr_targetname = iscsi_session_target_name_get(curr); sid = iscsi_session_sid_get(curr); if (prev != NULL) prev_targetname = iscsi_session_target_name_get(prev); else prev_targetname = NULL; if (! ((prev_targetname != NULL) && (curr_targetname != NULL) && (strcmp(prev_targetname, curr_targetname) == 0))) { printf("%sTarget: %s (%s)\n", prefix, curr_targetname, get_iscsi_node_type(sid)); prev = NULL; } curr_address = iscsi_session_address_get(curr); curr_port = iscsi_session_port_get(curr); if (prev != NULL) { prev_address = iscsi_session_address_get(prev); prev_port = iscsi_session_port_get(prev); } else { prev_address = NULL; prev_port = 0; } if (! ((prev_address != NULL) && (curr_address != NULL) && (prev_port != 0) && (curr_port != 0) && (strcmp(prev_address, curr_address) == 0) && (curr_port == prev_port))) { if (strchr(curr_address, '.')) printf("%s\tCurrent Portal: %s:%" PRIi32 ",%" PRIi32 "\n", prefix, curr_address, curr_port, iscsi_session_tpgt_get(curr)); else printf("%s\tCurrent Portal: [%s]:%" PRIi32 ",%" PRIi32 "\n", prefix, curr_address, curr_port, iscsi_session_tpgt_get(curr)); persistent_address = iscsi_session_persistent_address_get(curr); if (strchr(persistent_address, '.')) printf("%s\tPersistent Portal: %s:%" PRIi32 ",%" PRIi32 "\n", prefix, persistent_address, iscsi_session_persistent_port_get(curr), iscsi_session_tpgt_get(curr)); else printf("%s\tPersistent Portal: [%s]:%" PRIi32 ",%" PRIi32 "\n", prefix, persistent_address, iscsi_session_persistent_port_get(curr), iscsi_session_tpgt_get(curr)); } else printf("\n"); if (flags & SESSION_INFO_IFACE) { printf("%s\t\t**********\n", prefix); printf("%s\t\tInterface:\n", prefix); printf("%s\t\t**********\n", prefix); new_prefix = calloc(1, 1 + strlen(prefix) + strlen("\t\t")); if (new_prefix == NULL) { printf("Could not print interface info. " "Out of Memory.\n"); return; } else { sprintf(new_prefix, "%s%s", prefix, "\t\t"); iface_print(iscsi_session_iface_get(curr), new_prefix); } free(new_prefix); } if (flags & SESSION_INFO_ISCSI_STATE) { printf("%s\t\tSID: %" PRIu32 "\n", prefix, sid); print_iscsi_state((int) sid, prefix, -1 /* tmo */); /* TODO(Gris Ge): It seems in the whole project, * tmo is always -1, correct? */ } if (flags & SESSION_INFO_ISCSI_TIM) { printf("%s\t\t*********\n", prefix); printf("%s\t\tTimeouts:\n", prefix); printf("%s\t\t*********\n", prefix); printf("%s\t\tRecovery Timeout: %" PRIi32 "\n", prefix, iscsi_session_recovery_tmo_get(curr)); tgt_reset_tmo = iscsi_session_tgt_reset_tmo_get(curr); lu_reset_tmo = iscsi_session_lu_reset_tmo_get(curr); abort_tmo = iscsi_session_abort_tmo_get(curr); if (tgt_reset_tmo >= 0) printf("%s\t\tTarget Reset Timeout: %" PRIi32 "\n", prefix, tgt_reset_tmo); else printf("%s\t\tTarget Reset Timeout: %s\n", prefix, UNKNOWN_VALUE); if (lu_reset_tmo >= 0) printf("%s\t\tLUN Reset Timeout: %" PRIi32 "\n", prefix, lu_reset_tmo); else printf("%s\t\tLUN Reset Timeout: %s\n", prefix, UNKNOWN_VALUE); if (abort_tmo >= 0) printf("%s\t\tAbort Timeout: %" PRIi32 "\n", prefix, abort_tmo); else printf("%s\t\tAbort Timeout: %s\n", prefix, UNKNOWN_VALUE); } if (flags & SESSION_INFO_ISCSI_AUTH) { printf("%s\t\t*****\n", prefix); printf("%s\t\tCHAP:\n", prefix); printf("%s\t\t*****\n", prefix); printf("%s\t\tusername: %s\n", prefix, strlen(iscsi_session_username_get(curr)) ? iscsi_session_username_get(curr) : UNKNOWN_VALUE); if (!do_show) printf("%s\t\tpassword: %s\n", prefix, "********"); else { pass = iscsi_session_password_get(curr); printf("%s\t\tpassword: %s\n", prefix, strlen(pass) ? pass : UNKNOWN_VALUE); } printf("%s\t\tusername_in: %s\n", prefix, strlen(iscsi_session_username_in_get(curr)) ? iscsi_session_username_in_get(curr) : UNKNOWN_VALUE); if (!do_show) printf("%s\t\tpassword_in: %s\n", prefix, "********"); else { pass = iscsi_session_password_in_get(curr); printf("%s\t\tpassword: %s\n", prefix, strlen(pass) ? pass : UNKNOWN_VALUE); } } if (flags & SESSION_INFO_ISCSI_PARAMS) print_iscsi_params((int) sid, prefix); if (flags & (SESSION_INFO_SCSI_DEVS | SESSION_INFO_HOST_DEVS)) print_scsi_state((int) sid, prefix, flags); prev = curr; } } int session_info_print(int info_level, struct iscsi_session **ses, uint32_t se_count, int do_show) { int err = 0; char *version; unsigned int flags = 0; uint32_t i = 0; switch (info_level) { case 0: case -1: for (i = 0; i < se_count; ++i) { err = session_info_print_flat(ses[i]); if (err != 0) break; } break; case 3: version = iscsi_sysfs_get_iscsi_kernel_version(); if (version) { printf("iSCSI Transport Class version %s\n", version); printf("version %s\n", ISCSI_VERSION_STR); free(version); } flags |= (SESSION_INFO_SCSI_DEVS | SESSION_INFO_HOST_DEVS); /* fall through */ case 2: flags |= (SESSION_INFO_ISCSI_PARAMS | SESSION_INFO_ISCSI_TIM | SESSION_INFO_ISCSI_AUTH); /* fall through */ case 1: flags |= (SESSION_INFO_ISCSI_STATE | SESSION_INFO_IFACE); session_info_print_tree(ses, se_count, "", flags, do_show); break; default: log_error("Invalid info level %d. Try 0 - 3.", info_level); return ISCSI_ERR_INVAL; } if (err) { log_error("Can not get list of active sessions (%d)", err); return err; } return 0; }