📄 initiator_utilities.c
字号:
space_left = current_session->oper_param->FirstBurstLength - actual_immediate_data_length; /* assume no unsolicited DataOut pdus will follow this one */ new_command->cmd_msg_flags = 0; if (current_session->oper_param->InitialR2T || new_command->still_to_send == 0 || space_left <= 0) { /* set F bit as no separate unsolicted data PDUs can follow */ iscsi_cmd->flags |= F_BIT; } else if (!(current_session->oper_param->InitialR2T)) { /* we are allowed to send unsolicited data PDUs * after this command, but do we need to and * is there any burst space left to do so? */ if (new_command->still_to_send > 0 && space_left > 0) { /* still data left to send, and there is room in first * burst, so set up to send unsolicited data PDUs next */ if ((cookie = create_r2t_cookie(current_session)) != NULL) { cookie->offset = new_command->data_offset; cookie->r2t_xfer_length = new_command->still_to_send; if (new_command->still_to_send > space_left) cookie->r2t_xfer_length = space_left; hookup_r2t_cookie(cookie, current_session, current_connection, new_command, ALL_ONES); /* tell tcp DataOut pdus follow */ new_command->cmd_msg_flags = MSG_MORE; /* need to mark this in case of retransmission, * because xmitting the cookie will overwrite * the command iovector and both will have * to be set up again. */ new_command->cmd_state = CMD_STATE_REXMIT_ORIG; } } } /* fill in fields for tx thread */ new_command->tx_sent_so_far = 0; /* nothing sent so far */ new_command->retransmit_tx_size = new_command->tx_size; new_command->header_complete = 0; /* need to finish header */ /* These are used in do_tx_send() and rx_rsp(), both of which will not * see this until after we set them here. */ new_command->header_opcode = ISCSI_INIT_SCSI_CMND; new_command->header_flags = iscsi_cmd->flags;out: /* set the number of iov slots actually used */ new_command->tx_iovlen = count; if (unlikely(max_iov_count < count)) max_iov_count = count; /* keep track of max no. ever used */}/* * executed only by tx thread. * the session->sess_lock MUST be held by the calling process/thread. * * Called only from ready_to_xmit(). * At the time of the call, cookie is known to be first on related_command's * r2t_cookies list, it is known to be non-NULL, it is known to be at the * beginning of related_connection's order_link, and it is known to * have a positive xfer length. * * Called to build a DataOut pdu header in the "data" area of the * "related_command" if that area is currently unused (else does nothing). * The amount of data to send is controlled by the first "cookie" for * that command, but the location(s) and layout of the data in memory * are controlled by the SCpnt field in the "related_command" when * setting up the msghdr and io vector in the "related_command". * Returns number of bytes newly set up for transmission (0 if none). * * While writing, the following variables in the related_command maintain state: * tx_size number of bytes left to send in current xmission * (updated as each pdu is sent) * tx_sent_so_far number of bytes sent so far in current xmission * (updated as each pdu is sent) * retransmit_size number of original bytes in current xmission * still_to_send total number of bytes of data not yet sent for * this write command * (updated as each pdu is sent) * r2t_sn R2TSN expected in next R2T from target * data_offset offset expected in next in-order R2T from target * (updated as each R2T is received) * n_r2t_cookies number of elements in list r2t_cookies that were * created by R2Ts (excludes cookie created for * unsolicited DataOut pdus) * (1 cookie created as each R2T is received) * r2t_cookes list with 1 r2t_cookie for each unsatisfied R2T * (includes 1 r2t_cookie for any unsolicited pdus) * (cookies removed from list as satisfied) * header_opcode opcode of last command sent carrying data * (0x01 on WRITE, 0x05 for DataOut) * data area where DataOut pdu is built */intsetup_dataoutpdu(struct connection *related_connection, struct command *related_command, struct r2t_cookie *cookie){ int len, prev_offset, cur_offset, count, size; char *cur_ptr; struct iovec *iov; struct scatterlist *sg; struct session *related_session; int sglength; TRACE(TRACE_ENTER_LEAVE, "Enter setup_dataoutpdu\n"); size = 0; if (related_command->tx_size != 0) { /* command's single data slot is busy, don't overwrite it */ TRACE(TRACE_ISCSI_FULL, "Busy DataOut slot, ITT %u, tx_size %u\n", related_command->init_task_tag, related_command->tx_size); goto out; } /* set up the DataOut PDU in command's single data slot */ memset(&related_command->data, 0, ISCSI_HDR_LEN); related_command->data.opcode = ISCSI_INIT_SCSI_DATA_OUT; related_command->data.target_xfer_tag = cookie->target_xfer_tag; related_command->data.init_task_tag = htonl(related_command->init_task_tag); related_command->data.exp_stat_sn = htonl(related_connection->exp_stat_sn); related_command->data.data_sn = htonl(cookie->data_out_sn); /* assume this is not the last DataOut PDU to be * sent in this sequence */ related_session = related_connection->my_session; len = related_connection->max_send_length; if (cookie->r2t_xfer_length <= len) { /* bad assumption, this is last DataOut PDU in this seq */ len = cookie->r2t_xfer_length; related_command->data.flags |= F_BIT; } /* assume no DataOut pdus follow this one */ related_command->cmd_msg_flags = 0; related_command->tx_data_length = len; /* for tx stats */ related_command->data.length = htonl(len); related_command->still_to_send -= len; /* get offset into original SCSI CMD buffer of next byte to be sent */ if (unlikely(related_session->oper_param->DataPDUInOrder == 0)) { /* DataPDUInOrder==No, send Data Out PDUs backwards */ cookie->offset -= len; /* next Data Out PDU limit */ prev_offset = cookie->offset; /* this Data Out PDU offset */ } else { /* DataPDUInOrder==Yes, send Data Out PDUs in order */ prev_offset = cookie->offset; /* this Data Out PDU offset */ cookie->offset += len; /* next Data Out PDU offset */ } related_command->data.offset = htonl(prev_offset); TRACE(TRACE_DEBUG, "Setup DataOut PDU, offset %d, DSL %d, still_to_send %u\n", prev_offset, len, related_command->still_to_send); /* update values in related command cookie to account for this PDU */ cookie->data_out_sn++; /* Seqno of next Data Out PDU */ cookie->r2t_xfer_length -= len; /* total amount left to send */ if (((int)cookie->r2t_xfer_length) <= 0) { /* finished with this cookie */ free_r2t_cookie(related_connection, related_command, cookie); } /* set up the TCP io vector, beginning with no. of bytes to xfer */ size = related_connection->basic_hdr_len + len; iov = related_command->tx_iov; /* point at empty tx_iov[] */ /* DataOut pdu header built in separate "data" area of struct command */ iov->iov_len = related_connection->basic_hdr_len; iov->iov_base = &related_command->data; related_command->header_complete = 0; related_command->header_opcode = related_command->data.opcode; related_command->header_flags = related_command->data.flags;#ifdef K26 if (use_sendpage(related_connection, related_command)) { related_command->pindex = 0; related_command->padding = 0; }#endif /* now fill in the iovector to point to data to be sent */ iov++; count = 2; /* always at least 2 items in iovector */ related_command->data_checksum = 0; /* initialize data checksum */ if (related_command->SCpnt->use_sg > 0) { /* SCSI gave us a scatter-gather list */ sg = (struct scatterlist *) related_command->SCpnt ->request_buffer; cur_offset = 0;#ifdef K26 /* Convert page struct passed in SG * to kernel vaddr. We can sleep on this * call so have to release our lock. */ UNH_UNLOCK(&related_session->sess_lock, related_connection->tx_lock_flags); sg_dma_address(sg) = (dma_addr_t)kmap(sg->page); UNH_LOCK(&related_session->sess_lock, related_connection->tx_lock_flags); cur_ptr = (void *)sg_dma_address(sg);#else cur_ptr = sg->address;#endif /* skip thru scatterlist past data already sent */ while (cur_offset < prev_offset) {#ifdef K26 sglength = sg_dma_len(sg);#else sglength = sg->length;#endif if (cur_offset + sglength > prev_offset) { cur_ptr = cur_ptr + (prev_offset - cur_offset); cur_offset = prev_offset; } else { cur_offset += sglength; sg++;#ifdef K26 cur_ptr = (void *)sg_dma_address(sg);#else cur_ptr = sg->address;#endif } } /* sg now points at first list item to xfer */#ifdef K26 iov->iov_len = ((char *)(sg_dma_address(sg) + sg_dma_len(sg))) - cur_ptr; if (use_sendpage(related_connection, related_command)) { int offset = cur_ptr - (char *) sg_dma_address(sg); related_command->sg[related_command->pindex] = *sg; related_command->sg[related_command->pindex].length -= offset; related_command->sg[related_command->pindex].offset += offset; related_command->pindex++; }#else iov->iov_len = (sg->address + sg->length) - cur_ptr;#endif iov->iov_base = cur_ptr; sg++; len -= iov->iov_len; /* no. of bytes left to fill */ while (len > 0) { /* need to add another element in iovector, but first * compute the partial data digest if we are using them */ if (related_connection->connection_flags & USE_DATADIGEST) { do_crc(iov->iov_base, iov->iov_len, &related_command->data_checksum); } count++; iov++;#ifdef K26 iov->iov_base = (unsigned long *)sg_dma_address(sg); sglength = sg_dma_len(sg); if (use_sendpage(related_connection, related_command)) { related_command->sg[related_command->pindex] = *sg; related_command->pindex++; }#else iov->iov_base = sg->address; sglength = sg->length;#endif iov->iov_len = sglength; len -= sglength; sg++; } if (len < 0) { /* only need to send part of the last list item */ iov->iov_len += len; } } else { /* all the data is in one buffer (no scatter gather list) */ iov->iov_base = related_command->SCpnt->request_buffer + prev_offset; iov->iov_len = len; } /* now deal with any padding that is needed. * * Draft 20, Section 10.1 iSCSI PDU Length and Padding * "iSCSI PDUs are padded to the closest integer number of four byte * words. The padding bytes SHOULD be 0." */ len = (-size) & 3; if (unlikely(len != 0)) { /* need to send len pad bytes in another element in iovector * but first compute the partial data digest if we are * using them */ if (related_connection->connection_flags & USE_DATADIGEST) { do_crc(iov->iov_base, iov->iov_len, &related_command->data_checksum); } count++; iov++; iov->iov_base = &pad_bytes; iov->iov_len = len; size += len; /* is now a multiple of 4 */ TRACE(TRACE_ISCSI_FULL, "Attach %d pad bytes\n", len);#ifdef K26 if (use_sendpage(related_connection, related_command)) related_command->padding = len;#endif } /* now compute and add the final data digest if we are using them */ if (related_connection->connection_flags & USE_DATADIGEST) { do_crc(iov->iov_base, iov->iov_len, &related_command->data_checksum); count++; iov++; iov->iov_base = &related_command->data_checksum; iov->iov_len = CRC_LEN; size += CRC_LEN; TRACE(TRACE_ISCSI_FULL, "Attach DataDigest\n"); } /* finally save size and number of iovector elements in message header*/ related_command->tx_sent_so_far = 0; /* nothing sent yet */ related_command->tx_size = size; /* marks this "in use" */ /* in case of rexmit only */ related_command->retransmit_tx_size = size; related_command->tx_iovlen = count; /* no. of iovs used */ if (unlikely(max_iov_count < count)) { max_iov_count = count; } related_command->tx_wait_to_send = jiffies; /* can send it now */ if (!list_empty(&related_connection->r2t_list)) { /* tell tcp more DataOut pdus are ready to follow this one */ related_command->cmd_msg_flags = MSG_MORE; }out: TRACE(TRACE_ENTER_LEAVE, "Leave setup_dataoutpdu, size %u\n", size); return size;}/* "prints" statistics on iov usage into buf, * returns no. of chars printed. */intprint_iovs(char *buf){ if (buf == NULL) return printk("iscsi Maximum of %d iov slots used out of %d\n", max_iov_count, MAX_IOV_SLOTS); else return sprintf(buf, "Maximum of %d iov slots used out of %d\n", max_iov_count, MAX_IOV_SLOTS);}voidendup_iovs(void){ print_iovs(NULL);}/* * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called from recv_data_in_data(), recv_pdu_header(). * Reads "orig_size" bytes into the iovector already set up in conn->rx_iov * from the socket attached to "conn". Uses the rx_msg and rx_iov * structures attached to "conn" to control the read. * "orig_size" MUST be positive. * Returns > 0 ("orig_size") on success with session lock held, * < 0 on failure with session lock not held.*/static int __attribute__ ((no_instrument_function))recv_iovector(struct connection *conn, int orig_size, int iov_count){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -