📄 initiator_tx.c
字号:
return 1;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by check_for_retransmit(). * Enter the xmit state of a command into state 3 * by issuing SNACK requests */static inttx_retransmit_state3(struct session *current_session, struct connection *current_connection, struct command *current_command){ int DInOrder = current_session->oper_param->DataSequenceInOrder; int PInOrder = current_session->oper_param->DataPDUInOrder; struct scsi_cmnd *SCpnt = current_command->SCpnt; struct init_error_rec err_rec; current_command->activity_flg = 3; if (likely(current_command->SCpnt != NULL)) { do { err_rec.curr_conn = current_connection; err_rec.related_cmd = current_command; if (current_command->SCpnt->sc_data_direction == SCSI_DATA_READ) { /* take care of out-of-order PDUs too -- * new 18_04 SAI */ if ( likely(DInOrder && PInOrder)) { if (current_command->data_offset != SCpnt->request_bufflen) { init_send_snack (&err_rec, current_command->data_in_sn, 0, DATA_R2T_SNACK); break; } } else { if (check_range_list_complete( ¤t_command-> r2t_range_list) > 0) { init_send_snack( &err_rec, current_command->data_in_sn, 0, DATA_R2T_SNACK); break; } } } init_send_snack(&err_rec, current_connection->exp_stat_sn, 1, STATUS_SNACK); } while (0); /* Timestamp command transmission time - SAI */ current_command->time_stamp = jiffies; } return 1 ;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * command and determines if the commands needs re-sent * during 3 states: * State 0 - Entered after original cmd is sent but NO reply is recv. * State 0 sets up the command again and re-xmits. * State 1/2 - Entered after state 0. Is sets up a no-op ping to see * if the target is alive. This state is executed twice if * necessary. * State 3 - State 3 uses SNACKS requests to fill -in lost or dropped * data PDU's. * * 0: * returns 1 if ok, 0 if nothing works and thread should terminate * Retransmit a loss/dropped command */static int __attribute__ ((no_instrument_function))check_for_retransmit(struct session *current_session, struct connection *current_connection, struct command *current_command){ int retval = 1; long delta_t; if (unlikely(TRACE_TEST(TRACE_ERROR_RECOVERY))) { TRACE(TRACE_ERROR_RECOVERY, "check_for_retransmit: ITT %u, " "state 0x%08x, still_to_send %u\n", current_command->init_task_tag, current_command->cmd_state, current_command->still_to_send); } if (current_session->oper_param->ErrorRecoveryLevel > 0 && current_session->retran_period > 0) { /* If timer expired and no activity, assume command was lost * and re-transmit command - SAI */ delta_t = jiffies - (current_command->time_stamp + ((current_session->retran_period) * HZ)); if (delta_t >= 0) { /* nothing received for this command during last * retran_period seconds */ TRACE(TRACE_ERROR_RECOVERY, "Timeout, ITT %u, time_stamp %u, jiffies %lu, " "delta %ld retran_period %u, HZ %u, " "activity_flg %u\n", current_command->init_task_tag, current_command->time_stamp, jiffies, delta_t, current_session->retran_period, HZ, current_command->activity_flg); if (!current_command->activity_flg) { /* no reply from target, rexmit */ tx_retransmit_state1(current_session, current_connection, current_command); } else if (current_command->activity_flg == 1) { /* first timeout, allow 1 more * due to freezing */ tx_retransmit_state2(current_session, current_connection, current_command); } else if (current_command->activity_flg == 2) { /* for read commands, the data_in or * the scsi response could be lost * due to packet drops because of * bad connection or during connection * recovery. This function pro-actively * fills the gap in data-in pdus and * scsi responses. This uses the command * re-transmit timer for checking * and filling gaps - SAI */ retval = tx_retransmit_state3(current_session, current_connection, current_command); } else { /* * current_command->activity_flg == 3 * Retransmit, Nop and SNACK all failed * nothing works, shut this tx thread down */ retval = 0; } } } return retval;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called by ready_to_xmit() and iscsi_initiator_tx_thread(). * returns 0 if command is immediate or its CmdSN is NOT beyond MaxCmdSN * (i.e., it is ok to send it to target now) * returns 1 if command is non-immediate and its CmdSN is beyond MaxCmdSN */static intbeyond_window(struct session *current_session, struct connection *current_connection, struct command *current_command){ int retval = 0, delta; if (!(current_command->iscsi_cmd.opcode & I_BIT)) { /* non-immediate, is its sequence number * beyond target's window limit? */ delta = current_session->max_cmd_sn - ntohl(current_command->iscsi_cmd.cmd_sn); if (delta < 0) { /* yes, mark that tx thread needs to be awakened */ current_connection->connection_flags |= NEED_TX_WAKEUP; /* can't send this command now */ TRACE(TRACE_ISCSI_FULL, "Delay sending ITT %u: CmdSN " "%u beyond MaxCmdSN %u\n", current_command->init_task_tag, ntohl(current_command->iscsi_cmd.cmd_sn), current_session->max_cmd_sn); retval = 1; } } return retval;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * returns 0 if nothing to xmit for this command, * else size to xmit * returns -1 if this command was cut short */static intready_to_xmit(struct session *current_session, struct connection *current_connection, struct command *current_command){ int size; long delta_t; struct r2t_cookie *cookie; if (unlikely(current_connection->short_command != NULL)) { /* in the middle of a partial send */ if (current_connection->short_command != current_command) { /* not a partial send of this command, leave now */ size = 0; goto out; } delta_t = jiffies - current_command->tx_wait_to_send; if (delta_t < 0) { /* this command has not waited long enuf since * last partial send */ size = -1; current_connection->connection_flags |= NEED_TX_WAKEUP; goto out; } /* ready to resume after partial send, * everything already set up */ size = current_command->tx_size; } else if (unlikely(current_command->cmd_state & CMD_STATE_ABORTING)) { /* current command is being aborted, do not xmit anything */ size = 0; } else if ((size = current_command->tx_size) == 0) { /* current command has already been sent */ if (!list_empty(¤t_command->r2t_cookies)) { /* this command has an unsatisfied R2T ready to go */ cookie = list_entry(current_command->r2t_cookies.next, struct r2t_cookie, link); if (&cookie->order_link == current_connection->r2t_list.next) { /* this r2t is next to send on this connection*/ if ((int) cookie->r2t_xfer_length > 0) { /* still data left to send on this R2T*/ size = setup_dataoutpdu( current_connection, current_command, cookie); } else { /* should never happen */ TRACE_ERROR("Cookie r2t_xfer_length %d " "not positive, ITT %u\n", (int) cookie ->r2t_xfer_length, current_command ->init_task_tag); free_r2t_cookie(current_connection, current_command, cookie); goto out; } } } }out: return size;}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by do_tx_send(). * Finalize a PDU header just before it is about to be transmitted. * This requires inserting the latest ExpStatSN on this connection * and then computing the header CRC if enabled. * The PDU header is always pointed to by the first slot in tx_iov * and the slot for the CRC is always at the end of that header. */static void __attribute__ ((no_instrument_function))finalize_header(struct connection *conn, struct command *command){ struct generic_pdu *pdu; pdu = (struct generic_pdu *)command->tx_iov->iov_base; pdu->exp_stat_sn = htonl(conn->exp_stat_sn); /* compute and add the header digest if we are using them */ if (conn->connection_flags & USE_HEADERDIGEST) { pdu->header_digest = 0; do_crc((__u8 *)pdu, ISCSI_HDR_LEN, &pdu->header_digest); TRACE(TRACE_ISCSI_FULL, "Attach HeaderDigest\n"); } command->tx_sent_so_far = 0; /* nothing sent so far */ command->retransmit_tx_size = command->tx_size; command->header_complete = 1; /* don't come back here again */}/* * executed only by tx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_tx_thread(). * We have a command that needs to be sent on this connection * and target window is open enough to receive it. * session lock is held on entry and exit, * but is released during call to sock_sendmsg(). * returns : 1 on success, * 0 on incomplete send, * -1 on fatal error */static intdo_tx_send(struct session *current_session, struct connection *current_connection, struct command *current_command){ mm_segment_t oldfs; int size, sent, retval = 1, iovlen; struct iovec *iov; __u32 opcode;#if defined(CONFIG_ISCSI_DEBUG) char op_buf[16];#endif if (!current_command->header_complete) { finalize_header(current_connection, current_command); } /* mark that this command was sent to target */ current_command->cmd_state |= CMD_STATE_TXSTARTED; opcode = current_command->header_opcode & ISCSI_OPCODE; TRACE(TRACE_DEBUG, "%s Header opcode 0x%.2x flags 0x%.2x\n", current->comm, current_command->header_opcode, current_command->header_flags); iov = current_command->tx_iov; iovlen = current_command->tx_iovlen; size = current_command->tx_size; if ((sent = current_command->tx_sent_so_far) == 0) { /* first time sending this command, use original iovec */ TRACE(TRACE_ISCSI, "%s Send %s, ITT %u, %u bytes\n", current->comm, printable_iscsi_op(iov->iov_base, op_buf), current_command->init_task_tag, size); if (unlikely(TRACE_TEST(TRACE_ISCSI_FULL))) { print_iscsi_command(iov->iov_base); } } else { /* previously did partial send, may need to use copy of iovec */ TRACE(TRACE_ISCSI, "%s More 0x%02x, ITT %u, %u bytes\n", current->comm, opcode, current_command->init_task_tag, size); while (iov->iov_len <= sent) { /* all of this iov already sent */ sent -= iov->iov_len; iov++; iovlen--; } if (sent > 0) { /* copy the remaining iovecs so we can modify 1st one */ memcpy(current_command->tx_iov_copy, iov, iovlen * sizeof(struct iovec)); /* update copied iov to account for previous sends */ iov = current_command->tx_iov_copy; iov->iov_base += sent; iov->iov_len -= sent; } } /* set up the message header for sendmsg */ memset(¤t_command->tx_msghdr, 0, sizeof(struct msghdr)); current_command->tx_msghdr.msg_iov = iov; current_command->tx_msghdr.msg_iovlen = iovlen; current_command->tx_msghdr.msg_flags = current_command->cmd_msg_flags; /***** uncomment this to put tx thread into non-blocking mode ***** current_command->tx_msghdr.msg_flags |= MSG_NOSIGNAL | MSG_DONTWAIT; *****/ TRACE(TRACE_DEBUG, "--sending %d, ITT %u\n", size, current_command->init_task_tag); /* Timestamp the command transmission time - SAI */ current_command->time_stamp = jiffies; /* allow other threads to run while we send */ UNH_UNLOCK(¤t_session->sess_lock, current_connection->tx_lock_flags);#ifdef K26 if (use_sendpage(current_connection, current_command) && current_command->pindex > 0) { struct socket *sock = current_connection->sock; struct scatterlist *sg; int res = 0, total_len, total_sent = 0, first_offset; int left_in_header; int flags = MSG_MORE, padding = current_command->padding; total_len = size - padding; left_in_header = current_connection->basic_hdr_len - current_command->tx_sent_so_far; if (left_in_header > 0) { current_command->tx_msghdr.msg_iovlen = 1; oldfs = get_fs(); set_fs(get_ds()); res = sock_sendmsg(current_connection->sock, ¤t_command->tx_msghdr, left_in_header); set_fs(oldfs); if (res != left_in_header) { sent = res; goto finish; } total_len -= res; total_sent += res; first_offset = 0; } else { first_offset = sent; } sg = current_command->sg; if (current_command->tx_iovlen != iovlen) sg--; while (total_len > 0) { struct page *page = sg->page; int i, len; int sg_len = sg->length; int nr = (sg->offset + sg->length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; int offset = sg->offset + first_offset; sg_len -= first_offset; i = offset >> PAGE_SHIFT; offset = offset & (PAGE_SIZE - 1); for (; total_len > 0 && i < nr; i++) { if (sg_len + offset > PAGE_SIZE) len = PAGE_SIZE - offset; else len = sg_len; if (len > total_len) { len = total_len; } if (total_len == len) flags = 0; res = sock->ops->sendpage(sock, page, offset, len, flags); if (len != res) { if (res > 0) { sent = total_sent; goto finish; } else { if (res == -EAGAIN) { sent = total_sent; goto eagain; } sent = res; goto finish; } } page++; offset = 0; total_len -= res; sg_len -= res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -