📄 iscsi_initiator.c
字号:
/* extract ip address and port into strings for printing */ if (cnv_inet_to_string(conn->local_ip_address, local_ip_string, local_port_string) > 0) TRACE(TRACE_DEBUG,"iscsi local address %s:%s\n", local_ip_string, local_port_string); }#ifdef ISCSI_STATS add_iscsi_proc_entry((void*)conn, CONNECTION);#endif /* Allocate buffer into which rx_thread will read * PDU headers from target. For now, we ignore AHS, * so space is needed only for BHS and digest. */ conn->rx_buf = (__u8 *)my_kmalloc(ISCSI_HDR_LEN + CRC_LEN, "rx_buf"); if (unlikely(conn->rx_buf == NULL)) { /* no memory for rx_buf */ retval = -ENOMEM; goto out2; } /* we are connected to a target */ conn->connection_state = CONNECTION_CONNECTED; /* chap and srp support - CHONG */ new_authparam.auth_flags = targ_data->auth_parameter.auth_flags; new_authparam.chap_local_ctx = CHAP_CloneContext(targ_data->auth_parameter.chap_local_ctx); new_authparam.chap_peer_ctx = CHAP_CloneContext(targ_data->auth_parameter.chap_peer_ctx); new_authparam.srp_ctx = SRP_CloneContext(targ_data->auth_parameter.srp_ctx); /* now go do the login phase for this new connection */ retval = iscsi_initiator_login(conn, when_called, p_param_tbl, new_authparam, targ_data, redirect_ip_address, redirect_ip_length); if (unlikely(retval != 0)) { goto out3; } /* Create connection's rx_thread only if get into Full Feature Phase */ kernel_thread((int (*)(void *)) iscsi_initiator_rx_thread, (void *) conn, 0); /* wait for the rx thread to set itself up */ down_interruptible(&conn->rx_done_sem); if (conn->rx_thread == NULL) { /* the rx thread has already shut itself down */ retval = -ECONNRESET; goto out; } /* connection is up and running */ conn->connection_state = CONNECTION_FULL_FEATURE_PHASE; /* start up the tx thread for this new connection */ kernel_thread((int (*)(void *)) iscsi_initiator_tx_thread, (void *) conn, 0); /* wait for the tx thread to set itself up */ down_interruptible(&conn->tx_done_sem); if (conn->rx_thread == NULL || conn->tx_thread == NULL) { /* the rx and/or tx thread have already shut themselves down */ retval = -ECONNRESET; }out: CHAP_FinalizeContext(new_authparam.chap_peer_ctx); CHAP_FinalizeContext(new_authparam.chap_local_ctx); SRP_FinalizeContext(new_authparam.srp_ctx);out0: TRACE(TRACE_ENTER_LEAVE, "Leave init_connection, retval %d\n", retval); return retval;out3: conn->connection_state = CONNECTION_NOT_PRESENT; my_kfree((void **)&conn->rx_buf, "rx_buf");out2: printk("%s Disconnected from %s:%s\n", current->comm, ip_string, port_string);#ifdef ISCSI_STATS remove_iscsi_proc_entry((void *)conn, CONNECTION);#endifout1: sock_release(conn->sock); conn->sock = NULL; goto out;}/**************************************************************************** * when called, NO LOCKS SHOULD BE LOCKED! * Called only by create_session() to * 1. initialize a new session structure * 2. create a new first connection for the session * 3. connect to the target * 4. conduct the complete login phase with the target * * Return value: =1 on redirection * =0 on all other successes, * <0 on failure ****************************************************************************/static intinit_session(struct session *sess, struct connection *conn, __u32 lun, struct iscsi_targetdata *targ_data, struct sockaddr **redirect_ip_address, int *redirect_ip_length){ int retval = 0; TRACE(TRACE_ENTER_LEAVE, "Enter init_session, sess %p\n", sess); /* if not already allocated, allocate now - new 18_04 SAI */ if (!sess->oper_param) { /* finish allocating remaining structs * new struct session points to */ sess->oper_param = (struct session_operational_parameters *) my_kmalloc(sizeof(struct session_operational_parameters), "session oper_param"); if (unlikely(sess->oper_param == NULL)) { retval = -ENOMEM; goto out; } } TRACE(TRACE_ISCSI, "Create session for target %u lun %u CID %u\n", sess->scsi_target_id, lun, conn->connection_id);#ifdef ISCSI_STATS add_iscsi_proc_entry((void*)sess, SESSION);#endif /* Connect to the target and go through the complete login phase */ /* chap and srp support - CHONG */ retval = init_connection(conn, LEADING_ONLY | INITIAL_ONLY | ALL, *sess->session_params, targ_data, redirect_ip_address, redirect_ip_length); if (unlikely(retval != 0)) goto out2; sess->session_state = SESSION_LOGGED_IN; /* successfully created a new connection for a new session * Set up the session-wide negotiated operational parameters for this * new session */ set_session_parameters(sess->oper_param, *sess->session_params); TRACE(TRACE_DEBUG, "ErrorRecoveryLevel %u\n", sess->oper_param->ErrorRecoveryLevel); /* force use of snack when error recovery is in effect - RDR * Draft 20, Section 10.16 SNACK Request * "If the implementation supports ErrorRecoveryLevel greater than * zero, it MUST support all SNACK types." */ if (sess->oper_param->ErrorRecoveryLevel > 0) { sess->init_snack_flag |= (DATA_SNACK_ENABLE | STATUS_SNACK_ENABLE); }out: TRACE(TRACE_ENTER_LEAVE, "Leave init_session, retval %d\n", retval); return retval;out2:#ifdef ISCSI_STATS remove_iscsi_proc_entry((void*)sess, SESSION);#endif my_kfree((void **)&sess->oper_param, "session oper_param"); goto out;}/* * when called, NO LOCKS SHOULD BE LOCKED! * free up the memory allocated to a session struct, but not any connection * structs it might point to, which must already have been freed up. * Except for those connection structs, undoes the allocations in * build_session_skeleton() and those that might come later, * in the reverse order */static voidunbuild_session_skeleton( struct session *old_session ){ struct command *command; struct r2t_cookie *cookie; struct list_head *lptr, *next; /* done with unused r2t cookie structures */ list_for_each_safe(lptr, next, &old_session->free_r2t_cookies) { list_del(lptr); cookie = list_entry(lptr, struct r2t_cookie, link); my_kfree((void **)&cookie, "r2t cookie"); } /* done with unused command structures */ list_for_each_safe(lptr, next, &old_session->free_commands) { list_del(lptr); command = list_entry(lptr, struct command, link); my_kfree((void **)&command, "command"); }#ifdef ISCSI_STATS my_kfree((void **)&old_session->sess_stats, "session_stats");#endif if (old_session->session_params) { /* done with the session's parameter table */ param_tbl_uncpy(*old_session->session_params); my_kfree((void **)&old_session->session_params, "session param_tbl"); } /* done with the session structure itself */ my_kfree((void **)&old_session, "session");}/* * when called, NO LOCKS SHOULD BE LOCKED! * create and initialize a session struct and its first connection struct */static struct session *build_session_skeleton(__u32 target, struct sockaddr *ip_address, int ip_length, __u32 lun, __u32 cid){ struct session *new_session; struct connection *conn; struct iscsi_targetdata *targ_data; new_session = (struct session *)my_kmalloc(sizeof(struct session), "session"); if (unlikely(new_session == NULL)) { goto out1; } /* reset all fields in new struct session to 0 */ memset(new_session, 0, sizeof(struct session)); /* initialize most of the new struct session fields here */ new_session->sess_lock = UNH_LOCK_UNLOCKED; INIT_LIST_HEAD(&new_session->free_commands); INIT_LIST_HEAD(&new_session->free_r2t_cookies); new_session->scsi_target_id = target; new_session->n_luns_in_session = 1; new_session->lun_bits = 1 << lun; new_session->session_state = SESSION_NOT_PRESENT; new_session->cur_task_tag = 88888; /* something unique */ new_session->cur_cmd_sn = 22222; /* something unique */ new_session->exp_cmd_sn = new_session->cur_cmd_sn + 1; new_session->max_cmd_sn = new_session->exp_cmd_sn; init_timer(&new_session->connrec_timer); targ_data = &global_hostdata->target_data[target]; /* use the configured values to initialize following fields */ new_session->session_flags = targ_data->init_sess_flags; new_session->init_conn_flags = targ_data->init_conn_flags; new_session->nop_period = targ_data->nop_period; TRACE(TRACE_TIMERS, "new session nop_period %u\n", new_session->nop_period); /* Added data and status snack support - SAI */ new_session->init_snack_flag = targ_data->init_snack_flag; /* Added the retransmit wait period - SAI */ new_session->retran_period = targ_data->retran_period; /* Store the connection scheduling scheme - SAI */ new_session->sched_scheme = targ_data->sched_scheme; /* allocate space for configured parameters */ new_session->session_params = my_kmalloc(MAX_CONFIG_PARAMS * sizeof(struct parameter_type), "session param_tbl"); if (unlikely(new_session->session_params == NULL)) { goto out_err; } /* init session parameters with copy of configured parameter table */ param_tbl_cpy(*new_session->session_params, targ_data->param_tbl);#ifdef ISCSI_STATS /* get stats structure */ new_session->sess_stats = (struct iscsi_session_stats*)my_kmalloc(sizeof(struct iscsi_session_stats), "session_stats"); if (unlikely(new_session->sess_stats == NULL)) { goto out_err; } /* reset all the stats field */ memset(new_session->sess_stats, 0, sizeof(struct iscsi_session_stats));#endif /* create the first connection on this session */ conn = (struct connection *)my_kmalloc(sizeof(struct connection), "connection"); if (unlikely(conn == NULL)) { /* no memory for new connection structure */ goto out_err; } /* reset all fields in new struct connection */ memset(conn, 0, sizeof(struct connection)); conn->connection_id = cid; /* target's default MaxRecvDataSegmentLength */ conn->max_send_length = 8192; /* initiator's MaxRecvDataSegmentLength */ conn->max_recv_length = 8192; conn->nop_counter = 1; conn->my_session = new_session; conn->connection_flags = new_session->init_conn_flags; conn->connection_state = CONNECTION_NOT_PRESENT; init_MUTEX_LOCKED(&conn->rx_done_sem); init_MUTEX_LOCKED(&conn->tx_sem); init_MUTEX_LOCKED(&conn->tx_done_sem); init_MUTEX_LOCKED(&conn->task_mgt_sem); init_timer(&conn->tx_timer); INIT_LIST_HEAD(&conn->pending_commands); INIT_LIST_HEAD(&conn->r2t_list); conn->ip_address = ip_address; conn->ip_length = ip_length; /* point fields in new session at new connection */ new_session->nconnections = 1; new_session->connection_head = conn; new_session->rr_conn_head = conn; /* pre-allocate maximum number command structures session may use * (one extra in case of task-management and/or nopout commands) */ if (unlikely(preallocate_commands(new_session) == 0)) { goto out_err; }out: return new_session;out_err: unbuild_session_skeleton(new_session);out1: TRACE(TRACE_NET, "Free ip_address %p\n", ip_address); my_kfree((void **)&ip_address, "ip_address"); goto out;}static intadd_session_to_hostdata(struct connection *new_connection, __u32 lun, struct session *new_session, struct Scsi_Host *host);/**************************************************************************** * when called, NO LOCKS SHOULD BE LOCKED! * executed by rx thread or tx thread or init_recovery thread or command process * Creates and initializes a new session and its first connection struct by * calling corresponding functions. It then tries to connect to the target. * Called from iscsi_initiator_proc_info() when a line such as * "iscsi_initiator ip 1234abcd port 4000 target 1 lun 2 cid 3" * is written to /proc/scsi/iscsi_initiator/0 * also called from create_rec_conn() to create a recovery connection * Return value: * =1 on success -- new session added, logged in, now in FFP * =2 on success -- new lun added to existing session * =0 on success -- new connection added, logged in, now in FFP * or new discovery session added, now in FFP * <0 on failure -- value is errno negated ****************************************************************************/intcreate_session(__u32 target, struct sockaddr *ip_address, int ip_length, __u32 lun, __u32 cid, struct Scsi_Host *host){ unsigned long lock_flags; int i, retval, redirect_count = 0; struct sockaddr *redirect_ip_address; int redirect_ip_length; struct session *new_session; struct connection *conn; struct iscsi_hostdata *hostdata = (struct iscsi_hostdata *) host->hostdata; if (unlikely(TRACE_TEST(TRACE_ENTER_LEAVE))) { char ip_string[INET6_ADDRSTRLEN+2]; char port_string[8]; if (cnv_inet_to_string(ip_address,ip_string,port_string) < 0) { /* should never happen */ TRACE_ERROR("bad ip_address\n"); TRACE(TRACE_NET, "Free ip_address %p\n", ip_address); my_kfree((void **)&ip_address, "ip_address"); /* software caused connection abort */ return -ECONNABORTED; } TRACE(TRACE_ENTER_LEAVE, "Enter create_session to %s:%s, " "target %u, lun %u, cid %u\n", ip_string, port_string, target, lun, cid); }retry: /* here to try again on a redirection */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -