📄 initiator_utilities.c
字号:
}/* * executed only by rx thread. * the session->sess_lock MUST be held by the calling process/thread. * Called by rx_data(), recv_ignore_data(). * Called to receive *size bytes of data (can be 0) into a scsi buffer * pointed to by the related_command (can be NULL), * plus over_flow_data_size bytes of data into a locally allocated * buffer. All the data is padded and checksummed as necessary. * On entry MUST have (*size + over_flow_data_size) > 0. * Called under protection of session->lock. * Returns > 0 if ok, * = 0 on err and session->sess_lock still held, * < 0 on err and session->sess_lock not held. * ptr to local buffer is set on return if allocated, else unchanged. * if returned not NULL, this buffer must be freed by caller!*/intrecv_data_in_data(struct connection *current_connection, struct command *related_command, struct iscsi_targ_scsi_data_in *data_in_header, __u32 *size, int over_flow_data_size, char **over_flow_buffer){ struct scatterlist *sg; __u8 *cur_ptr, extra_data_buffer[16]; __u32 cur_offset, recv_checksum, checksum; int received = 1, count, cur_size, padbytes, nbytes; struct iovec *iov;#ifdef K26 struct session *current_session = current_connection->my_session;#endif TRACE(TRACE_ENTER_LEAVE, "Enter recv_data_in_data, size %u, " "over_flow_data_size %d\n", *size, over_flow_data_size); iov = current_connection->rx_iov; /* point at empty rx_iov[] */ count = 0; /* no. of slots used in rx_iov*/ if ((nbytes = *size) > 0) { /* Check if we have scatter-gather list to be filled */ if (related_command->SCpnt->use_sg == 0) { /* No scatter-gather list, just 1 big buffer */ TRACE(TRACE_DEBUG, "No Sc-Gather list\n"); iov->iov_base = related_command->SCpnt->request_buffer + data_in_header->offset; iov->iov_len = nbytes; iov++; count++; } else { /* We have to fill scatter-gather list */ TRACE(TRACE_DEBUG, "Gather size %d\n", related_command->SCpnt->use_sg); sg = (struct scatterlist *) related_command->SCpnt->request_buffer; cur_offset = 0;/* donnelly */#ifdef K26/* Notes on kernel 2.6 changes. * Prior to 2.6, a device driver had to know if the memory * model they existed under was either hi-mem or small * and use the appropriate vaddr mapping of kmap() ( for large ) * or page_address() ( for small) . The only recommended way * now is to allow kmap() to set up the appropriate mappings * avoid page_adress all together. */ TRACE(TRACE_DEBUG, "sg %p page %p off %x addr %x len %x\n", sg,sg->page,sg->offset, sg->dma_address, sg->length); /* Convert page struct passed in SG instead of using * pci_map_sg(NULL,sg,SCpnt->use_sg, * SCpnt->sc_data_direction) * or page_address for portability between memory * models to create a kernel vaddr. * We can sleep on this * call so have have to release our lock. * kmap can sleep * kmap_atomic() won't sleep but can fail */ UNH_UNLOCK(¤t_session->sess_lock, current_connection->rx_lock_flags); cur_ptr = kmap(sg->page); sg_dma_address(sg) = (dma_addr_t)cur_ptr; UNH_LOCK(¤t_session->sess_lock, current_connection->rx_lock_flags); sg_dma_address(sg) += sg->offset; cur_ptr += sg->offset;#else cur_ptr = sg->address;#endif /* first find where to put data in the scatterlist */#ifdef K26 TRACE(TRACE_DEBUG, "cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n", cur_offset, data_in_header->offset, sg_dma_len(sg), cur_ptr, sg_dma_address(sg)); while (cur_offset < data_in_header->offset) { if (cur_offset + sg_dma_len(sg) > data_in_header->offset) { cur_ptr = (char *)sg_dma_address(sg) + data_in_header->offset - cur_offset; cur_offset = data_in_header->offset; TRACE(TRACE_DEBUG, "In while: cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n", cur_offset, data_in_header->offset, sg_dma_len(sg), cur_ptr, sg_dma_address(sg)); } else { cur_offset += sg_dma_len(sg); sg++; cur_ptr = (void *)sg_dma_address(sg); TRACE(TRACE_DEBUG, "In else: cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %x\n", cur_offset, data_in_header->offset, sg_dma_len(sg), cur_ptr, sg_dma_address(sg)); } } /* while */#else TRACE(TRACE_DEBUG, "cur_offset %d data_in_off %d sg len %d \n cur_ptr %p dma_addr %p\n", cur_offset, data_in_header->offset, sg->length, cur_ptr, sg->address); while (cur_offset < data_in_header->offset) { TRACE(TRACE_DEBUG, "cur_offset while %d %d %d %p %p\n", cur_offset, data_in_header->offset, sg->length, cur_ptr, sg->address); if (cur_offset + sg->length > data_in_header->offset) { cur_ptr = cur_ptr + data_in_header->offset - cur_offset; cur_offset = data_in_header->offset; } else { cur_offset += sg->length; sg++; cur_ptr = sg->address; } }#endif /* fill in the buffers till we receive amount of data * corresponding to the datasegmentlength in the * DataIn header */ for (received = 0; received < nbytes; received += cur_size) {/* jpd */#ifdef K26 cur_size = (__u32) sg_dma_address(sg) + sg_dma_len(sg) - (__u32) cur_ptr;#else cur_size = (__u32) sg->address + sg->length - (__u32) cur_ptr;#endif if (cur_size > nbytes - received) { cur_size = nbytes - received; } iov->iov_len = cur_size; iov->iov_base = cur_ptr; sg++;/* jpd */#ifdef K26 cur_ptr = (__u8 *)sg_dma_address(sg);#else cur_ptr = sg->address;#endif iov++; count++; } } } /* end of if (nbytes > 0) */ nbytes += over_flow_data_size; /* may need to read padding and/or crc and/or extra data */ padbytes = (-nbytes) & 3; if (unlikely(padbytes != 0)) { /* have to receive pad bytes */ over_flow_data_size += padbytes; nbytes += padbytes; } if (unlikely(over_flow_data_size > 0)) { /* have to receive extra data and/or padding */ if (over_flow_data_size <= sizeof(extra_data_buffer)) { /* use local buffer for small amounts of extra data */ iov->iov_base = extra_data_buffer; } else { /* have to allocate a big buffer for extra data */ *over_flow_buffer = (char *)my_kmalloc( over_flow_data_size, "local buf"); if (unlikely(*over_flow_buffer == NULL)) { received = -ENOMEM; goto out_unlock; } iov->iov_base = *over_flow_buffer; } iov->iov_len = over_flow_data_size; iov++; count++; } if (current_connection->connection_flags & USE_DATADIGEST) { /* receive crc into local variable for checking */ iov->iov_base = &recv_checksum; iov->iov_len = CRC_LEN; nbytes += CRC_LEN; iov++; count++; /* need to compute the checksum after reading, * but recvmsg destroys the iovector during * reading, so we need to make a copy now */ memcpy(current_connection->rx_iov_copy, current_connection->rx_iov, count * sizeof(struct iovec)); } received = recv_iovector(current_connection, nbytes, count); if (unlikely(received <= 0)) goto out; if (current_connection->connection_flags & USE_DATADIGEST) { /* need to go back to compute and check the checksum */ checksum = 0; iov = current_connection->rx_iov_copy; for (count--; count > 0; count--) { do_crc(iov->iov_base, iov->iov_len, &checksum); iov++; } if (unlikely(checksum != recv_checksum)) { /* There is a Data Digest err, * handle appropriately - SAI */ TRACE_ERROR("opcode 0x%02x, ITT %u, Data CRC wrong: " "got 0x%08x, expected 0x%08x\n", data_in_header->opcode, related_command->init_task_tag, ntohl(recv_checksum), ntohl(checksum)); data_in_header->length = 0; /*already got all data*/ received = recv_data_in_error( current_connection, related_command, data_in_header, size); } }out: TRACE(TRACE_ENTER_LEAVE, "Leave recv_data_in_data, received %d\n", received); return received;out_unlock: UNH_UNLOCK(¤t_connection->my_session->sess_lock, current_connection->rx_lock_flags); goto out;}/* * the session->sess_lock MUST be held by the calling process/thread. * here to attach cmnds to the list after they have been properly * filled in. The reason we needed to be a bit careful is that other * portions of the driver might be attempting to traverse the list * at the same time that we are here so we don't want to attach an * invalid entry. */voidattach_pending_command(struct command *new_command, struct connection *current_connection, int need_itt){ struct iscsi_init_scsi_cmnd *iscsi_cmd; struct session *current_session; TRACE(TRACE_ENTER_LEAVE, "Enter attach_pending_command, command %p, need_itt %d\n", new_command, need_itt); /* extract a copy of pdu's opcode and flags for use after sendmsg */ /* These bytes are in the "iscsi_cmd" field of the "struct command" for all pdu types except DataOut when they are in the "data" field of the "struct command" */ new_command->header_opcode = ((__u8 *) (new_command->tx_iov[0].iov_base))[0]; new_command->header_flags = ((__u8 *) (new_command->tx_iov[0].iov_base))[1]; current_session = current_connection->my_session; iscsi_cmd = &new_command->iscsi_cmd; /* now allocate a session-wide command number, and task tag if needed */ if (need_itt >= 0) { switch (need_itt) { case 1: /* set ITT to unique value != 0xffffffff */ new_command->init_task_tag = current_session->cur_task_tag++; if (unlikely(current_session->cur_task_tag == ALL_ONES)) current_session->cur_task_tag++; iscsi_cmd->init_task_tag = htonl(new_command->init_task_tag); break; case 0: /* set ITT to 0xffffffff, and I bit to 1 * * RFC 3721 Section 10.18.1 Initiator Task Tag (NOP-Out) * "If the Initiator Task Tag contains 0xffffffff, the * I bit MUST be set to 1 and the CmdSN is not advanced * after this PDU is sent." */ iscsi_cmd->init_task_tag = new_command->init_task_tag = ALL_ONES; iscsi_cmd->opcode |= I_BIT; break; case 2: /* reusing old command struct, so ITT already set */ list_del(&new_command->link); new_command->header_complete = 0; break; } /* switch */ /* * RFC 3720 Section 3.2.2.1 Command Numbering and Acknowledging * * "Commands meant for immediate delivery are marked with an * immediate delivery flag; they MUST also carry the * current CmdSN. CmdSn does not advance after a command marked * for immediate delivery is sent. Command numbering starts * with the first login request on the first connection of a * session (the leading login on the leading connection) and * command numbers are incremented by 1 for every non-immediate * command issued afterwards. * ... * For the numbering mechanism, the initiator and target * maintain the following three variables for each session: * * - CmdSN - the current command Sequence Number, advanced * by 1 on each command shipped except for commands marked for * immediate delivery. CmdSN always contains the number to be * assigned to the next Command PDU." * * RFC 3720 Section 10.2.1.1 I (bit in Basic Header Segment) * "For request PDUs, the I bit set to 1 is an immediate * delivery marker." */ iscsi_cmd->cmd_sn = htonl(current_session->cur_cmd_sn); if (likely(!(iscsi_cmd->opcode & I_BIT))) { /* not an immediate command, advance CmdSN by 1 */ current_session->cur_cmd_sn++; } /* else I bit is set (immediate command), CmdSN unchanged */ } TRACE(TRACE_DEBUG, "attach_pending command %p connection %p ###\n", new_command, current_connection); /* 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; /* first time command can be sent */ new_command->tx_wait_to_send = jiffies; new_command->time_stamp = jiffies; /* add this new command to end of pending commands list */ list_add_tail(&new_command->link,¤t_connection->pending_commands); TRACE(TRACE_DEBUG, "Attach pending command, ITT %u\n", new_command->init_task_tag); /* signal the tx thread for this session that is has work to do */ if (atomic_read(¤t_connection->tx_sem.count) <= 0) { TRACE(TRACE_ISCSI_FULL, "wake up tx_thread\n"); up(¤t_connection->tx_sem); } TRACE(TRACE_ENTER_LEAVE, "Leave attach_pending_command\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -