📄 iscsi_initiator.c
字号:
/* turn on (almost) all tracing while processing an abort */ TRACE_GET(save_trace); TRACE_SET(TRACE_ALL & ~(TRACE_ISCSI_FULL|TRACE_ENTER_LEAVE|TRACE_MY_MEMORY)); TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_initiator_abort\n");/* RDR */#ifndef K26 /* unlock the lock obtained by the scsi midlevel before calling us */ spin_unlock(&io_request_lock);#endif /* get exclusive access to the iscsi structures */ if (!find_aborted_command(Cmnd, &related_session, &related_connection, &related_command, 1, &lock_flags)) { goto out; } /* Successfully found the matching command to be aborted. * Corresponding session, connection and command are valid. * Session lock is held. Mark this command as being aborted. */ related_command->cmd_state |= CMD_STATE_ABORTING; if (related_command->cmd_state & CMD_STATE_TXSTARTED) { /* this command was previously sent to target, so we now have to send a task management function command to the target */ tm_send_and_wait(Cmnd, related_session, related_connection, &related_command, &lock_flags); if (related_command == NULL ) goto out_session_lock_held; } retval = SUCCESS; /* Free command struct for the SCSI command that had to be aborted */ /* error recovery - SAI */ Cmnd->result = DID_ABORT << 16; related_command->cmd_state |= CMD_STATE_RXDONE | CMD_STATE_TXDONE; free_pending_command(related_command, related_connection); TRACE(TRACE_DEBUG, "Freed aborted command, ITT %u\n", related_command->init_task_tag);out_session_lock_held: UNH_UNLOCK(&related_session->sess_lock, lock_flags);out:/* RDR */#ifndef K26 /* get back lock so caller in scsi midlevel can release it! */ spin_lock(&io_request_lock);#endif TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_initiator_abort, 0x%04x\n", retval); /* restore tracing to what it was when we came in here */ TRACE_SET(save_trace); return retval;}/****************************************************************************** This function is called by the SCSI Mid-level.* (via the eh_device_reset_handler field in the* Scsi_Host_Template driver_template)* Still need to implement this function!!*****************************************************************************/static intiscsi_initiator_reset(struct scsi_cmnd * Cmnd){ TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_initiator_reset\n"); TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_initiator_reset, 0x%04x\n", SUCCESS); return SUCCESS;}static intscan_redirect_address(char *string, struct sockaddr **ip_address, int *ip_length){ int retval; char *ptr; if (*string == '[') { /* start of a bracketed IPv6 address */ if ((ptr = strchr(string, ']')) == NULL) { TRACE_ERROR("Illegal bracketed IPv6 address %s\n", string); retval = -ECONNABORTED; } else { /* see if a port was supplied or not */ if (*(ptr+1) == ':') { ptr++; } else { ptr = ISCSI_WKP_STRING; } if ((retval = cnv_string_to_inet(string+1, ptr, ip_address, ip_length)) != AF_INET6) { if (retval >= 0) { TRACE_ERROR("Illegal bracketed IPv6 " "address %s\n", string); retval = -ECONNABORTED; } } } } else { /* must be start of an IPv4 address */ if ((ptr = strchr(string, ':'))) { ptr++; } else { ptr = ISCSI_WKP_STRING; } if ((retval = cnv_string_to_inet(string, ptr, ip_address, ip_length)) != AF_INET) { if (retval >= 0) { TRACE_ERROR("Illegal IPv4 address %s\n",string); retval = -ECONNABORTED; } } } return retval;}/* set up the 6-byte isid from values configured for this target * configured values limited to 2 bits for type, 24 bits for number & qualifier * * RFC 3720 Section 10.12.5 ISID * T = 00b * A&B - 22-bit OUI * C&D - 24-bit qualifier * T = 01b * A - 6-bit Reserved * B&C - 24-bit IANA Enterprise Number * D - 16-bit Qualifier * T = 10b * A - 6-bit Reserved * B&C - 24-bit Random number * D - 16-bit Qualifier * T = 11b * A, B, C, D - Reserved */static void __attribute__ ((no_instrument_function))setup_isid(struct iscsi_targetdata *targ_data, __u32 *isid){ __u32 temp; __u16 qual, *ptr16 = (__u16 *)&isid[1]; temp = targ_data->isid_type << 30; qual = targ_data->isid_qualifier; switch (targ_data->isid_type) { case 0: /* OUI Format */ temp |= ((targ_data->isid_number & MASK_22_BITS)<<8) | ((targ_data->isid_qualifier >> 16) & MASK_8_BITS); break; case 1: /* EN Format */ case 2: /* Random Format */ temp |= targ_data->isid_number; break; case 3: /* Reserved Format */ qual = 0; break; } /* switch */ *isid = htonl(temp); *ptr16 = htons(qual);}/****************************************************************************** Sets the session operation parameters and changes the session* state to LOGGED_IN, meaning the initiator is in done with login phase.* Called only from init_connection()* Return value: =1 on redirection* =0 on any other success* <0 on failure*****************************************************************************/static intiscsi_initiator_login(struct connection *current_connection, __u32 when_called, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], struct auth_parameter_type auth_param, struct iscsi_targetdata *targ_data, struct sockaddr **redirect_ip_address, int *redirect_ip_length)/* chap and srp support - CHONG */{ int retval = 0, cid; int login_task_tag; __u32 isid[2]; struct session *current_session; __u32 pdu_version_number = 0; struct parameter_type *p;#ifdef ISCSI_STATS unsigned long flags;#endif TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_initiator_login, current connection %p\n", current_connection); current_session = current_connection->my_session; /* set up the 6-byte isid */ setup_isid(targ_data, isid); cid = current_connection->connection_id; /* for offset 20 */ /* initialize task tag for the whole login process */ /* then update the session's task tag counter */ login_task_tag = current_session->cur_task_tag++; TRACE(TRACE_DEBUG, "iscsi_initiator_login pdu_version_number %u\n", pdu_version_number); /* In login phase always disable Header & Data Digests */ current_connection->connection_flags &= ~USE_HEADERDIGEST; current_connection->connection_flags &= ~USE_DATADIGEST; current_connection->basic_hdr_len = ISCSI_HDR_LEN; retval = initiator_parameter_negotiate(current_connection->sock, p_param_tbl, auth_param, ¤t_session->cur_cmd_sn, login_task_tag, isid, ¤t_session->tsih, cid, ¤t_connection->connection_flags, pdu_version_number, when_called, ¤t_connection->exp_stat_sn, ¤t_connection->max_send_length, ¤t_connection->max_recv_length); if (unlikely(retval < 0)) { TRACE(TRACE_ISCSI, "parameter negotiation failed\n"); /* software caused connection abort */ retval = -ECONNABORTED; goto out; } else if (likely(retval == 0)) { /* new connection negotiation finished successfully */ if (current_connection->connection_flags & USE_HEADERDIGEST) current_connection->basic_hdr_len += CRC_LEN; current_connection->connection_state = CONNECTION_LOGGED_IN;#ifdef ISCSI_STATS UNH_LOCK(&host_data_lock, flags); global_hostdata->instance_stats.iscsi_intr_login_accept_rsp++; UNH_UNLOCK(&host_data_lock, flags);#endif } else { /* have a redirection attempt */#ifdef ISCSI_STATS UNH_LOCK(&host_data_lock, flags); global_hostdata->instance_stats.iscsi_intr_login_redirect_rsp++; UNH_UNLOCK(&host_data_lock, flags);#endif p = find_parameter(TARGETADDRESS, p_param_tbl); if (unlikely(p == NULL)) { /* could not find TargetAddress key */ TRACE_ERROR("Cannot find %s key\n", TARGETADDRESS); retval = -ECONNABORTED; } else if (!IS_KEY_GOT_FROM_OTHER_SIDE(p->neg_info)) { /* target never sent us this key */ TRACE_ERROR ("Target never sent TargetAddr key on Redirectn\n"); retval = -ECONNABORTED; } else if (scan_redirect_address(p->str_value, redirect_ip_address, redirect_ip_length) < 0) { retval = -ECONNABORTED; } }out:#ifdef ISCSI_STATS if (retval == -ECONNABORTED) { struct timeval tv; /* * Do do_gettimeofday() and find_parameter() * before holding the lock to reduce the lock hold * up time. */ do_gettimeofday(&tv); p = find_parameter(TARGETNAME, p_param_tbl); UNH_LOCK(&host_data_lock, flags); global_hostdata->instance_stats.iscsi_intr_login_failure++; global_hostdata->instance_stats.iscsi_intr_last_failure_time=tv; if (p != NULL && p->str_value) { strreplace(&(global_hostdata->instance_stats.iscsi_intr_last_tgt_failure_name), p->str_value); } if (current_connection->ip_address) { if (!global_hostdata->instance_stats.iscsi_intr_last_tgt_failure_address) global_hostdata->instance_stats.iscsi_intr_last_tgt_failure_address = my_kmalloc(sizeof(struct sockaddr), "failure address"); if (global_hostdata->instance_stats.iscsi_intr_last_tgt_failure_address) memcpy(global_hostdata->instance_stats.iscsi_intr_last_tgt_failure_address, current_connection->ip_address, sizeof(struct sockaddr)); } UNH_UNLOCK(&host_data_lock, flags); }#endif TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_initiator_login, retval %d\n", retval); return retval;}/**************************************************************************** * when called, NO LOCKS SHOULD BE LOCKED! * Initializes the fields of the first connection in a new session, * connects to a remote target, logs in to it, * and creates the rx_thread for that connection * if full feature phase has been attained successfully. * Called by create_session() when adding new connection to existing session * and by init_session() when this is first connection in a new session. * Return value: =1 for redirection, * =0 for any other success, * <0 for error ****************************************************************************/static intinit_connection(struct connection *conn, __u32 when_called, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], struct iscsi_targetdata *targ_data, struct sockaddr **redirect_ip_address, int *redirect_ip_length){ int retval; struct auth_parameter_type new_authparam; char ip_string[INET6_ADDRSTRLEN+2], port_string[8]; char local_ip_string[INET6_ADDRSTRLEN+2], local_port_string[8]; int local_addr_len; /* extract address family into retval, ip address and port in strings */ retval = cnv_inet_to_string(conn->ip_address, ip_string, port_string); if (unlikely(retval < 0)) { TRACE_ERROR("%s\n", ip_string); goto out0; } TRACE(TRACE_ENTER_LEAVE, "Enter init_connection, conn %p, sess %p\n", conn, conn->my_session); TRACE(TRACE_ISCSI, "Create connection %p to target %u CID %u " "at %s:%s family %d\n", conn, conn->my_session->scsi_target_id, conn->connection_id, ip_string, port_string, retval); /* finish allocating fields of new struct connection */#ifdef FC2 retval = sock_create(retval, SOCK_STREAM, 0, &conn->sock, 0);#else retval = sock_create(retval, SOCK_STREAM, 0, &conn->sock);#endif if (unlikely(retval < 0)) { TRACE_ERROR("Can't create socket, error %d\n", -retval); goto out0; } TRACE(TRACE_NET, "Created socket %p\n", conn->sock);/* Ming Zhang, mingz@ele.uri.edu */#ifndef K26 /* to keep tcp from strangling due to lack of memory, force tcp's calls to alloc_skb() to use atomic allocation, not GFP_KERNEL */ conn->sock->sk->allocation = GFP_ATOMIC;#endif /* auth support- CHONG */ new_authparam.auth_flags = 0; new_authparam.chap_local_ctx = NULL; new_authparam.chap_peer_ctx = NULL; new_authparam.srp_ctx = NULL; retval = conn->sock->ops->connect(conn->sock, conn->ip_address, conn->ip_length, 0); printk("%s to target %u cid %u at %s:%s conn %p\n", retval < 0 ? "***ERROR*** can't connect" : "Connected", conn->my_session->scsi_target_id, conn->connection_id, ip_string, port_string, conn); if (unlikely(retval < 0)) { /* turn on (almost) all tracing after this call */ if (TRACE_TEST(TRACE_DEBUG)) { TRACE_SET(TRACE_ALL & ~(TRACE_ISCSI_FULL|TRACE_ENTER_LEAVE|TRACE_MY_MEMORY)); } goto out1; } /* Turn off the Nagle Algorithm on this connection */ tcp_nagle_off(conn->sock); /* * Get the socket details - local IP/port * You should't fail here unless you have failed in * connect() call in which case, you won't be here. */ local_addr_len = conn->ip_length; /* value-result parameter */ if (conn->local_ip_address == NULL) conn->local_ip_address = my_kmalloc(sizeof(struct sockaddr), "local_ip_address"); if (conn->local_ip_address != NULL && conn->sock->ops->getname(conn->sock, conn->local_ip_address, &local_addr_len, 0) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -