📄 initiator_rx.c
字号:
size = related_command->SCpnt->request_bufflen - data_in_header->offset; else size = 0; } else { /* be sure this is not negative for use later on! */ over_flow_data_size = 0; } if (unlikely(TRACE_TEST(TRACE_DEBUG))) { TRACE(TRACE_DEBUG, "Local data offset %u, " "request length %d\n", related_command->data_offset, related_command->SCpnt->request_bufflen); TRACE(TRACE_DEBUG, "DataIn hdr data offset %u, payload len %u\n", data_in_header->offset, size); } if (related_command->recvd_length == 0) { /* this is first PDU in a sequence */ related_command->r2t_range_list.offset = data_in_header->offset; /* can sequences be out-of-order? */ if (unlikely(!related_session->oper_param ->DataSequenceInOrder)){ /* DataSequenceInOrder==No, so seqs can be * out-of-order */ related_command->data_offset = data_in_header->offset; } /* can the PDU's within a sequence be out-of-order? */ if (unlikely(!related_session->oper_param ->DataPDUInOrder)) { /* DataPDUInOrder==No, so PDUs can be * out-of-order */ related_command->pdu_range_list.limit = 0; related_command->pdu_range_list.offset = ALL_ONES; } } /* can the PDU's within a sequence be out-of-order? */ if (unlikely(!related_session->oper_param->DataPDUInOrder)) { /* DataPDUInOrder==No, so PDU can be out-of-order */ __u32 limit; if (related_command->pdu_range_list.offset > data_in_header->offset) { /* this is smallest offset seen so far */ related_command->pdu_range_list.offset = data_in_header->offset; } limit = data_in_header->offset + size; if (related_command->pdu_range_list.limit < limit) { /* this is largest limit seen so far */ related_command->pdu_range_list.limit = limit; } /* each DataIn PDU is its own range */ merge_offset_length(&related_command->pdu_range_list, data_in_header->offset, size); } else { /* DataPDUInOrder==Yes, so PDU must be * in-order within seq. * Does buffer offset in DataIn header have * expected value? */ if (unlikely(related_command->data_offset != data_in_header->offset)) { TRACE_ERROR( "DataIn with ITT %u, DataSN %u, size " "%u, has offset %u, expected %u\n", local_itt, data_in_header->data_sn, size, data_in_header->offset, related_command->data_offset); } } if (unlikely(size == 0)) { TRACE_WARNING("DataIn with ITT %u, DataSN %u, " "offset %u, has no data\n", local_itt, data_in_header->data_sn, data_in_header->offset); } else { received = recv_data_in_data(current_connection, related_command, data_in_header, &size, over_flow_data_size, &over_flow_buffer); if (unlikely(received <= 0)) goto out; /* data in the DataIn was received correctly, * update amount of data transfered so far in this seq */ related_command->data_offset += size; related_command->recvd_length += size;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check that we have not received more data * than allowed in one input sequence */ if (unlikely(related_command->recvd_length > related_session->oper_param->MaxBurstLength)){ TRACE_ERROR( "DataIn with ITT %u gives sequence with" " %u bytes, more than %u allowed by " "%s\n", local_itt, related_command->recvd_length, related_session->oper_param ->MaxBurstLength, "MaxBurstLength"); }#endif /* update amount of data transfered so far in this cmd*/ related_command->r2t_range_list.limit += size; related_command->cmd_error_size += size; /* if this is the last DataIn PDU expected for the * corresponding SCSI Command, check that F_BIT is set */ if (related_command->r2t_range_list.limit >= related_command->SCpnt->request_bufflen) { /* last rexmitted DataIn PDU may not have * F bit set */ if (unlikely(!(data_in_header->flags & F_BIT) && related_command->cmd_error_state != CMD_USING_SNACK)) { TRACE_ERROR( "F_BIT not set on last expected" " DataIn with ITT %u\n", local_itt); /* turn it on now */ data_in_header->flags |= F_BIT; } } } if ((data_in_header->flags & F_BIT)) { /* this is last DataIn PDU in a sequence, set up for * any new sequence that may follow this one */ if (unlikely(!related_session->oper_param ->DataPDUInOrder)) { /* DataPDUInOrder==No, pdus can be * out-of-order within a sequence */ check_range_list_complete(&related_command-> pdu_range_list); free_range_list(&related_command-> pdu_range_list); /* set up offset to first pdu in this sequence*/ related_command->r2t_range_list.offset = related_command->pdu_range_list.offset; } if (unlikely(!related_session->oper_param ->DataSequenceInOrder)){ /* DataSequenceInOrder==No, sequences can * be out-of-order */ merge_offset_length(&related_command-> r2t_range_list, related_command-> r2t_range_list.offset, related_command-> recvd_length); } else if (unlikely(related_command ->r2t_range_list.offset + related_command->recvd_length != related_command->r2t_range_list.limit)) { /* in-order sequence not in-order */ if (related_command->cmd_error_state == CMD_OK_SO_FAR) { /* avoid cascading error messages * during error recovery */ TRACE_ERROR( "In-order sequence started at " "offset %u, expected to start at " "%u\n", related_command->r2t_range_list. offset, related_command->r2t_range_list. limit - related_command->recvd_length); } } /* mark that next DataIn PDU (if any) starts * a new sequence */ related_command->recvd_length = 0; } if (unlikely(related_command->cmd_error_state == CMD_USING_SNACK)) { /* this DataIn is a reply to previous SNACK from us */ related_command->cmd_error_runlen -= 1; if (related_command->cmd_error_runlen == 0) { /* this is last DataIn from previous SNACK */ related_command->cmd_error_state=CMD_OK_SO_FAR; /* now we can acknowledge the stat_sn if a * DataIn S=1 or SCSI Response originally * caused us to send the SNACK */ if (current_connection->increment) { if (!(data_in_header->flags & S_BIT)) { current_connection->exp_stat_sn++; data_in_header->flags |= S_BIT; } } else { /* make it look like this pdu was the * one that had the original A bit set * by restoring fields saved from the * DataIn pdu that started the rexmit */ data_in_header->flags |= A_BIT; data_in_header->target_xfer_tag = related_command->abit_ttt; data_in_header->lun = related_command->abit_lun; related_command->data_in_sn = related_command->abit_in_sn; related_command->data_offset = related_command->abit_offset; } } } if (unlikely((data_in_header->flags & A_BIT) && related_session->oper_param->ErrorRecoveryLevel>0)) { if (related_command->cmd_error_state == CMD_OK_SO_FAR) { /* send target the DataACK SNACK he requested */ err_rec.curr_conn = current_connection; err_rec.related_cmd = related_command; err_rec.err_type = -1; received = init_send_snack(&err_rec, related_command->data_in_sn, 0, DATACK_SNACK); if (received <= 0) goto out; } else if (related_command->cmd_error_state == CMD_NEEDS_SNACK) { /* time to send a snack to get erroneous * DataIn pdus retransmitted */ received=send_data_ack_snack(current_connection, related_command, 0); if (received <= 0) goto out; } else {/* should never happen */ TRACE_ERROR("got DataIN with A_BIT set but " "cmd_error_state %d\n", related_command->cmd_error_state); } } if (data_in_header->flags & S_BIT) { /* this command is a "phase collapse" with "good" * status or is the last DataIn pdu retransmitted * as part of a recovery triggered by S_BIT or * scsi response */ TRACE(TRACE_DEBUG, "Phase collapse, ITT %u, " "recvd_length %u, data_offset %u, " "request_bufflen %u, recv_so_far %u, " "data_in_sn %u\n", local_itt, related_command->recvd_length, related_command->data_offset, related_command->SCpnt->request_bufflen, related_command->r2t_range_list.limit, related_command->data_in_sn); received = do_scsi_response(current_connection, related_command, (struct iscsi_targ_scsi_rsp *) data_in_header, 0, NULL); } }out: if (unlikely(over_flow_buffer != NULL)) my_kfree((void **) &over_flow_buffer, "local buf"); TRACE(TRACE_ENTER_LEAVE, "Leave rx_data, retval %d\n", received); return received;}static int __attribute__ ((no_instrument_function))rx_pack_cookie_from_pdu( struct session *related_session, struct connection *current_connection, struct command *related_command , struct iscsi_targ_r2t *r2t_header, __u32 local_itt, __u32 offset, __u32 xfer_len);/**************************************************************************** * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called only by iscsi_initiator_rx_thread(). * This function processes the R2T PDU and sets up the TCP buffers for the * first iSCSI DataOut PDU to be sent out to the target. It wakes up the * tx thread so that it can send DataOut PDU to the target. * Parameters: current_connection which is a ptr to the connection struct * where the R2T header was received. * Return Value: >0 success * =0 on failure, session lock is locked * <0 on failure, session lock is NOT locked ****************************************************************************/static intrx_r2t(struct connection *current_connection, __u32 local_itt, struct command *related_command){ struct iscsi_targ_r2t *r2t_header; struct session *related_session; struct init_error_rec err_rec; int delta, delta2, retval = 1; __u32 r2t_sn, offset, xfer_len; struct r2t_cookie *cookie; TRACE(TRACE_ENTER_LEAVE, "Enter rx_r2t, current_connection %p\n", current_connection); r2t_header = (struct iscsi_targ_r2t *) current_connection->rx_buf; r2t_sn = ntohl(r2t_header->r2t_sn); offset = ntohl(r2t_header->offset); xfer_len = ntohl(r2t_header->xfer_len); if (unlikely(TRACE_TEST(TRACE_DEBUG))) { debug_print_ip(current_connection, "R2T"); } related_session = current_connection->my_session;#ifdef ISCSI_CHECK_PDU_FORMAT /* Check if reserved fields are zero or not */ if (unlikely(!((r2t_header->flags & ~F_BIT) == 0 && r2t_header->rsvd2 == 0))) { reserved_not_0("R2T"); }#endif if (likely(related_command != NULL)) { /* target is responding to this command, so it does not * need to be sent again on a retransmission */ related_command->cmd_state &= ~CMD_STATE_REXMIT_ORIG; /* is this R2T the correct sequence of R2Ts for this command? */ /* Draft 20, Section 10.8.2 R2TSN * "R2TSN is the R2T PDU input PDU number within the command * identified by the Initiator Task Tag." */ /* new - SAI */ delta = related_command->r2t_sn - r2t_sn; delta2 = related_command->data_offset - offset; if (unlikely(delta != 0)) { if (related_session->oper_param->ErrorRecoveryLevel > 0 && delta == 1 && delta2 > 0) { /* only one outstanding R2T supported * for error recovery levels > 0. * If an R2T seq. repeats due to * inherent timeout from Target * either due to lost or delayed * DataOuts, remove the old R2T * cookie and recreate a new one. * Remember to re-transmit all * DataOuts requested by the R2T. * - new 18_04 - SAI */ TRACE_WARNING("Recovery R2T for ITT %u has " "R2TSN %u, expected %u\n", local_itt, r2t_sn, related_command->r2t_sn); if (!list_empty(&related_command->r2t_cookies)){ /* we did not send the cookie's * remaining xfer length */ cookie = list_entry(related_command ->r2t_cookies.next, struct r2t_cookie, link); related_command->data_offset -= cookie-> r2t_xfer_length; free_r2t_cookie(current_connection, related_command, cookie); } related_command->r2t_sn--; TRACE(TRACE_ERROR_RECOVERY, "Got Recovery R2T, ITT %u, " "R2TSN %u, offset %u, DDTL %u\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -